Merge "Update null cipher notification mutator API naming to match accessor" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index c136dd7..98b62b3 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -26,6 +26,7 @@
     ":android.content.flags-aconfig-java{.generated_srcjars}",
     ":android.content.pm.flags-aconfig-java{.generated_srcjars}",
     ":android.content.res.flags-aconfig-java{.generated_srcjars}",
+    ":android.crashrecovery.flags-aconfig-java{.generated_srcjars}",
     ":android.credentials.flags-aconfig-java{.generated_srcjars}",
     ":android.database.sqlite-aconfig-java{.generated_srcjars}",
     ":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}",
@@ -64,6 +65,7 @@
     ":com.android.input.flags-aconfig-java{.generated_srcjars}",
     ":com.android.internal.foldables.flags-aconfig-java{.generated_srcjars}",
     ":com.android.media.flags.bettertogether-aconfig-java{.generated_srcjars}",
+    ":com.android.media.flags.editing-aconfig-java{.generated_srcjars}",
     ":com.android.net.flags-aconfig-java{.generated_srcjars}",
     ":com.android.net.thread.flags-aconfig-java{.generated_srcjars}",
     ":com.android.server.flags.services-aconfig-java{.generated_srcjars}",
@@ -93,6 +95,7 @@
         "android.companion.virtual.flags-aconfig",
         "android.content.pm.flags-aconfig",
         "android.content.res.flags-aconfig",
+        "android.crashrecovery.flags-aconfig",
         "android.credentials.flags-aconfig",
         "android.database.sqlite-aconfig",
         "android.hardware.biometrics.flags-aconfig",
@@ -538,6 +541,21 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+// Media Editing
+aconfig_declarations {
+    name: "com.android.media.flags.editing-aconfig",
+    package: "com.android.media.editing.flags",
+    srcs: [
+        "media/java/android/media/flags/editing.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "com.android.media.flags.editing-aconfig-java",
+    aconfig_declarations: "com.android.media.flags.editing-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Media TV
 aconfig_declarations {
     name: "android.media.tv.flags-aconfig",
@@ -1062,3 +1080,16 @@
     aconfig_declarations: "android.adaptiveauth.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// CrashRecovery Module
+aconfig_declarations {
+    name: "android.crashrecovery.flags-aconfig",
+    package: "android.crashrecovery.flags",
+    srcs: ["packages/CrashRecovery/aconfig/flags.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.crashrecovery.flags-aconfig-java",
+    aconfig_declarations: "android.crashrecovery.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 9c56733..e12f74f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -95,6 +95,7 @@
         ":platform-compat-native-aidl",
 
         // AIDL sources from external directories
+        ":android.frameworks.location.altitude-V2-java-source",
         ":android.hardware.biometrics.common-V4-java-source",
         ":android.hardware.biometrics.fingerprint-V3-java-source",
         ":android.hardware.biometrics.face-V4-java-source",
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
index 0ea2daf..bc84708 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
@@ -248,6 +248,11 @@
         return mServiceWatcher.waitOnCreate();
     }
 
+    /** Wait for session paused. */
+    public void waitForSessionPaused() throws InterruptedException {
+        mServiceWatcher.waitSessionPaused();
+    }
+
     @NonNull
     protected ActivityWatcher startWatcher() {
         return mActivitiesWatcher.watch(CustomTestActivity.class);
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
index aa95dfd..44e8a67 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
@@ -80,6 +80,34 @@
         testActivityLaunchTime(R.layout.test_container_activity, 500);
     }
 
+    @Test
+    public void testSendEventsLatency() throws Throwable {
+        enableService();
+
+        testSendEventLatency(R.layout.test_container_activity, 0);
+    }
+
+    @Test
+    public void testSendEventsLatency_contains100Views() throws Throwable {
+        enableService();
+
+        testSendEventLatency(R.layout.test_container_activity, 100);
+    }
+
+    @Test
+    public void testSendEventsLatency_contains300Views() throws Throwable {
+        enableService();
+
+        testSendEventLatency(R.layout.test_container_activity, 300);
+    }
+
+    @Test
+    public void testSendEventsLatency_contains500Views() throws Throwable {
+        enableService();
+
+        testSendEventLatency(R.layout.test_container_activity, 500);
+    }
+
     private void testActivityLaunchTime(int layoutId, int numViews) throws Throwable {
         final Object drawNotifier = new Object();
         final Intent intent = getLaunchIntent(layoutId, numViews);
@@ -111,6 +139,38 @@
         }
     }
 
+    private void testSendEventLatency(int layoutId, int numViews) throws Throwable {
+        final Object drawNotifier = new Object();
+        final Intent intent = getLaunchIntent(layoutId, numViews);
+        intent.putExtra(CustomTestActivity.INTENT_EXTRA_FINISH_ON_IDLE, true);
+        intent.putExtra(CustomTestActivity.INTENT_EXTRA_DRAW_CALLBACK,
+                new RemoteCallback(result -> {
+                    synchronized (drawNotifier) {
+                        drawNotifier.notifyAll();
+                    }
+                }));
+        final ActivityWatcher watcher = startWatcher();
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mEntryActivity.startActivity(intent);
+            synchronized (drawNotifier) {
+                try {
+                    drawNotifier.wait(GENERIC_TIMEOUT_MS);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            waitForSessionPaused();
+
+            // Ignore the time to finish the activity
+            state.pauseTiming();
+            watcher.waitFor(DESTROYED);
+            sInstrumentation.waitForIdleSync();
+            state.resumeTiming();
+        }
+    }
+
     @Test
     public void testOnVisibilityAggregated_visibleChanged() throws Throwable {
         enableService();
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
index ecc5112..0b5345f 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
@@ -114,6 +114,10 @@
     public void onContentCaptureEvent(ContentCaptureSessionId sessionId,
             ContentCaptureEvent event) {
         Log.i(TAG, "onContentCaptureEventsRequest(session=" + sessionId + "): " + event);
+        if (sServiceWatcher != null
+                && event.getType() == ContentCaptureEvent.TYPE_SESSION_PAUSED) {
+            sServiceWatcher.mSessionPaused.countDown();
+        }
     }
 
     @Override
@@ -126,6 +130,7 @@
         private static final long GENERIC_TIMEOUT_MS = 10_000;
         private final CountDownLatch mCreated = new CountDownLatch(1);
         private final CountDownLatch mDestroyed = new CountDownLatch(1);
+        private final CountDownLatch mSessionPaused = new CountDownLatch(1);
         private boolean mReadyToClear = true;
         private Pair<Set<String>, Set<ComponentName>> mAllowList;
 
@@ -151,6 +156,11 @@
             await(mDestroyed, "not destroyed");
         }
 
+        /** Wait for session paused. */
+        public void waitSessionPaused() throws InterruptedException {
+            await(mSessionPaused, "no Paused");
+        }
+
         /**
          * Allow just this package.
          */
diff --git a/apex/jobscheduler/framework/aconfig/job.aconfig b/apex/jobscheduler/framework/aconfig/job.aconfig
index e73b434..788e824 100644
--- a/apex/jobscheduler/framework/aconfig/job.aconfig
+++ b/apex/jobscheduler/framework/aconfig/job.aconfig
@@ -13,3 +13,10 @@
     description: "Add APIs to let apps attach debug information to jobs"
     bug: "293491637"
 }
+
+flag {
+    name: "backup_jobs_exemption"
+    namespace: "backstage_power"
+    description: "Introduce a new RUN_BACKUP_JOBS permission and exemption logic allowing for longer running jobs for apps whose primary purpose is to backup or sync content."
+    bug: "318731461"
+}
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 6c8af39..ae98fe1 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -77,6 +77,12 @@
             @NonNull String notificationChannel, int userId, @NonNull String packageName);
 
     /**
+     * @return {@code true} if the given package holds the
+     * {@link android.Manifest.permission.RUN_BACKUP_JOBS} permission.
+     */
+    boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid);
+
+    /**
      * Report a snapshot of sync-related jobs back to the sync manager
      */
     JobStorePersistStats getPersistStats();
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 7a92cca..57467e3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1840,7 +1840,9 @@
                     /* isFlexConstraintSatisfied */ false,
                     jobStatus.canApplyTransportAffinities(),
                     jobStatus.getNumAppliedFlexibleConstraints(),
-                    jobStatus.getNumDroppedFlexibleConstraints());
+                    jobStatus.getNumDroppedFlexibleConstraints(),
+                    jobStatus.getFilteredTraceTag(),
+                    jobStatus.getFilteredDebugTags());
 
             // If the job is immediately ready to run, then we can just immediately
             // put it in the pending list and try to schedule it.  This is especially
@@ -2288,7 +2290,9 @@
                     cancelled.isConstraintSatisfied(JobStatus.CONSTRAINT_FLEXIBLE),
                     cancelled.canApplyTransportAffinities(),
                     cancelled.getNumAppliedFlexibleConstraints(),
-                    cancelled.getNumDroppedFlexibleConstraints());
+                    cancelled.getNumDroppedFlexibleConstraints(),
+                    cancelled.getFilteredTraceTag(),
+                    cancelled.getFilteredDebugTags());
         }
         // If this is a replacement, bring in the new version of the job
         if (incomingJob != null) {
@@ -4193,6 +4197,11 @@
         }
 
         @Override
+        public boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid) {
+            return JobSchedulerService.this.hasRunBackupJobsPermission(packageName, packageUid);
+        }
+
+        @Override
         public JobStorePersistStats getPersistStats() {
             synchronized (mLock) {
                 return new JobStorePersistStats(mJobs.getPersistStats());
@@ -4355,6 +4364,22 @@
     }
 
     /**
+     * Returns whether the app holds the {@link Manifest.permission.RUN_BACKUP_JOBS} permission.
+     */
+    private boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid) {
+        if (packageName == null) {
+            Slog.wtfStack(TAG,
+                    "Expected a non-null package name when calling hasRunBackupJobsPermission");
+            return false;
+        }
+
+        return PermissionChecker.checkPermissionForPreflight(getTestableContext(),
+                android.Manifest.permission.RUN_BACKUP_JOBS,
+                PermissionChecker.PID_UNKNOWN, packageUid, packageName)
+                    == PermissionChecker.PERMISSION_GRANTED;
+    }
+
+    /**
      * Binder stub trampoline implementation
      */
     final class JobSchedulerStub extends IJobScheduler.Stub {
@@ -5448,6 +5473,9 @@
             pw.print(Flags.FLAG_THROW_ON_UNSUPPORTED_BIAS_USAGE,
                     Flags.throwOnUnsupportedBiasUsage());
             pw.println();
+            pw.print(android.app.job.Flags.FLAG_BACKUP_JOBS_EXEMPTION,
+                    android.app.job.Flags.backupJobsExemption());
+            pw.println();
             pw.decreaseIndent();
             pw.println();
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index 6f2393a..0cf6a7a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -356,6 +356,9 @@
             case com.android.server.job.Flags.FLAG_THROW_ON_UNSUPPORTED_BIAS_USAGE:
                 pw.println(com.android.server.job.Flags.throwOnUnsupportedBiasUsage());
                 break;
+            case android.app.job.Flags.FLAG_BACKUP_JOBS_EXEMPTION:
+                pw.println(android.app.job.Flags.backupJobsExemption());
+                break;
             default:
                 pw.println("Unknown flag: " + flagName);
                 break;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index fe55e27..8ab7d2f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -541,7 +541,9 @@
                     job.isConstraintSatisfied(JobStatus.CONSTRAINT_FLEXIBLE),
                     job.canApplyTransportAffinities(),
                     job.getNumAppliedFlexibleConstraints(),
-                    job.getNumDroppedFlexibleConstraints());
+                    job.getNumDroppedFlexibleConstraints(),
+                    job.getFilteredTraceTag(),
+                    job.getFilteredDebugTags());
             sEnqueuedJwiAtJobStart.logSampleWithUid(job.getUid(), job.getWorkCount());
             final String sourcePackage = job.getSourcePackageName();
             if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
@@ -1630,7 +1632,9 @@
                 completedJob.isConstraintSatisfied(JobStatus.CONSTRAINT_FLEXIBLE),
                 completedJob.canApplyTransportAffinities(),
                 completedJob.getNumAppliedFlexibleConstraints(),
-                completedJob.getNumDroppedFlexibleConstraints());
+                completedJob.getNumDroppedFlexibleConstraints(),
+                completedJob.getFilteredTraceTag(),
+                completedJob.getFilteredDebugTags());
         if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
             Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler",
                     getId());
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
index 14cce19..6883d18 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
@@ -972,6 +972,20 @@
             synchronized (mLock) {
                 final long earliest = getLifeCycleBeginningElapsedLocked(js);
                 final long latest = getLifeCycleEndElapsedLocked(js, nowElapsed, earliest);
+                if (latest <= earliest) {
+                    // Something has gone horribly wrong. This has only occurred on incorrectly
+                    // configured tests, but add a check here for safety.
+                    Slog.wtf(TAG, "Got invalid latest when scheduling alarm."
+                            + " Prefetch=" + js.getJob().isPrefetch());
+                    // Since things have gone wrong, the safest and most reliable thing to do is
+                    // stop applying flex policy to the job.
+                    mFlexibilityTracker.setNumDroppedFlexibleConstraints(js,
+                            js.getNumAppliedFlexibleConstraints());
+                    mJobsToCheck.add(js);
+                    mHandler.sendEmptyMessage(MSG_CHECK_JOBS);
+                    return;
+                }
+
                 final long nextTimeElapsed =
                         getNextConstraintDropTimeElapsedLocked(js, earliest, latest);
 
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 d39863c..2ea980d 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
@@ -48,6 +48,7 @@
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Pair;
+import android.util.Patterns;
 import android.util.Range;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -76,6 +77,7 @@
 import java.util.Objects;
 import java.util.Random;
 import java.util.function.Predicate;
+import java.util.regex.Pattern;
 
 /**
  * Uniquely identifies a job internally.
@@ -203,6 +205,17 @@
     // TODO(b/129954980): ensure this doesn't spam statsd, especially at boot
     private static final boolean STATS_LOG_ENABLED = false;
 
+    /**
+     * Simple patterns to match some common forms of PII. This is not intended all-encompassing and
+     * any clients should aim to do additional filtering.
+     */
+    private static final ArrayMap<Pattern, String> BASIC_PII_FILTERS = new ArrayMap<>();
+
+    static {
+        BASIC_PII_FILTERS.put(Patterns.EMAIL_ADDRESS, "[EMAIL]");
+        BASIC_PII_FILTERS.put(Patterns.PHONE, "[PHONE]");
+    }
+
     // No override.
     public static final int OVERRIDE_NONE = 0;
     // Override to improve sorting order. Does not affect constraint evaluation.
@@ -250,6 +263,18 @@
     private final long mLoggingJobId;
 
     /**
+     * List of tags from {@link JobInfo#getDebugTags()}, filtered using {@link #BASIC_PII_FILTERS}.
+     * Lazily loaded in {@link #getFilteredDebugTags()}.
+     */
+    @Nullable
+    private String[] mFilteredDebugTags;
+    /**
+     * Trace tag from {@link JobInfo#getTraceTag()}, filtered using {@link #BASIC_PII_FILTERS}.
+     * Lazily loaded in {@link #getFilteredTraceTag()}.
+     */
+    @Nullable
+    private String mFilteredTraceTag;
+    /**
      * Tag to identify the wakelock held for this job. Lazily loaded in
      * {@link #getWakelockTag()} since it's not typically needed until the job is about to run.
      */
@@ -1197,21 +1222,25 @@
             return ACTIVE_INDEX;
         }
 
-        final int bucketWithMediaExemption;
-        if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX
-                && mHasMediaBackupExemption) {
+        final boolean isEligibleAsBackupJob = job.getTriggerContentUris() != null
+                && job.getRequiredNetwork() != null
+                && !job.hasLateConstraint()
+                && mJobSchedulerInternal.hasRunBackupJobsPermission(sourcePackageName, sourceUid);
+        final boolean isBackupExempt = mHasMediaBackupExemption || isEligibleAsBackupJob;
+        final int bucketWithBackupExemption;
+        if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX && isBackupExempt) {
             // Treat it as if it's at most WORKING_INDEX (lower index grants higher quota) since
             // media backup jobs are important to the user, and the source package may not have
             // been used directly in a while.
-            bucketWithMediaExemption = Math.min(WORKING_INDEX, actualBucket);
+            bucketWithBackupExemption = Math.min(WORKING_INDEX, actualBucket);
         } else {
-            bucketWithMediaExemption = actualBucket;
+            bucketWithBackupExemption = actualBucket;
         }
 
         // If the app is considered buggy, but hasn't yet been put in the RESTRICTED bucket
         // (potentially because it's used frequently by the user), limit its effective bucket
         // so that it doesn't get to run as much as a normal ACTIVE app.
-        if (isBuggy && bucketWithMediaExemption < WORKING_INDEX) {
+        if (isBuggy && bucketWithBackupExemption < WORKING_INDEX) {
             if (!mIsDowngradedDueToBuggyApp) {
                 // Safety check to avoid logging multiple times for the same job.
                 Counter.logIncrementWithUid(
@@ -1221,7 +1250,7 @@
             }
             return WORKING_INDEX;
         }
-        return bucketWithMediaExemption;
+        return bucketWithBackupExemption;
     }
 
     /** Returns the real standby bucket of the job. */
@@ -1325,6 +1354,47 @@
         return batteryName;
     }
 
+    @VisibleForTesting
+    @NonNull
+    static String applyBasicPiiFilters(@NonNull String val) {
+        for (int i = BASIC_PII_FILTERS.size() - 1; i >= 0; --i) {
+            val = BASIC_PII_FILTERS.keyAt(i).matcher(val).replaceAll(BASIC_PII_FILTERS.valueAt(i));
+        }
+        return val;
+    }
+
+    /**
+     * List of tags from {@link JobInfo#getDebugTags()}, filtered using a basic set of PII filters.
+     */
+    @NonNull
+    public String[] getFilteredDebugTags() {
+        if (mFilteredDebugTags != null) {
+            return mFilteredDebugTags;
+        }
+        final ArraySet<String> debugTags = job.getDebugTagsArraySet();
+        mFilteredDebugTags = new String[debugTags.size()];
+        for (int i = 0; i < mFilteredDebugTags.length; ++i) {
+            mFilteredDebugTags[i] = applyBasicPiiFilters(debugTags.valueAt(i));
+        }
+        return mFilteredDebugTags;
+    }
+
+    /**
+     * Trace tag from {@link JobInfo#getTraceTag()}, filtered using a basic set of PII filters.
+     */
+    @Nullable
+    public String getFilteredTraceTag() {
+        if (mFilteredTraceTag != null) {
+            return mFilteredTraceTag;
+        }
+        final String rawTag = job.getTraceTag();
+        if (rawTag == null) {
+            return null;
+        }
+        mFilteredTraceTag = applyBasicPiiFilters(rawTag);
+        return mFilteredTraceTag;
+    }
+
     /** Return the String to be used as the tag for the wakelock held for this job. */
     @NonNull
     public String getWakelockTag() {
diff --git a/core/TEST_MAPPING b/core/TEST_MAPPING
index fd571c9..f1e4d0ee 100644
--- a/core/TEST_MAPPING
+++ b/core/TEST_MAPPING
@@ -20,5 +20,15 @@
         "core/tests/coretests/src/com/android/internal/inputmethod/.*"
       ]
     }
-  ]
+  ],
+  "postsubmit": [
+      {
+        "name": "CtsContactKeysManagerTestCases",
+        "options": [
+          {
+            "include-filter": "android.provider.cts.contactkeys."
+          }
+        ]
+      }
+    ]
 }
diff --git a/core/api/Android.bp b/core/api/Android.bp
index 907916a..8d8a82b 100644
--- a/core/api/Android.bp
+++ b/core/api/Android.bp
@@ -96,21 +96,3 @@
     name: "non-updatable-test-lint-baseline.txt",
     srcs: ["test-lint-baseline.txt"],
 }
-
-java_api_contribution {
-    name: "api-stubs-docs-non-updatable-public-stubs",
-    api_surface: "public",
-    api_file: "current.txt",
-    visibility: [
-        "//build/orchestrator/apis",
-    ],
-}
-
-java_api_contribution {
-    name: "frameworks-base-core-api-module-lib-stubs",
-    api_surface: "module-lib",
-    api_file: "module-lib-current.txt",
-    visibility: [
-        "//build/orchestrator/apis",
-    ],
-}
diff --git a/core/api/current.txt b/core/api/current.txt
index 987b5c6..920d6e0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -147,6 +147,7 @@
     field public static final String MANAGE_DEVICE_POLICY_CAMERA = "android.permission.MANAGE_DEVICE_POLICY_CAMERA";
     field public static final String MANAGE_DEVICE_POLICY_CERTIFICATES = "android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES";
     field public static final String MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE = "android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE";
+    field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final String MANAGE_DEVICE_POLICY_CONTENT_PROTECTION = "android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION";
     field public static final String MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES = "android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES";
     field public static final String MANAGE_DEVICE_POLICY_DEFAULT_SMS = "android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS";
     field public static final String MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS = "android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS";
@@ -277,6 +278,7 @@
     field @FlaggedApi("android.companion.flags.device_presence") public static final String REQUEST_OBSERVE_DEVICE_UUID_PRESENCE = "android.permission.REQUEST_OBSERVE_DEVICE_UUID_PRESENCE";
     field public static final String REQUEST_PASSWORD_COMPLEXITY = "android.permission.REQUEST_PASSWORD_COMPLEXITY";
     field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+    field @FlaggedApi("android.app.job.backup_jobs_exemption") public static final String RUN_BACKUP_JOBS = "android.permission.RUN_BACKUP_JOBS";
     field public static final String RUN_USER_INITIATED_JOBS = "android.permission.RUN_USER_INITIATED_JOBS";
     field public static final String SCHEDULE_EXACT_ALARM = "android.permission.SCHEDULE_EXACT_ALARM";
     field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
@@ -284,6 +286,7 @@
     field public static final String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
     field public static final String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
     field public static final String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
+    field @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public static final String SET_BIOMETRIC_DIALOG_LOGO = "android.permission.SET_BIOMETRIC_DIALOG_LOGO";
     field public static final String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
     field @Deprecated public static final String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
     field public static final String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT";
@@ -442,6 +445,7 @@
     field public static final int alertDialogTheme = 16843529; // 0x1010309
     field public static final int alignmentMode = 16843642; // 0x101037a
     field public static final int allContactsName = 16843468; // 0x10102cc
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int allow;
     field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
@@ -845,6 +849,7 @@
     field public static final int format24Hour = 16843723; // 0x10103cb
     field public static final int fraction = 16843992; // 0x10104d8
     field public static final int fragment = 16843491; // 0x10102e3
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentAdvancedPattern;
     field public static final int fragmentAllowEnterTransitionOverlap = 16843976; // 0x10104c8
     field public static final int fragmentAllowReturnTransitionOverlap = 16843977; // 0x10104c9
     field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
@@ -855,10 +860,13 @@
     field public static final int fragmentFadeExitAnimation = 16843498; // 0x10102ea
     field public static final int fragmentOpenEnterAnimation = 16843493; // 0x10102e5
     field public static final int fragmentOpenExitAnimation = 16843494; // 0x10102e6
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentPattern;
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentPrefix;
     field public static final int fragmentReenterTransition = 16843975; // 0x10104c7
     field public static final int fragmentReturnTransition = 16843973; // 0x10104c5
     field public static final int fragmentSharedElementEnterTransition = 16843972; // 0x10104c4
     field public static final int fragmentSharedElementReturnTransition = 16843974; // 0x10104c6
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentSuffix;
     field public static final int freezesText = 16843116; // 0x101016c
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
@@ -1327,10 +1335,15 @@
     field public static final int propertyYName = 16843893; // 0x1010475
     field public static final int protectionLevel = 16842761; // 0x1010009
     field public static final int publicKey = 16843686; // 0x10103a6
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int query;
     field public static final int queryActionMsg = 16843227; // 0x10101db
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryAdvancedPattern;
     field public static final int queryAfterZeroResults = 16843394; // 0x1010282
     field public static final int queryBackground = 16843911; // 0x1010487
     field public static final int queryHint = 16843608; // 0x1010358
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryPattern;
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryPrefix;
+    field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int querySuffix;
     field public static final int quickContactBadgeStyleSmallWindowLarge = 16843443; // 0x10102b3
     field public static final int quickContactBadgeStyleSmallWindowMedium = 16843442; // 0x10102b2
     field public static final int quickContactBadgeStyleSmallWindowSmall = 16843441; // 0x10102b1
@@ -8182,6 +8195,9 @@
     field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
     field public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+    field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_DISABLED = 1; // 0x1
+    field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_ENABLED = 2; // 0x2
+    field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0; // 0x0
     field public static final String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
     field public static final String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
     field public static final String DELEGATION_CERT_INSTALL = "delegation-cert-install";
@@ -10592,6 +10608,7 @@
     field public static final String CONNECTIVITY_DIAGNOSTICS_SERVICE = "connectivity_diagnostics";
     field public static final String CONNECTIVITY_SERVICE = "connectivity";
     field public static final String CONSUMER_IR_SERVICE = "consumer_ir";
+    field @FlaggedApi("android.provider.user_keys") public static final String CONTACT_KEYS_SERVICE = "contact_keys";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
     field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
     field public static final int CONTEXT_RESTRICTED = 4; // 0x4
@@ -11385,10 +11402,12 @@
     method public final void addDataScheme(String);
     method public final void addDataSchemeSpecificPart(String, int);
     method public final void addDataType(String) throws android.content.IntentFilter.MalformedMimeTypeException;
+    method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final void addUriRelativeFilterGroup(@NonNull android.content.UriRelativeFilterGroup);
     method @NonNull public java.util.function.Predicate<android.content.Intent> asPredicate();
     method @NonNull public java.util.function.Predicate<android.content.Intent> asPredicateWithTypeResolution(@NonNull android.content.ContentResolver);
     method public final java.util.Iterator<android.content.IntentFilter.AuthorityEntry> authoritiesIterator();
     method public final java.util.Iterator<java.lang.String> categoriesIterator();
+    method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final void clearUriRelativeFilterGroups();
     method public final int countActions();
     method public final int countCategories();
     method public final int countDataAuthorities();
@@ -11396,6 +11415,7 @@
     method public final int countDataSchemeSpecificParts();
     method public final int countDataSchemes();
     method public final int countDataTypes();
+    method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final int countUriRelativeFilterGroups();
     method public static android.content.IntentFilter create(String, String);
     method public final int describeContents();
     method public void dump(android.util.Printer, String);
@@ -11407,6 +11427,7 @@
     method public final android.os.PatternMatcher getDataSchemeSpecificPart(int);
     method public final String getDataType(int);
     method public final int getPriority();
+    method @FlaggedApi("android.content.pm.relative_reference_intent_filters") @NonNull public final android.content.UriRelativeFilterGroup getUriRelativeFilterGroup(int);
     method public final boolean hasAction(String);
     method public final boolean hasCategory(String);
     method public final boolean hasDataAuthority(android.net.Uri);
@@ -11828,6 +11849,27 @@
     field public static final long INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
   }
 
+  @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final class UriRelativeFilter {
+    ctor public UriRelativeFilter(int, int, @NonNull String);
+    method @NonNull public String getFilter();
+    method public int getPatternType();
+    method public int getUriPart();
+    method public boolean matchData(@NonNull android.net.Uri);
+    field public static final int FRAGMENT = 2; // 0x2
+    field public static final int PATH = 0; // 0x0
+    field public static final int QUERY = 1; // 0x1
+  }
+
+  @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final class UriRelativeFilterGroup {
+    ctor public UriRelativeFilterGroup(int);
+    method public void addUriRelativeFilter(@NonNull android.content.UriRelativeFilter);
+    method public int getAction();
+    method @NonNull public java.util.Collection<android.content.UriRelativeFilter> getUriRelativeFilters();
+    method public boolean matchData(@NonNull android.net.Uri);
+    field public static final int ACTION_ALLOW = 0; // 0x0
+    field public static final int ACTION_BLOCK = 1; // 0x1
+  }
+
 }
 
 package android.content.om {
@@ -12349,6 +12391,7 @@
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public void registerPackageInstallerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.content.pm.PackageInstaller.SessionCallback);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
+    method @FlaggedApi("android.content.pm.archiving") public void setArchiveCompatibilityOptions(boolean, boolean);
     method public boolean shouldHideFromSuggestions(@NonNull String, @NonNull android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
@@ -18722,8 +18765,8 @@
     method @Nullable public int getAllowedAuthenticators();
     method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @Nullable public android.hardware.biometrics.PromptContentView getContentView();
     method @Nullable public CharSequence getDescription();
-    method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @Nullable @RequiresPermission("android.permission.MANAGE_BIOMETRIC_DIALOG") public android.graphics.Bitmap getLogoBitmap();
-    method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @DrawableRes @RequiresPermission("android.permission.MANAGE_BIOMETRIC_DIALOG") public int getLogoRes();
+    method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @Nullable @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_LOGO) public android.graphics.Bitmap getLogoBitmap();
+    method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @DrawableRes @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_LOGO) public int getLogoRes();
     method @Nullable public CharSequence getNegativeButtonText();
     method @Nullable public CharSequence getSubtitle();
     method @NonNull public CharSequence getTitle();
@@ -18773,8 +18816,8 @@
     method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setContentView(@NonNull android.hardware.biometrics.PromptContentView);
     method @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence);
     method @Deprecated @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setDeviceCredentialAllowed(boolean);
-    method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @NonNull @RequiresPermission("android.permission.MANAGE_BIOMETRIC_DIALOG") public android.hardware.biometrics.BiometricPrompt.Builder setLogo(@DrawableRes int);
-    method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @NonNull @RequiresPermission("android.permission.MANAGE_BIOMETRIC_DIALOG") public android.hardware.biometrics.BiometricPrompt.Builder setLogo(@NonNull android.graphics.Bitmap);
+    method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @NonNull @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_LOGO) public android.hardware.biometrics.BiometricPrompt.Builder setLogoBitmap(@NonNull android.graphics.Bitmap);
+    method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @NonNull @RequiresPermission(android.Manifest.permission.SET_BIOMETRIC_DIALOG_LOGO) public android.hardware.biometrics.BiometricPrompt.Builder setLogoRes(@DrawableRes int);
     method @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener);
     method @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(@NonNull CharSequence);
     method @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setTitle(@NonNull CharSequence);
@@ -22333,6 +22376,7 @@
     method @NonNull public java.util.List<java.lang.String> getSupportedVendorParameters();
     method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
     method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
+    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
     method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
     method public void release();
     method public void releaseOutputBuffer(int, boolean);
@@ -22394,6 +22438,7 @@
     method public abstract void onError(@NonNull android.media.MediaCodec, @NonNull android.media.MediaCodec.CodecException);
     method public abstract void onInputBufferAvailable(@NonNull android.media.MediaCodec, int);
     method public abstract void onOutputBufferAvailable(@NonNull android.media.MediaCodec, int, @NonNull android.media.MediaCodec.BufferInfo);
+    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void onOutputBuffersAvailable(@NonNull android.media.MediaCodec, int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
     method public abstract void onOutputFormatChanged(@NonNull android.media.MediaCodec, @NonNull android.media.MediaFormat);
   }
 
@@ -22481,6 +22526,7 @@
   }
 
   public static final class MediaCodec.OutputFrame {
+    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public java.util.ArrayDeque<android.media.MediaCodec.BufferInfo> getBufferInfos();
     method @NonNull public java.util.Set<java.lang.String> getChangedKeys();
     method public int getFlags();
     method @NonNull public android.media.MediaFormat getFormat();
@@ -22496,6 +22542,7 @@
 
   public final class MediaCodec.QueueRequest {
     method public void queue();
+    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setBufferInfos(@NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
     method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
     method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @NonNull android.media.MediaCodec.CryptoInfo);
     method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
@@ -24299,7 +24346,7 @@
     method @Nullable public android.media.MediaRouter2.RoutingController getController(@NonNull String);
     method @NonNull public java.util.List<android.media.MediaRouter2.RoutingController> getControllers();
     method @NonNull public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context);
-    method @FlaggedApi("com.android.media.flags.enable_cross_user_routing_in_media_router2") @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MEDIA_CONTENT_CONTROL, android.Manifest.permission.MEDIA_ROUTING_CONTROL}) public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context, @NonNull String, @NonNull android.os.UserHandle);
+    method @FlaggedApi("com.android.media.flags.enable_cross_user_routing_in_media_router2") @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MEDIA_CONTENT_CONTROL, android.Manifest.permission.MEDIA_ROUTING_CONTROL}) public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context, @NonNull String);
     method @FlaggedApi("com.android.media.flags.enable_rlp_callbacks_in_media_router2") @Nullable public android.media.RouteListingPreference getRouteListingPreference();
     method @NonNull public java.util.List<android.media.MediaRoute2Info> getRoutes();
     method @NonNull public android.media.MediaRouter2.RoutingController getSystemController();
@@ -25715,9 +25762,48 @@
     field public static final String KEY_STATSD_ATOM = "bundlesession-statsd-atom";
   }
 
+  @FlaggedApi("com.android.media.editing.flags.add_media_metrics_editing") public final class EditingEndedEvent extends android.media.metrics.Event implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getErrorCode();
+    method public int getFinalState();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.metrics.EditingEndedEvent> CREATOR;
+    field public static final int ERROR_CODE_AUDIO_PROCESSING_FAILED = 18; // 0x12
+    field public static final int ERROR_CODE_DECODER_INIT_FAILED = 11; // 0xb
+    field public static final int ERROR_CODE_DECODING_FAILED = 12; // 0xc
+    field public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 13; // 0xd
+    field public static final int ERROR_CODE_ENCODER_INIT_FAILED = 14; // 0xe
+    field public static final int ERROR_CODE_ENCODING_FAILED = 15; // 0xf
+    field public static final int ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED = 16; // 0x10
+    field public static final int ERROR_CODE_FAILED_RUNTIME_CHECK = 2; // 0x2
+    field public static final int ERROR_CODE_IO_BAD_HTTP_STATUS = 6; // 0x6
+    field public static final int ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED = 9; // 0x9
+    field public static final int ERROR_CODE_IO_FILE_NOT_FOUND = 7; // 0x7
+    field public static final int ERROR_CODE_IO_NETWORK_CONNECTION_FAILED = 4; // 0x4
+    field public static final int ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT = 5; // 0x5
+    field public static final int ERROR_CODE_IO_NO_PERMISSION = 8; // 0x8
+    field public static final int ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE = 10; // 0xa
+    field public static final int ERROR_CODE_IO_UNSPECIFIED = 3; // 0x3
+    field public static final int ERROR_CODE_MUXING_FAILED = 19; // 0x13
+    field public static final int ERROR_CODE_NONE = 1; // 0x1
+    field public static final int ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED = 17; // 0x11
+    field public static final int FINAL_STATE_CANCELED = 2; // 0x2
+    field public static final int FINAL_STATE_ERROR = 3; // 0x3
+    field public static final int FINAL_STATE_SUCCEEDED = 1; // 0x1
+  }
+
+  @FlaggedApi("com.android.media.editing.flags.add_media_metrics_editing") public static final class EditingEndedEvent.Builder {
+    ctor public EditingEndedEvent.Builder(int);
+    method @NonNull public android.media.metrics.EditingEndedEvent build();
+    method @NonNull public android.media.metrics.EditingEndedEvent.Builder setErrorCode(int);
+    method @NonNull public android.media.metrics.EditingEndedEvent.Builder setMetricsBundle(@NonNull android.os.Bundle);
+    method @NonNull public android.media.metrics.EditingEndedEvent.Builder setTimeSinceCreatedMillis(@IntRange(from=0xffffffff) long);
+  }
+
   public final class EditingSession implements java.lang.AutoCloseable {
     method public void close();
     method @NonNull public android.media.metrics.LogSessionId getSessionId();
+    method @FlaggedApi("com.android.media.editing.flags.add_media_metrics_editing") public void reportEditingEndedEvent(@NonNull android.media.metrics.EditingEndedEvent);
   }
 
   public abstract class Event {
@@ -33429,6 +33515,7 @@
     field public static final String DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI = "no_sharing_admin_configured_wifi";
     field public static final String DISALLOW_SMS = "no_sms";
     field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
+    field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
     field public static final String DISALLOW_ULTRA_WIDEBAND_RADIO = "no_ultra_wideband_radio";
     field public static final String DISALLOW_UNIFIED_PASSWORD = "no_unified_password";
     field public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -35154,6 +35241,54 @@
     field public static final String LONGITUDE = "longitude";
   }
 
+  @FlaggedApi("android.provider.user_keys") public class ContactKeysManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getAllContactKeys(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getAllSelfKeys();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.ContactKey getContactKey(@NonNull String, @NonNull String, @NonNull String);
+    method public static int getMaxKeySizeBytes();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getOwnerContactKeys(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getOwnerSelfKeys();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.SelfKey getSelfKey(@NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeContactKey(@NonNull String, @NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeSelfKey(@NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public void updateOrInsertContactKey(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateOrInsertSelfKey(@NonNull String, @NonNull String, @NonNull byte[]);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, int);
+    field public static final int UNVERIFIED = 0; // 0x0
+    field public static final int VERIFICATION_FAILED = 1; // 0x1
+    field public static final int VERIFIED = 2; // 0x2
+  }
+
+  public static final class ContactKeysManager.ContactKey implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getAccountId();
+    method @Nullable public String getDeviceId();
+    method @Nullable public String getDisplayName();
+    method @Nullable public String getEmailAddress();
+    method @Nullable public byte[] getKeyValue();
+    method public int getLocalVerificationState();
+    method @NonNull public String getOwnerPackageName();
+    method @Nullable public String getPhoneNumber();
+    method public int getRemoteVerificationState();
+    method public long getTimeUpdated();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.ContactKey> CREATOR;
+  }
+
+  public static final class ContactKeysManager.SelfKey implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getAccountId();
+    method @Nullable public String getDeviceId();
+    method @Nullable public byte[] getKeyValue();
+    method @NonNull public String getOwnerPackageName();
+    method public int getRemoteVerificationState();
+    method public long getTimeUpdated();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.SelfKey> CREATOR;
+  }
+
   @Deprecated public class Contacts {
     field @Deprecated public static final String AUTHORITY = "contacts";
     field @Deprecated public static final android.net.Uri CONTENT_URI;
@@ -40575,7 +40710,7 @@
     method public int getPriorityCategoryReminders();
     method public int getPriorityCategoryRepeatCallers();
     method public int getPriorityCategorySystem();
-    method @FlaggedApi("android.app.modes_api") public int getPriorityChannels();
+    method @FlaggedApi("android.app.modes_api") public int getPriorityChannelsAllowed();
     method public int getPriorityConversationSenders();
     method public int getPriorityMessageSenders();
     method public int getVisualEffectAmbient();
@@ -53625,13 +53760,13 @@
     method @Deprecated public android.view.Display getDefaultDisplay();
     method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
     method public default boolean isCrossWindowBlurEnabled();
-    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.os.IBinder registerBatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerBatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
     method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void registerTrustedPresentationListener(@NonNull android.os.IBinder, @NonNull android.window.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
-    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.os.IBinder registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
     method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer);
     method public void removeViewImmediate(android.view.View);
-    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void unregisterSurfaceControlInputReceiver(@NonNull android.os.IBinder);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void unregisterSurfaceControlInputReceiver(@NonNull android.view.SurfaceControl);
     method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void unregisterTrustedPresentationListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5a84368..f101161 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -129,6 +129,8 @@
     field public static final String DISABLE_SYSTEM_SOUND_EFFECTS = "android.permission.DISABLE_SYSTEM_SOUND_EFFECTS";
     field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
     field public static final String DOMAIN_VERIFICATION_AGENT = "android.permission.DOMAIN_VERIFICATION_AGENT";
+    field @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission") public static final String EMBED_ANY_APP_IN_UNTRUSTED_MODE = "android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE";
+    field @FlaggedApi("android.content.pm.emergency_install_permission") public static final String EMERGENCY_INSTALL_PACKAGES = "android.permission.EMERGENCY_INSTALL_PACKAGES";
     field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
     field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
     field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
@@ -559,7 +561,7 @@
 
   public class ActivityManager {
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
-    method @FlaggedApi("android.app.uid_importance_listener_for_uids") @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(@NonNull android.app.ActivityManager.OnUidImportanceListener, int, @Nullable int[]);
+    method @FlaggedApi("android.app.uid_importance_listener_for_uids") @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(@NonNull android.app.ActivityManager.OnUidImportanceListener, int, @NonNull int[]);
     method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
     method @FlaggedApi("android.app.get_binding_uid_importance") @RequiresPermission(android.Manifest.permission.GET_BINDING_UID_IMPORTANCE) public int getBindingUidImportance(int);
     method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
@@ -871,6 +873,10 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
   }
 
+  @FlaggedApi("android.app.bic_client") public final class BackgroundInstallControlManager {
+    method @FlaggedApi("android.app.bic_client") @NonNull @RequiresPermission(android.Manifest.permission.GET_BACKGROUND_INSTALLED_PACKAGES) public java.util.List<android.content.pm.PackageInfo> getBackgroundInstalledPackages(long);
+  }
+
   public class BroadcastOptions {
     method public void clearRequireCompatChange();
     method public int getPendingIntentBackgroundActivityStartMode();
@@ -3388,11 +3394,10 @@
   }
 
   @FlaggedApi("android.companion.virtual.flags.virtual_camera") public static final class VirtualCameraConfig.Builder {
-    ctor public VirtualCameraConfig.Builder();
+    ctor public VirtualCameraConfig.Builder(@NonNull String);
     method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder addStreamConfig(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int);
     method @NonNull public android.companion.virtual.camera.VirtualCameraConfig build();
     method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder setLensFacing(int);
-    method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder setName(@NonNull String);
     method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder setSensorOrientation(int);
     method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder setVirtualCameraCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.camera.VirtualCameraCallback);
   }
@@ -4228,6 +4233,7 @@
   public final class UserProperties implements android.os.Parcelable {
     method public int describeContents();
     method public int getCrossProfileContentSharingStrategy();
+    method @FlaggedApi("android.multiuser.support_hiding_profiles") @NonNull public int getProfileApiVisibility();
     method public int getShowInQuietMode();
     method public int getShowInSharingSurfaces();
     method public boolean isCredentialShareableWithParent();
@@ -4237,6 +4243,9 @@
     field public static final int CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT = 1; // 0x1
     field public static final int CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION = 0; // 0x0
     field public static final int CROSS_PROFILE_CONTENT_SHARING_UNKNOWN = -1; // 0xffffffff
+    field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_HIDDEN = 1; // 0x1
+    field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_UNKNOWN = -1; // 0xffffffff
+    field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_VISIBLE = 0; // 0x0
     field public static final int SHOW_IN_QUIET_MODE_DEFAULT = 2; // 0x2
     field public static final int SHOW_IN_QUIET_MODE_HIDDEN = 1; // 0x1
     field public static final int SHOW_IN_QUIET_MODE_PAUSED = 0; // 0x0
@@ -4372,6 +4381,41 @@
 
 }
 
+package android.credentials.selection {
+
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class FailureResult {
+    ctor public FailureResult(int, @Nullable String);
+    method public int getErrorCode();
+    method @Nullable public String getErrorMessage();
+    field public static final int ERROR_CODE_CANCELED_AND_LAUNCHED_SETTINGS = 2; // 0x2
+    field public static final int ERROR_CODE_DIALOG_CANCELED_BY_USER = 1; // 0x1
+    field public static final int ERROR_CODE_UI_FAILURE = 0; // 0x0
+  }
+
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class ProviderPendingIntentResponse implements android.os.Parcelable {
+    ctor public ProviderPendingIntentResponse(int, @Nullable android.content.Intent);
+    method public int describeContents();
+    method public int getResultCode();
+    method @Nullable public android.content.Intent getResultData();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.ProviderPendingIntentResponse> CREATOR;
+  }
+
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class ResultHelper {
+    method public static void sendFailureResult(@NonNull android.os.ResultReceiver, @NonNull android.credentials.selection.FailureResult);
+    method public static void sendUserSelectionResult(@NonNull android.os.ResultReceiver, @NonNull android.credentials.selection.UserSelectionResult);
+  }
+
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class UserSelectionResult {
+    ctor public UserSelectionResult(@NonNull String, @NonNull String, @NonNull String, @Nullable android.credentials.selection.ProviderPendingIntentResponse);
+    method @NonNull public String getEntryKey();
+    method @NonNull public String getEntrySubkey();
+    method @Nullable public android.credentials.selection.ProviderPendingIntentResponse getPendingIntentProviderResponse();
+    method @NonNull public String getProviderId();
+  }
+
+}
+
 package android.database {
 
   public abstract class ContentObserver {
@@ -6121,6 +6165,7 @@
     method public boolean containsKey(String);
     method public int describeContents();
     method @Deprecated public android.graphics.Bitmap getBitmap(String);
+    method @FlaggedApi("android.hardware.radio.hd_radio_improved") public int getBitmapId(@NonNull String);
     method public android.hardware.radio.RadioMetadata.Clock getClock(String);
     method public int getInt(String);
     method public String getString(String);
@@ -6184,6 +6229,7 @@
     method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract void close();
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
     method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public android.hardware.radio.ProgramList getDynamicProgramList(@Nullable android.hardware.radio.ProgramList.Filter);
+    method @FlaggedApi("android.hardware.radio.hd_radio_improved") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public android.graphics.Bitmap getMetadataImage(int);
     method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract boolean getMute();
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public java.util.Map<java.lang.String,java.lang.String> getParameters(@NonNull java.util.List<java.lang.String>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
@@ -6886,7 +6932,6 @@
   public final class MediaRouter2 {
     method @NonNull public java.util.List<android.media.MediaRoute2Info> getAllRoutes();
     method @Nullable public String getClientPackageName();
-    method @Nullable @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void setRouteVolume(@NonNull android.media.MediaRoute2Info, int);
     method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void startScan();
     method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void stopScan();
@@ -14774,6 +14819,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String);
     method public boolean needsOtaServiceProvisioning();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
+    method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @RequiresPermission(android.Manifest.permission.DUMP) public void persistEmergencyCallDiagnosticData(@NonNull String, @NonNull android.telephony.TelephonyManager.EmergencyCallDiagnosticParams);
     method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerCarrierPrivilegesCallback(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback);
@@ -14952,6 +14998,21 @@
     method public default void onCarrierServiceChanged(@Nullable String, int);
   }
 
+  @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") public static final class TelephonyManager.EmergencyCallDiagnosticParams {
+    method public long getLogcatCollectionStartTimeMillis();
+    method public boolean isLogcatCollectionEnabled();
+    method public boolean isTelecomDumpSysCollectionEnabled();
+    method public boolean isTelephonyDumpSysCollectionEnabled();
+  }
+
+  public static final class TelephonyManager.EmergencyCallDiagnosticParams.Builder {
+    ctor public TelephonyManager.EmergencyCallDiagnosticParams.Builder();
+    method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticParams build();
+    method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticParams.Builder setLogcatCollectionStartTimeMillis(long);
+    method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticParams.Builder setTelecomDumpSysCollectionEnabled(boolean);
+    method @NonNull public android.telephony.TelephonyManager.EmergencyCallDiagnosticParams.Builder setTelephonyDumpSysCollectionEnabled(boolean);
+  }
+
   public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
     ctor public TelephonyManager.ModemActivityInfoException(int);
     method public int getErrorCode();
@@ -17153,38 +17214,38 @@
   }
 
   @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class SatelliteManager {
-    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatelliteService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getAllSatellitePlmnsForCarrier(int);
-    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getSatelliteAttachRestrictionReasonsForCarrier(int);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingSatelliteDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatelliteService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getAttachRestrictionReasonsForCarrier(int);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatellitePlmnsForCarrier(int);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForCapabilitiesChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForIncomingDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteModemStateCallback);
     method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void registerForNtnSignalStrengthChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.NtnSignalStrengthCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteCapabilitiesChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteModemStateCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsAttachEnabledForCarrier(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsCommunicationAllowedForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsDemoModeEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteAttachEnabledForCarrier(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteCommunicationAllowedForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void requestIsSatelliteSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void requestIsSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestNtnSignalStrength(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.NtnSignalStrength,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestTimeForNextSatelliteVisibility(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.time.Duration,android.telephony.satellite.SatelliteManager.SatelliteException>);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void sendSatelliteDatagram(int, @NonNull android.telephony.satellite.SatelliteDatagram, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void sendDatagram(int, @NonNull android.telephony.satellite.SatelliteDatagram, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void setDeviceAlignedWithSatellite(boolean);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void startSatelliteTransmissionUpdates(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void stopSatelliteTransmissionUpdates(@NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void startTransmissionUpdates(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void stopTransmissionUpdates(@NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForCapabilitiesChanged(@NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForIncomingDatagram(@NonNull android.telephony.satellite.SatelliteDatagramCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForModemStateChanged(@NonNull android.telephony.satellite.SatelliteModemStateCallback);
     method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForNtnSignalStrengthChanged(@NonNull android.telephony.satellite.NtnSignalStrengthCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteCapabilitiesChanged(@NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteDatagram(@NonNull android.telephony.satellite.SatelliteDatagramCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteModemStateChanged(@NonNull android.telephony.satellite.SatelliteModemStateCallback);
-    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
     field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2; // 0x2
     field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1; // 0x1
     field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_UNKNOWN = 0; // 0x0
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index b8b98a3..c546d7a 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -195,8 +195,11 @@
     method public void setTaskOverlay(boolean, boolean);
   }
 
-  public static final class ActivityOptions.LaunchCookie {
+  public static final class ActivityOptions.LaunchCookie implements android.os.Parcelable {
     ctor public ActivityOptions.LaunchCookie();
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.ActivityOptions.LaunchCookie> CREATOR;
   }
 
   public static interface ActivityOptions.OnAnimationFinishedListener {
@@ -1262,9 +1265,9 @@
 
 }
 
-package android.credentials.ui {
+package android.credentials.selection {
 
-  public final class AuthenticationEntry implements android.os.Parcelable {
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class AuthenticationEntry implements android.os.Parcelable {
     ctor public AuthenticationEntry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, int);
     ctor public AuthenticationEntry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, int, @NonNull android.content.Intent);
     method public int describeContents();
@@ -1274,32 +1277,47 @@
     method @NonNull public int getStatus();
     method @NonNull public String getSubkey();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.AuthenticationEntry> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.AuthenticationEntry> CREATOR;
     field public static final int STATUS_LOCKED = 0; // 0x0
     field public static final int STATUS_UNLOCKED_BUT_EMPTY_LESS_RECENT = 1; // 0x1
     field public static final int STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT = 2; // 0x2
   }
 
-  public final class CreateCredentialProviderData extends android.credentials.ui.ProviderData implements android.os.Parcelable {
-    ctor public CreateCredentialProviderData(@NonNull String, @NonNull java.util.List<android.credentials.ui.Entry>, @Nullable android.credentials.ui.Entry);
-    method @Nullable public android.credentials.ui.Entry getRemoteEntry();
-    method @NonNull public java.util.List<android.credentials.ui.Entry> getSaveEntries();
-    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.CreateCredentialProviderData> CREATOR;
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public class BaseDialogResult implements android.os.Parcelable {
+    ctor public BaseDialogResult(@Nullable android.os.IBinder);
+    ctor protected BaseDialogResult(@NonNull android.os.Parcel);
+    method public static void addToBundle(@NonNull android.credentials.selection.BaseDialogResult, @NonNull android.os.Bundle);
+    method public int describeContents();
+    method @Nullable public static android.credentials.selection.BaseDialogResult fromResultData(@NonNull android.os.Bundle);
+    method @Deprecated @Nullable public android.os.IBinder getRequestToken();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.BaseDialogResult> CREATOR;
+    field public static final int RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS = 1; // 0x1
+    field public static final int RESULT_CODE_DATA_PARSING_FAILURE = 3; // 0x3
+    field public static final int RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION = 2; // 0x2
+    field public static final int RESULT_CODE_DIALOG_USER_CANCELED = 0; // 0x0
   }
 
-  public static final class CreateCredentialProviderData.Builder {
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class CreateCredentialProviderData extends android.credentials.selection.ProviderData implements android.os.Parcelable {
+    ctor public CreateCredentialProviderData(@NonNull String, @NonNull java.util.List<android.credentials.selection.Entry>, @Nullable android.credentials.selection.Entry);
+    method @Nullable public android.credentials.selection.Entry getRemoteEntry();
+    method @NonNull public java.util.List<android.credentials.selection.Entry> getSaveEntries();
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.CreateCredentialProviderData> CREATOR;
+  }
+
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public static final class CreateCredentialProviderData.Builder {
     ctor public CreateCredentialProviderData.Builder(@NonNull String);
-    method @NonNull public android.credentials.ui.CreateCredentialProviderData build();
-    method @NonNull public android.credentials.ui.CreateCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.ui.Entry);
-    method @NonNull public android.credentials.ui.CreateCredentialProviderData.Builder setSaveEntries(@NonNull java.util.List<android.credentials.ui.Entry>);
+    method @NonNull public android.credentials.selection.CreateCredentialProviderData build();
+    method @NonNull public android.credentials.selection.CreateCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.selection.Entry);
+    method @NonNull public android.credentials.selection.CreateCredentialProviderData.Builder setSaveEntries(@NonNull java.util.List<android.credentials.selection.Entry>);
   }
 
-  public final class DisabledProviderData extends android.credentials.ui.ProviderData implements android.os.Parcelable {
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class DisabledProviderData extends android.credentials.selection.ProviderData implements android.os.Parcelable {
     ctor public DisabledProviderData(@NonNull String);
-    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.DisabledProviderData> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.DisabledProviderData> CREATOR;
   }
 
-  public final class Entry implements android.os.Parcelable {
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class Entry implements android.os.Parcelable {
     ctor public Entry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice);
     ctor public Entry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, @NonNull android.content.Intent);
     method public int describeContents();
@@ -1309,56 +1327,81 @@
     method @NonNull public android.app.slice.Slice getSlice();
     method @NonNull public String getSubkey();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.Entry> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.Entry> CREATOR;
   }
 
-  public final class GetCredentialProviderData extends android.credentials.ui.ProviderData implements android.os.Parcelable {
-    ctor public GetCredentialProviderData(@NonNull String, @NonNull java.util.List<android.credentials.ui.Entry>, @NonNull java.util.List<android.credentials.ui.Entry>, @NonNull java.util.List<android.credentials.ui.AuthenticationEntry>, @Nullable android.credentials.ui.Entry);
-    method @NonNull public java.util.List<android.credentials.ui.Entry> getActionChips();
-    method @NonNull public java.util.List<android.credentials.ui.AuthenticationEntry> getAuthenticationEntries();
-    method @NonNull public java.util.List<android.credentials.ui.Entry> getCredentialEntries();
-    method @Nullable public android.credentials.ui.Entry getRemoteEntry();
-    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.GetCredentialProviderData> CREATOR;
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class FailureDialogResult extends android.credentials.selection.BaseDialogResult implements android.os.Parcelable {
+    ctor public FailureDialogResult(@Nullable android.os.IBinder, @Nullable String);
+    method public static void addToBundle(@NonNull android.credentials.selection.FailureDialogResult, @NonNull android.os.Bundle);
+    method @Nullable public static android.credentials.selection.FailureDialogResult fromResultData(@NonNull android.os.Bundle);
+    method @Nullable public String getErrorMessage();
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.FailureDialogResult> CREATOR;
   }
 
-  public static final class GetCredentialProviderData.Builder {
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class GetCredentialProviderData extends android.credentials.selection.ProviderData implements android.os.Parcelable {
+    ctor public GetCredentialProviderData(@NonNull String, @NonNull java.util.List<android.credentials.selection.Entry>, @NonNull java.util.List<android.credentials.selection.Entry>, @NonNull java.util.List<android.credentials.selection.AuthenticationEntry>, @Nullable android.credentials.selection.Entry);
+    method @NonNull public java.util.List<android.credentials.selection.Entry> getActionChips();
+    method @NonNull public java.util.List<android.credentials.selection.AuthenticationEntry> getAuthenticationEntries();
+    method @NonNull public java.util.List<android.credentials.selection.Entry> getCredentialEntries();
+    method @Nullable public android.credentials.selection.Entry getRemoteEntry();
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.GetCredentialProviderData> CREATOR;
+  }
+
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public static final class GetCredentialProviderData.Builder {
     ctor public GetCredentialProviderData.Builder(@NonNull String);
-    method @NonNull public android.credentials.ui.GetCredentialProviderData build();
-    method @NonNull public android.credentials.ui.GetCredentialProviderData.Builder setActionChips(@NonNull java.util.List<android.credentials.ui.Entry>);
-    method @NonNull public android.credentials.ui.GetCredentialProviderData.Builder setAuthenticationEntries(@NonNull java.util.List<android.credentials.ui.AuthenticationEntry>);
-    method @NonNull public android.credentials.ui.GetCredentialProviderData.Builder setCredentialEntries(@NonNull java.util.List<android.credentials.ui.Entry>);
-    method @NonNull public android.credentials.ui.GetCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.ui.Entry);
+    method @NonNull public android.credentials.selection.GetCredentialProviderData build();
+    method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setActionChips(@NonNull java.util.List<android.credentials.selection.Entry>);
+    method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setAuthenticationEntries(@NonNull java.util.List<android.credentials.selection.AuthenticationEntry>);
+    method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setCredentialEntries(@NonNull java.util.List<android.credentials.selection.Entry>);
+    method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.selection.Entry);
   }
 
-  public class IntentFactory {
-    method @NonNull public static android.content.Intent createCredentialSelectorIntent(@NonNull android.credentials.ui.RequestInfo, @NonNull java.util.ArrayList<android.credentials.ui.ProviderData>, @NonNull java.util.ArrayList<android.credentials.ui.DisabledProviderData>, @NonNull android.os.ResultReceiver);
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public class IntentFactory {
+    method @NonNull public static android.content.Intent createCredentialSelectorIntent(@NonNull android.credentials.selection.RequestInfo, @NonNull java.util.ArrayList<android.credentials.selection.ProviderData>, @NonNull java.util.ArrayList<android.credentials.selection.DisabledProviderData>, @NonNull android.os.ResultReceiver);
   }
 
-  public abstract class ProviderData implements android.os.Parcelable {
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public abstract class ProviderData implements android.os.Parcelable {
     ctor public ProviderData(@NonNull String);
     ctor protected ProviderData(@NonNull android.os.Parcel);
     method public int describeContents();
     method @NonNull public String getProviderFlattenedComponentName();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final String EXTRA_DISABLED_PROVIDER_DATA_LIST = "android.credentials.ui.extra.DISABLED_PROVIDER_DATA_LIST";
-    field public static final String EXTRA_ENABLED_PROVIDER_DATA_LIST = "android.credentials.ui.extra.ENABLED_PROVIDER_DATA_LIST";
+    field public static final String EXTRA_DISABLED_PROVIDER_DATA_LIST = "android.credentials.selection.extra.DISABLED_PROVIDER_DATA_LIST";
+    field public static final String EXTRA_ENABLED_PROVIDER_DATA_LIST = "android.credentials.selection.extra.ENABLED_PROVIDER_DATA_LIST";
   }
 
-  public final class RequestInfo implements android.os.Parcelable {
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class RequestInfo implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public String getAppPackageName();
     method @Nullable public android.credentials.CreateCredentialRequest getCreateCredentialRequest();
+    method @NonNull public java.util.List<java.lang.String> getDefaultProviderIds();
     method @Nullable public android.credentials.GetCredentialRequest getGetCredentialRequest();
+    method @NonNull public java.util.List<java.lang.String> getRegistryProviderIds();
     method @NonNull public android.os.IBinder getToken();
     method @NonNull public String getType();
-    method @NonNull public static android.credentials.ui.RequestInfo newCreateRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.CreateCredentialRequest, @NonNull String);
-    method @NonNull public static android.credentials.ui.RequestInfo newGetRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.GetCredentialRequest, @NonNull String);
+    method public boolean hasPermissionToOverrideDefault();
+    method @NonNull public static android.credentials.selection.RequestInfo newCreateRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.CreateCredentialRequest, @NonNull String);
+    method @NonNull public static android.credentials.selection.RequestInfo newCreateRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.CreateCredentialRequest, @NonNull String, boolean, @NonNull java.util.List<java.lang.String>);
+    method @NonNull public static android.credentials.selection.RequestInfo newGetRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.GetCredentialRequest, @NonNull String, boolean);
+    method @NonNull public static android.credentials.selection.RequestInfo newGetRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.GetCredentialRequest, @NonNull String);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.RequestInfo> CREATOR;
-    field @NonNull public static final String EXTRA_REQUEST_INFO = "android.credentials.ui.extra.REQUEST_INFO";
-    field @NonNull public static final String TYPE_CREATE = "android.credentials.ui.TYPE_CREATE";
-    field @NonNull public static final String TYPE_GET = "android.credentials.ui.TYPE_GET";
-    field @NonNull public static final String TYPE_UNDEFINED = "android.credentials.ui.TYPE_UNDEFINED";
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.RequestInfo> CREATOR;
+    field @NonNull public static final String EXTRA_REQUEST_INFO = "android.credentials.selection.extra.REQUEST_INFO";
+    field @NonNull public static final String TYPE_CREATE = "android.credentials.selection.TYPE_CREATE";
+    field @NonNull public static final String TYPE_GET = "android.credentials.selection.TYPE_GET";
+    field @NonNull public static final String TYPE_UNDEFINED = "android.credentials.selection.TYPE_UNDEFINED";
+  }
+
+  @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class UserSelectionDialogResult extends android.credentials.selection.BaseDialogResult implements android.os.Parcelable {
+    ctor public UserSelectionDialogResult(@Nullable android.os.IBinder, @NonNull String, @NonNull String, @NonNull String);
+    ctor public UserSelectionDialogResult(@Nullable android.os.IBinder, @NonNull String, @NonNull String, @NonNull String, @Nullable android.credentials.selection.ProviderPendingIntentResponse);
+    method public static void addToBundle(@NonNull android.credentials.selection.UserSelectionDialogResult, @NonNull android.os.Bundle);
+    method @Nullable public static android.credentials.selection.UserSelectionDialogResult fromResultData(@NonNull android.os.Bundle);
+    method @NonNull public String getEntryKey();
+    method @NonNull public String getEntrySubkey();
+    method @Nullable public android.credentials.selection.ProviderPendingIntentResponse getPendingIntentProviderResponse();
+    method @NonNull public String getProviderId();
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.UserSelectionDialogResult> CREATOR;
   }
 
 }
@@ -2068,6 +2111,14 @@
 
 }
 
+package android.media.projection {
+
+  public final class MediaProjectionManager {
+    method @NonNull public android.content.Intent createScreenCaptureIntent(@Nullable android.app.ActivityOptions.LaunchCookie);
+  }
+
+}
+
 package android.media.soundtrigger {
 
   public final class SoundTriggerInstrumentation {
@@ -2603,7 +2654,6 @@
     method @NonNull public static String convert(@NonNull java.util.UUID);
     method @Nullable public String getCloudMediaProvider();
     method public boolean isAppIoBlocked(@NonNull java.util.UUID, int, int, int);
-    method public static boolean isUserKeyUnlocked(int);
     field public static final String CACHE_RESERVE_PERCENT_HIGH_KEY = "cache_reserve_percent_high";
     field public static final String CACHE_RESERVE_PERCENT_LOW_KEY = "cache_reserve_percent_low";
     field public static final String STORAGE_THRESHOLD_PERCENT_HIGH_KEY = "storage_threshold_percent_high";
@@ -3646,6 +3696,7 @@
 
   public interface WindowManager extends android.view.ViewManager {
     method public default int getDisplayImePolicy(int);
+    method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @Nullable public default android.os.IBinder getSurfaceControlInputClientToken(@NonNull android.view.SurfaceControl);
     method public static boolean hasWindowExtensionsEnabled();
     method public default void holdLock(android.os.IBinder, int);
     method public default boolean isGlobalKey(int);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9d20f3c..6285eb3 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -107,6 +107,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -4440,8 +4441,7 @@
      * is used here, you will receive a call each time a uids importance transitions between
      * being <= {@link RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE} and
      * > {@link RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE}.
-     * @param uids The UIDs that this listener is interested with. A {@code null} value means
-     * all UIDs will be monitored by this listener, this will be equivalent to the
+     * @param uids The UIDs that this listener is interested with.
      * {@link #addOnUidImportanceListener(OnUidImportanceListener, int)} in this case.
      *
      * <p>Calling this API with the same instance of {@code listener} without
@@ -4456,7 +4456,9 @@
     @SuppressLint("SamShouldBeLast")
     @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
     public void addOnUidImportanceListener(@NonNull OnUidImportanceListener listener,
-            @RunningAppProcessInfo.Importance int importanceCutpoint, @Nullable int[] uids) {
+            @RunningAppProcessInfo.Importance int importanceCutpoint, @NonNull int[] uids) {
+        Objects.requireNonNull(listener);
+        Objects.requireNonNull(uids);
         addOnUidImportanceListenerInternal(listener, importanceCutpoint, uids);
     }
 
diff --git a/core/java/android/app/ActivityOptions.aidl b/core/java/android/app/ActivityOptions.aidl
index bd5cd88..2d4a85f 100644
--- a/core/java/android/app/ActivityOptions.aidl
+++ b/core/java/android/app/ActivityOptions.aidl
@@ -17,4 +17,7 @@
 package android.app;
 
 /** @hide */
-parcelable ActivityOptions.SceneTransitionInfo;
\ No newline at end of file
+parcelable ActivityOptions.SceneTransitionInfo;
+
+/** @hide */
+parcelable ActivityOptions.LaunchCookie;
\ No newline at end of file
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 57fca74..111895e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -184,6 +184,12 @@
     public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";
 
     /**
+     * Callback for when animation is aborted.
+     * @hide
+     */
+    private static final String KEY_ANIM_ABORT_LISTENER = "android:activity.animAbortListener";
+
+    /**
      * Specific a theme for a splash screen window.
      * @hide
      */
@@ -459,6 +465,7 @@
     private int mHeight;
     private IRemoteCallback mAnimationStartedListener;
     private IRemoteCallback mAnimationFinishedListener;
+    private IRemoteCallback mAnimationAbortListener;
     private SceneTransitionInfo mSceneTransitionInfo;
     private PendingIntent mUsageTimeReport;
     private int mLaunchDisplayId = INVALID_DISPLAY;
@@ -716,6 +723,14 @@
     }
 
     /**
+     * Callback for finding out when the given animation is finished
+     * @hide
+     */
+    public void setOnAnimationFinishedListener(IRemoteCallback listener) {
+        mAnimationFinishedListener = listener;
+    }
+
+    /**
      * Callback for finding out when the given animation has drawn its last frame.
      * @hide
      */
@@ -728,6 +743,14 @@
     }
 
     /**
+     * Callback for finding out when the given animation is aborted
+     * @hide
+     */
+    public void setOnAnimationAbortListener(IRemoteCallback listener) {
+        mAnimationAbortListener = listener;
+    }
+
+    /**
      * Create an ActivityOptions specifying an animation where the new
      * activity is scaled from a small originating area of the screen to
      * its final full representation.
@@ -1327,6 +1350,8 @@
                 KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE,
                 MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED);
         mDisableStartingWindow = opts.getBoolean(KEY_DISABLE_STARTING_WINDOW);
+        mAnimationAbortListener = IRemoteCallback.Stub.asInterface(
+                opts.getBinder(KEY_ANIM_ABORT_LISTENER));
     }
 
     /**
@@ -1427,11 +1452,15 @@
 
     /** @hide */
     public void abort() {
-        if (mAnimationStartedListener != null) {
+        sendResultIgnoreErrors(mAnimationStartedListener, null);
+        sendResultIgnoreErrors(mAnimationAbortListener, null);
+    }
+
+    private void sendResultIgnoreErrors(IRemoteCallback callback, Bundle data) {
+        if (callback != null) {
             try {
-                mAnimationStartedListener.sendResult(null);
-            } catch (RemoteException e) {
-            }
+                callback.sendResult(data);
+            } catch (RemoteException e) { }
         }
     }
 
@@ -1929,14 +1958,87 @@
      */
     @SuppressLint("UnflaggedApi")
     @TestApi
-    public static final class LaunchCookie {
+    public static final class LaunchCookie implements Parcelable {
         /** @hide */
-        public final IBinder binder = new Binder();
+        public final IBinder binder;
 
         /** @hide */
         @SuppressLint("UnflaggedApi")
         @TestApi
-        public LaunchCookie() {}
+        public LaunchCookie() {
+            binder = new Binder();
+        }
+
+        /** @hide */
+        public LaunchCookie(@Nullable String descriptor) {
+            binder = new Binder(descriptor);
+        }
+
+        private LaunchCookie(Parcel in) {
+            this.binder = in.readStrongBinder();
+        }
+
+        /** @hide */
+        @SuppressLint("UnflaggedApi")
+        @TestApi
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        /** @hide */
+        @SuppressLint("UnflaggedApi")
+        @TestApi
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeStrongBinder(binder);
+        }
+
+        /** @hide */
+        public static LaunchCookie readFromParcel(@NonNull Parcel in) {
+            return new LaunchCookie(in);
+        }
+
+        /** @hide */
+        public static void writeToParcel(@Nullable LaunchCookie launchCookie, Parcel out) {
+            if (launchCookie != null) {
+                launchCookie.writeToParcel(out, 0);
+            } else {
+                out.writeStrongBinder(null);
+            }
+        }
+
+        /** @hide */
+        @SuppressLint("UnflaggedApi")
+        @TestApi
+        @NonNull
+        public static final Parcelable.Creator<LaunchCookie> CREATOR =
+                new Parcelable.Creator<LaunchCookie>() {
+
+                    @Override
+                    public LaunchCookie createFromParcel(Parcel source) {
+                        return new LaunchCookie(source);
+                    }
+
+                    @Override
+                    public LaunchCookie[] newArray(int size) {
+                        return new LaunchCookie[size];
+                    }
+                };
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (obj instanceof LaunchCookie) {
+                LaunchCookie other = (LaunchCookie) obj;
+                return binder == other.binder;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return binder.hashCode();
+        }
     }
 
     /**
@@ -2110,12 +2212,7 @@
                 mCustomExitResId = otherOptions.mCustomExitResId;
                 mCustomBackgroundColor = otherOptions.mCustomBackgroundColor;
                 mThumbnail = null;
-                if (mAnimationStartedListener != null) {
-                    try {
-                        mAnimationStartedListener.sendResult(null);
-                    } catch (RemoteException e) {
-                    }
-                }
+                sendResultIgnoreErrors(mAnimationStartedListener, null);
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
                 break;
             case ANIM_CUSTOM_IN_PLACE:
@@ -2126,12 +2223,7 @@
                 mStartY = otherOptions.mStartY;
                 mWidth = otherOptions.mWidth;
                 mHeight = otherOptions.mHeight;
-                if (mAnimationStartedListener != null) {
-                    try {
-                        mAnimationStartedListener.sendResult(null);
-                    } catch (RemoteException e) {
-                    }
-                }
+                sendResultIgnoreErrors(mAnimationStartedListener, null);
                 mAnimationStartedListener = null;
                 break;
             case ANIM_THUMBNAIL_SCALE_UP:
@@ -2143,12 +2235,7 @@
                 mStartY = otherOptions.mStartY;
                 mWidth = otherOptions.mWidth;
                 mHeight = otherOptions.mHeight;
-                if (mAnimationStartedListener != null) {
-                    try {
-                        mAnimationStartedListener.sendResult(null);
-                    } catch (RemoteException e) {
-                    }
-                }
+                sendResultIgnoreErrors(mAnimationStartedListener, null);
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
                 break;
             case ANIM_SCENE_TRANSITION:
@@ -2165,6 +2252,9 @@
         mRemoteAnimationAdapter = otherOptions.mRemoteAnimationAdapter;
         mLaunchIntoPipParams = otherOptions.mLaunchIntoPipParams;
         mIsEligibleForLegacyPermissionPrompt = otherOptions.mIsEligibleForLegacyPermissionPrompt;
+
+        sendResultIgnoreErrors(mAnimationAbortListener, null);
+        mAnimationAbortListener = otherOptions.mAnimationAbortListener;
     }
 
     /**
@@ -2363,6 +2453,8 @@
         if (mDisableStartingWindow) {
             b.putBoolean(KEY_DISABLE_STARTING_WINDOW, mDisableStartingWindow);
         }
+        b.putBinder(KEY_ANIM_ABORT_LISTENER,
+                mAnimationAbortListener != null ? mAnimationAbortListener.asBinder() : null);
         return b;
     }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1bdbd4c5..5d2a26e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -319,6 +319,10 @@
     public static final int SERVICE_DONE_EXECUTING_START = 1;
     /** Type for IActivityManager.serviceDoneExecuting: done stopping (destroying) service */
     public static final int SERVICE_DONE_EXECUTING_STOP = 2;
+    /** Type for IActivityManager.serviceDoneExecuting: done with an onRebind call */
+    public static final int SERVICE_DONE_EXECUTING_REBIND = 3;
+    /** Type for IActivityManager.serviceDoneExecuting: done with an onUnbind call */
+    public static final int SERVICE_DONE_EXECUTING_UNBIND = 4;
 
     /** Use foreground GC policy (less pause time) and higher JIT weight. */
     private static final int VM_PROCESS_STATE_JANK_PERCEPTIBLE = 0;
@@ -4882,7 +4886,7 @@
             mServices.put(data.token, service);
             try {
                 ActivityManager.getService().serviceDoneExecuting(
-                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
+                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0, null);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -4913,7 +4917,7 @@
                     } else {
                         s.onRebind(data.intent);
                         ActivityManager.getService().serviceDoneExecuting(
-                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
+                                data.token, SERVICE_DONE_EXECUTING_REBIND, 0, 0, data.intent);
                     }
                 } catch (RemoteException ex) {
                     throw ex.rethrowFromSystemServer();
@@ -4943,7 +4947,7 @@
                                 data.token, data.intent, doRebind);
                     } else {
                         ActivityManager.getService().serviceDoneExecuting(
-                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
+                                data.token, SERVICE_DONE_EXECUTING_UNBIND, 0, 0, data.intent);
                     }
                 } catch (RemoteException ex) {
                     throw ex.rethrowFromSystemServer();
@@ -5057,7 +5061,7 @@
 
                 try {
                     ActivityManager.getService().serviceDoneExecuting(
-                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
+                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res, null);
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
@@ -5089,7 +5093,7 @@
 
                 try {
                     ActivityManager.getService().serviceDoneExecuting(
-                            token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
+                            token, SERVICE_DONE_EXECUTING_STOP, 0, 0, null);
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ccd8456..bb666e6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1548,9 +1548,31 @@
     public static final int OP_READ_SYSTEM_GRAMMATICAL_GENDER =
             AppProtoEnums.APP_OP_READ_SYSTEM_GRAMMATICAL_GENDER;
 
+    /**
+     * Allows an app whose primary use case is to backup or sync content to run longer jobs.
+     *
+     * @hide
+     */
+    public static final int OP_RUN_BACKUP_JOBS = AppProtoEnums.APP_OP_RUN_BACKUP_JOBS;
+
+    /**
+     * Whether the app has enabled to receive the icon overlay for fetching archived apps.
+     *
+     * @hide
+     */
+    public static final int OP_ARCHIVE_ICON_OVERLAY = AppProtoEnums.APP_OP_ARCHIVE_ICON_OVERLAY;
+
+    /**
+     * Whether the app has enabled compatibility support for unarchival.
+     *
+     * @hide
+     */
+    public static final int OP_UNARCHIVAL_CONFIRMATION =
+            AppProtoEnums.APP_OP_UNARCHIVAL_CONFIRMATION;
+
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final int _NUM_OP = 144;
+    public static final int _NUM_OP = 147;
 
     /**
      * All app ops represented as strings.
@@ -1700,6 +1722,9 @@
             OPSTR_ENABLE_MOBILE_DATA_BY_USER,
             OPSTR_RESERVED_FOR_TESTING,
             OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
+            OPSTR_RUN_BACKUP_JOBS,
+            OPSTR_ARCHIVE_ICON_OVERLAY,
+            OPSTR_UNARCHIVAL_CONFIRMATION,
     })
     public @interface AppOpString {}
 
@@ -2040,6 +2065,20 @@
     public static final String OPSTR_MEDIA_ROUTING_CONTROL = "android:media_routing_control";
 
     /**
+     * Whether the app has enabled to receive the icon overlay for fetching archived apps.
+     *
+     * @hide
+     */
+    public static final String OPSTR_ARCHIVE_ICON_OVERLAY = "android:archive_icon_overlay";
+
+    /**
+     * Whether the app has enabled compatibility support for unarchival.
+     *
+     * @hide
+     */
+    public static final String OPSTR_UNARCHIVAL_CONFIRMATION = "android:unarchival_support";
+
+    /**
      * AppOp granted to apps that we are started via {@code am instrument -e --no-isolated-storage}
      *
      * <p>MediaProvider is the only component (outside of system server) that should care about this
@@ -2392,6 +2431,13 @@
     public static final String OPSTR_READ_SYSTEM_GRAMMATICAL_GENDER =
             "android:read_system_grammatical_gender";
 
+    /**
+     * Allows an app whose primary use case is to backup or sync content to run longer jobs.
+     *
+     * @hide
+     */
+    public static final String OPSTR_RUN_BACKUP_JOBS = "android:run_backup_jobs";
+
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
     /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2504,6 +2550,9 @@
             OP_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA,
             OP_MEDIA_ROUTING_CONTROL,
             OP_READ_SYSTEM_GRAMMATICAL_GENDER,
+            OP_RUN_BACKUP_JOBS,
+            OP_ARCHIVE_ICON_OVERLAY,
+            OP_UNARCHIVAL_CONFIRMATION,
     };
 
     static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{
@@ -2961,6 +3010,14 @@
                 // will make it an app-op permission in the future.
                 // .setPermission(Manifest.permission.READ_SYSTEM_GRAMMATICAL_GENDER)
                 .build(),
+        new AppOpInfo.Builder(OP_RUN_BACKUP_JOBS, OPSTR_RUN_BACKUP_JOBS, "RUN_BACKUP_JOBS")
+                .setPermission(Manifest.permission.RUN_BACKUP_JOBS).build(),
+        new AppOpInfo.Builder(OP_ARCHIVE_ICON_OVERLAY, OPSTR_ARCHIVE_ICON_OVERLAY,
+                "ARCHIVE_ICON_OVERLAY")
+                .setDefaultMode(MODE_ALLOWED).build(),
+        new AppOpInfo.Builder(OP_UNARCHIVAL_CONFIRMATION, OPSTR_UNARCHIVAL_CONFIRMATION,
+                "UNARCHIVAL_CONFIRMATION")
+                .setDefaultMode(MODE_ALLOWED).build(),
     };
 
     // The number of longs needed to form a full bitmask of app ops
@@ -3095,7 +3152,7 @@
 
     /**
      * Retrieve the permission associated with an operation, or null if there is not one.
-     *
+
      * @param op The operation name.
      *
      * @hide
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 34c44f9..4f1db7d 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -4032,7 +4032,8 @@
     private Drawable getArchivedAppIcon(String packageName) {
         try {
             return new BitmapDrawable(null,
-                    mPM.getArchivedAppIcon(packageName, new UserHandle(getUserId())));
+                    mPM.getArchivedAppIcon(packageName, new UserHandle(getUserId()),
+                            mContext.getPackageName()));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/BackgroundInstallControlManager.java b/core/java/android/app/BackgroundInstallControlManager.java
new file mode 100644
index 0000000..664fceb
--- /dev/null
+++ b/core/java/android/app/BackgroundInstallControlManager.java
@@ -0,0 +1,102 @@
+/*
+ * 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 android.app;
+
+import static android.Manifest.permission.GET_BACKGROUND_INSTALLED_PACKAGES;
+import static android.annotation.SystemApi.Client.PRIVILEGED_APPS;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.content.pm.IBackgroundInstallControlService;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import java.util.List;
+
+/**
+ * BackgroundInstallControlManager client allows apps to query apps installed in background.
+ *
+ * <p>Any applications that was installed without an accompanying installer UI activity paired
+ * with recorded user interaction event is considered background installed. This is determined by
+ * analysis of user-activity logs.
+ *
+ * <p>Warning: BackgroundInstallControl should not be considered a definitive
+ * authority of identifying background installed applications. Consumers can use this as a
+ * supplementary signal, but must perform additional due diligence to confirm the install nature
+ * of the package.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_BIC_CLIENT)
+@SystemApi(client = PRIVILEGED_APPS)
+@SystemService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE)
+public final class BackgroundInstallControlManager {
+
+    private static final String TAG = "BackgroundInstallControlManager";
+    private static IBackgroundInstallControlService sService;
+    private final Context mContext;
+
+    BackgroundInstallControlManager(Context context) {
+        mContext = context;
+    }
+
+    private static IBackgroundInstallControlService getService() {
+        if (sService == null) {
+            sService =
+                    IBackgroundInstallControlService.Stub.asInterface(
+                            ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
+        }
+        return sService;
+    }
+
+    /**
+     * Returns a full list of {@link PackageInfo} of apps currently installed for the current user
+     * that are considered installed in the background.
+     *
+     * <p>Refer to top level doc {@link BackgroundInstallControlManager} for more details on
+     * background-installed applications.
+     * <p>
+     *
+     * @param flags - Flags will be used to call
+     * {@link PackageManager#getInstalledPackages(PackageInfoFlags)} to retrieve installed packages.
+     * @return A list of packages retrieved from {@link PackageManager} with non-background
+     * installed app filter applied.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_BIC_CLIENT)
+    @SystemApi
+    @RequiresPermission(GET_BACKGROUND_INSTALLED_PACKAGES)
+    public @NonNull List<PackageInfo> getBackgroundInstalledPackages(
+            @PackageManager.PackageInfoFlagsBits long flags) {
+        List<PackageInfo> backgroundInstalledPackages;
+        try {
+            return getService()
+                    .getBackgroundInstalledPackages(flags, mContext.getUserId())
+                    .getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ed00d9c..b0f6c46 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -240,7 +240,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mOpPackageName;
     private final @NonNull ContextParams mParams;
-    private final @NonNull AttributionSource mAttributionSource;
+    private @NonNull AttributionSource mAttributionSource;
 
     private final @NonNull ResourcesManager mResourcesManager;
     @UnsupportedAppUsage
@@ -2630,10 +2630,9 @@
                 flags | CONTEXT_REGISTER_PACKAGE);
         if (pi != null) {
             ContextImpl c = new ContextImpl(this, mMainThread, pi, ContextParams.EMPTY,
-                    mAttributionSource.getAttributionTag(),
-                    mAttributionSource.getNext(),
-                    null, mToken, new UserHandle(UserHandle.getUserId(application.uid)),
-                    flags, null, null);
+                    mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), null,
+                    mToken, new UserHandle(UserHandle.getUserId(application.uid)), flags, null,
+                    null, mDeviceId, mIsExplicitDeviceId);
 
             final int displayId = getDisplayId();
             final Integer overrideDisplayId = mForceDisplayOverrideInResources
@@ -2679,18 +2678,16 @@
             // The system resources are loaded in every application, so we can safely copy
             // the context without reloading Resources.
             return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
-                    mAttributionSource.getAttributionTag(),
-                    mAttributionSource.getNext(),
-                    null, mToken, user, flags, null, null);
+                    mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), null,
+                    mToken, user, flags, null, null, mDeviceId, mIsExplicitDeviceId);
         }
 
         LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                 flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
         if (pi != null) {
             ContextImpl c = new ContextImpl(this, mMainThread, pi, mParams,
-                    mAttributionSource.getAttributionTag(),
-                    mAttributionSource.getNext(),
-                    null, mToken, user, flags, null, null);
+                    mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), null,
+                    mToken, user, flags, null, null, mDeviceId, mIsExplicitDeviceId);
 
             final int displayId = getDisplayId();
             final Integer overrideDisplayId = mForceDisplayOverrideInResources
@@ -2729,9 +2726,8 @@
         final String[] paths = mPackageInfo.getSplitPaths(splitName);
 
         final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
-                mAttributionSource.getAttributionTag(),
-                mAttributionSource.getNext(),
-                splitName, mToken, mUser, mFlags, classLoader, null);
+                mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), splitName,
+                mToken, mUser, mFlags, classLoader, null, mDeviceId, mIsExplicitDeviceId);
 
         context.setResources(ResourcesManager.getInstance().getResources(
                 mToken,
@@ -2765,9 +2761,9 @@
         }
 
         ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
-                mAttributionSource.getAttributionTag(),
-                mAttributionSource.getNext(),
-                mSplitName, mToken, mUser, mFlags, mClassLoader, null);
+                mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+                mToken, mUser, mFlags, mClassLoader, null, mDeviceId,
+                mIsExplicitDeviceId);
         context.mIsConfigurationBasedContext = true;
 
         final int displayId = getDisplayId();
@@ -2786,9 +2782,8 @@
         }
 
         ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
-                mAttributionSource.getAttributionTag(),
-                mAttributionSource.getNext(),
-                mSplitName, mToken, mUser, mFlags, mClassLoader, null);
+                mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+                mToken, mUser, mFlags, mClassLoader, null, mDeviceId, mIsExplicitDeviceId);
 
         final int displayId = display.getDisplayId();
 
@@ -2833,14 +2828,9 @@
             }
         }
 
-        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
-                mAttributionSource.getAttributionTag(),
-                mAttributionSource.getNext(),
-                mSplitName, mToken, mUser, mFlags, mClassLoader, null);
-
-        context.mDeviceId = deviceId;
-        context.mIsExplicitDeviceId = true;
-        return context;
+        return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
+                mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+                mToken, mUser, mFlags, mClassLoader, null, deviceId, true);
     }
 
     @NonNull
@@ -2926,9 +2916,8 @@
     @UiContext
     ContextImpl createWindowContextBase(@NonNull IBinder token, int displayId) {
         ContextImpl baseContext = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
-                mAttributionSource.getAttributionTag(),
-                mAttributionSource.getNext(),
-                mSplitName, token, mUser, mFlags, mClassLoader, null);
+                mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+                token, mUser, mFlags, mClassLoader, null, mDeviceId, mIsExplicitDeviceId);
         // Window contexts receive configurations directly from the server and as such do not
         // need to override their display in ResourcesManager.
         baseContext.mForceDisplayOverrideInResources = false;
@@ -2979,7 +2968,8 @@
     public Context createContext(@NonNull ContextParams contextParams) {
         return new ContextImpl(this, mMainThread, mPackageInfo, contextParams,
                 contextParams.getAttributionTag(), contextParams.getNextAttributionSource(),
-                mSplitName, mToken, mUser, mFlags, mClassLoader, null);
+                mSplitName, mToken, mUser, mFlags, mClassLoader, null, mDeviceId,
+                mIsExplicitDeviceId);
     }
 
     @Override
@@ -2993,9 +2983,8 @@
         final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
                 | Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
         return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
-                mAttributionSource.getAttributionTag(),
-                mAttributionSource.getNext(),
-                mSplitName, mToken, mUser, flags, mClassLoader, null);
+                mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+                mToken, mUser, flags, mClassLoader, null, mDeviceId, mIsExplicitDeviceId);
     }
 
     @Override
@@ -3003,9 +2992,8 @@
         final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
                 | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
         return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
-                mAttributionSource.getAttributionTag(),
-                mAttributionSource.getNext(),
-                mSplitName, mToken, mUser, flags, mClassLoader, null);
+                mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+                mToken, mUser, flags, mClassLoader, null, mDeviceId, mIsExplicitDeviceId);
     }
 
     @Override
@@ -3098,6 +3086,7 @@
             int deviceId = vdm.getDeviceIdForDisplayId(displayId);
             if (deviceId != mDeviceId) {
                 mDeviceId = deviceId;
+                mAttributionSource = mAttributionSource.withDeviceId(mDeviceId);
                 notifyOnDeviceChangedListeners(mDeviceId);
             }
         }
@@ -3298,7 +3287,8 @@
     static ContextImpl createSystemContext(ActivityThread mainThread) {
         LoadedApk packageInfo = new LoadedApk(mainThread);
         ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
-                ContextParams.EMPTY, null, null, null, null, null, 0, null, null);
+                ContextParams.EMPTY, null, null, null, null, null, 0, null, null,
+                DEVICE_ID_DEFAULT, false);
         context.setResources(packageInfo.getResources());
         context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
                 context.mResourcesManager.getDisplayMetrics());
@@ -3333,7 +3323,8 @@
             String opPackageName) {
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
         ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
-            ContextParams.EMPTY, null, null, null, null, null, 0, null, opPackageName);
+                ContextParams.EMPTY, null, null, null, null, null, 0, null, opPackageName,
+                DEVICE_ID_DEFAULT, false);
         context.setResources(packageInfo.getResources());
         context.mContextType = isSystemOrSystemUI(context) ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
                 : CONTEXT_TYPE_NON_UI;
@@ -3371,7 +3362,7 @@
 
         ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
                 attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader,
-                null);
+                null, DEVICE_ID_DEFAULT, false);
         context.mContextType = CONTEXT_TYPE_ACTIVITY;
         context.mIsConfigurationBasedContext = true;
 
@@ -3407,7 +3398,8 @@
             @NonNull LoadedApk packageInfo, @NonNull ContextParams params,
             @Nullable String attributionTag, @Nullable AttributionSource nextAttributionSource,
             @Nullable String splitName, @Nullable IBinder token, @Nullable UserHandle user,
-            int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) {
+            int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName,
+            int deviceId, boolean isExplicitDeviceId) {
         mOuterContext = this;
         // If creator didn't specify which storage to use, use the default
         // location for application.
@@ -3437,13 +3429,18 @@
 
         String opPackageName;
 
+        mDeviceId = deviceId;
+        mIsExplicitDeviceId = isExplicitDeviceId;
+
         if (container != null) {
             mBasePackageName = container.mBasePackageName;
             opPackageName = container.mOpPackageName;
             setResources(container.mResources);
             mDisplay = container.mDisplay;
-            mDeviceId = container.mDeviceId;
-            mIsExplicitDeviceId = container.mIsExplicitDeviceId;
+            if (!isExplicitDeviceId) {
+                mIsExplicitDeviceId = container.mIsExplicitDeviceId;
+                mDeviceId = container.mDeviceId;
+            }
             mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
             mIsConfigurationBasedContext = container.mIsConfigurationBasedContext;
             mContextType = container.mContextType;
@@ -3466,17 +3463,18 @@
         mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName;
         mParams = Objects.requireNonNull(params);
         mAttributionSource = createAttributionSource(attributionTag, nextAttributionSource,
-                params.getRenouncedPermissions(), params.shouldRegisterAttributionSource());
+                params.getRenouncedPermissions(), params.shouldRegisterAttributionSource(), mDeviceId);
         mContentResolver = new ApplicationContentResolver(this, mainThread);
     }
 
     private @NonNull AttributionSource createAttributionSource(@Nullable String attributionTag,
             @Nullable AttributionSource nextAttributionSource,
-            @Nullable Set<String> renouncedPermissions, boolean shouldRegister) {
+            @Nullable Set<String> renouncedPermissions, boolean shouldRegister,
+            int deviceId) {
         AttributionSource attributionSource = new AttributionSource(Process.myUid(),
                 Process.myPid(), mOpPackageName, attributionTag,
                 (renouncedPermissions != null) ? renouncedPermissions.toArray(new String[0]) : null,
-                getDeviceId(), nextAttributionSource);
+                deviceId, nextAttributionSource);
         // If we want to access protected data on behalf of another app we need to
         // tell the OS that we opt in to participate in the attribution chain.
         if (nextAttributionSource != null || shouldRegister) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 47403d2..b063d04 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -294,7 +294,8 @@
     @UnsupportedAppUsage
     ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
     @UnsupportedAppUsage
-    oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res);
+    oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res,
+            in Intent intent);
     /** @deprecated  Use {@link #getIntentSenderWithFeature} instead */
     @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@link PendingIntent#getIntentSender()} instead")
     IIntentSender getIntentSender(int type, in String packageName, in IBinder token,
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 2162e3a..68512b8 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -79,6 +79,7 @@
  * implementation is described to the system through an AndroidManifest.xml's
  * &lt;instrumentation&gt; tag.
  */
+@android.ravenwood.annotation.RavenwoodKeepPartialClass
 public class Instrumentation {
 
     /**
@@ -132,6 +133,7 @@
     private UiAutomation mUiAutomation;
     private final Object mAnimationCompleteLock = new Object();
 
+    @android.ravenwood.annotation.RavenwoodKeep
     public Instrumentation() {
     }
 
@@ -142,6 +144,7 @@
      * reflection, but it will serve as noticeable discouragement from
      * doing such a thing.
      */
+    @android.ravenwood.annotation.RavenwoodReplace
     private void checkInstrumenting(String method) {
         // Check if we have an instrumentation context, as init should only get called by
         // the system in startup processes that are being instrumented.
@@ -151,6 +154,11 @@
         }
     }
 
+    private void checkInstrumenting$ravenwood(String method) {
+        // At the moment, Ravenwood doesn't attach a Context, but we're only ever
+        // running code as part of tests, so we continue quietly
+    }
+
     /**
      * Returns if it is being called in an instrumentation environment.
      *
@@ -2504,6 +2512,7 @@
      * Takes control of the execution of messages on the specified looper until
      * {@link TestLooperManager#release} is called.
      */
+    @android.ravenwood.annotation.RavenwoodKeep
     public TestLooperManager acquireLooperManager(Looper looper) {
         checkInstrumenting("acquireLooperManager");
         return new TestLooperManager(looper);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ed0cfbe..a81ad3c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5487,6 +5487,15 @@
             return mColors;
         }
 
+        /**
+         * @param isHeader If the notification is a notification header
+         * @return An instance of mColors after resolving the palette
+         */
+        private Colors getColors(boolean isHeader) {
+            mColors.resolvePalette(mContext, mN.color, !isHeader && mN.isColorized(), mInNightMode);
+            return mColors;
+        }
+
         private void updateBackgroundColor(RemoteViews contentView,
                 StandardTemplateParams p) {
             if (isBackgroundColorized(p)) {
@@ -6618,6 +6627,23 @@
             return getColors(p).getContrastColor();
         }
 
+        /**
+         * Gets the foreground color of the small icon.  If the notification is colorized, this
+         * is the primary text color, otherwise it's the contrast-adjusted app-provided color.
+         * @hide
+         */
+        public @ColorInt int getSmallIconColor(boolean isHeader) {
+            return getColors(/* isHeader = */ isHeader).getContrastColor();
+        }
+
+        /**
+         * Gets the background color of the notification.
+         * @hide
+         */
+        public @ColorInt int getBackgroundColor(boolean isHeader) {
+            return getColors(/* isHeader = */ isHeader).getBackgroundColor();
+        }
+
         /** @return the theme's accent color for colored UI elements. */
         private @ColorInt int getPrimaryAccentColor(StandardTemplateParams p) {
             return getColors(p).getPrimaryAccentColor();
@@ -8532,6 +8558,8 @@
             boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
             boolean isHeaderless = !isConversationLayout && isCollapsed;
 
+            //TODO (b/217799515): ensure mConversationTitle always returns the correct
+            // conversationTitle, probably set mConversationTitle = conversationTitle after this
             CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
                     ? super.mBigContentTitle
                     : mConversationTitle;
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 0760d4d..3b5bba2 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -90,8 +90,8 @@
 per-file pinner-client.aconfig = file:/core/java/android/app/pinner/OWNERS
 
 # BackgroundInstallControlManager
-per-file BackgroundInstallControlManager.java = file:/services/core/java/com/android/server/pm/OWNERS
-per-file background_install_control_manager.aconfig = file:/services/core/java/com/android/server/pm/OWNERS
+per-file BackgroundInstallControlManager.java = file:/services/core/java/com/android/server/pm/BACKGROUND_INSTALL_OWNERS
+per-file background_install_control_manager.aconfig = file:/services/core/java/com/android/server/pm/BACKGROUND_INSTALL_OWNERS
 
 # ResourcesManager
 per-file ResourcesManager.java = file:RESOURCES_OWNERS
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 0261f0a..1ac08ac 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -179,6 +179,14 @@
     @Overridable
     public static final long BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT = 236704164L;
 
+    /**
+     * Validate options passed in as bundle.
+     * @hide
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    public static final long PENDING_INTENT_OPTIONS_CHECK = 320664730L;
+
     /** @hide */
     @IntDef(flag = true,
             value = {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d755413..397b63f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -210,6 +210,7 @@
 import android.permission.PermissionManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
+import android.provider.ContactKeysManager;
 import android.safetycenter.SafetyCenterFrameworkInitializer;
 import android.scheduling.SchedulingFrameworkInitializer;
 import android.security.FileIntegrityManager;
@@ -1604,6 +1605,18 @@
                     }
                 });
 
+        registerService(Context.CONTACT_KEYS_SERVICE, ContactKeysManager.class,
+                new CachedServiceFetcher<ContactKeysManager>() {
+                    @Override
+                    public ContactKeysManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        if (!android.provider.Flags.userKeys()) {
+                            throw new ServiceNotFoundException(
+                                    "ContactKeysManager is not supported");
+                        }
+                        return new ContactKeysManager(ctx);
+                    }});
+
         sInitializing = true;
         try {
             // Note: the following functions need to be @SystemApis, once they become mainline
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5c42b0e..86d0125 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -53,6 +53,7 @@
 import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
 import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.view.contentprotection.flags.Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
@@ -61,6 +62,7 @@
 import android.annotation.BroadcastBehavior;
 import android.annotation.CallbackExecutor;
 import android.annotation.ColorInt;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -4092,6 +4094,29 @@
         return MTE_NOT_CONTROLLED_BY_POLICY;
     }
 
+    /** Indicates that content protection is not controlled by policy, allowing user to choose. */
+    @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+    public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0;
+
+    /** Indicates that content protection is controlled and disabled by a policy. */
+    @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+    public static final int CONTENT_PROTECTION_DISABLED = 1;
+
+    /** Indicates that content protection is controlled and enabled by a policy. */
+    @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+    public static final int CONTENT_PROTECTION_ENABLED = 2;
+
+    /** @hide */
+    @IntDef(
+            prefix = {"CONTENT_PROTECTION_"},
+            value = {
+                CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY,
+                CONTENT_PROTECTION_DISABLED,
+                CONTENT_PROTECTION_ENABLED,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ContentProtectionPolicy {}
+
     /**
      * This object is a single place to tack on invalidation and disable calls.  All
      * binder caches in this class derive from this Config, so all can be invalidated or
diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig
index 029b93a..4473b95 100644
--- a/core/java/android/app/background_install_control_manager.aconfig
+++ b/core/java/android/app/background_install_control_manager.aconfig
@@ -1,7 +1,7 @@
 package: "android.app"
 
 flag {
-     namespace: "background_install_control"
+     namespace: "preload_safety"
      name: "bic_client"
      description: "System API for background install control."
      is_fixed_read_only: true
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index ec181da..1f19f81 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -907,7 +907,10 @@
 
     private InteractionHandler getHandler(InteractionHandler handler) {
         return (view, pendingIntent, response) -> {
-            AppWidgetManager.getInstance(mContext).noteAppWidgetTapped(mAppWidgetId);
+            AppWidgetManager manager = AppWidgetManager.getInstance(mContext);
+            if (manager != null) {
+                manager.noteAppWidgetTapped(mAppWidgetId);
+            }
             if (handler != null) {
                 return handler.onInteraction(view, pendingIntent, response);
             } else {
diff --git a/core/java/android/companion/virtual/camera/VirtualCameraConfig.java b/core/java/android/companion/virtual/camera/VirtualCameraConfig.java
index 350cf3d..06a0f5c 100644
--- a/core/java/android/companion/virtual/camera/VirtualCameraConfig.java
+++ b/core/java/android/companion/virtual/camera/VirtualCameraConfig.java
@@ -196,13 +196,12 @@
      * <li>At least one stream must be added with {@link #addStreamConfig(int, int, int, int)}.
      * <li>A callback must be set with {@link #setVirtualCameraCallback(Executor,
      *     VirtualCameraCallback)}
-     * <li>A camera name must be set with {@link #setName(String)}
      * <li>A lens facing must be set with {@link #setLensFacing(int)}
      */
     @FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA)
     public static final class Builder {
 
-        private String mName;
+        private final String mName;
         private final ArraySet<VirtualCameraStreamConfig> mStreamConfigurations = new ArraySet<>();
         private Executor mCallbackExecutor;
         private VirtualCameraCallback mCallback;
@@ -210,12 +209,12 @@
         private int mLensFacing = LENS_FACING_UNKNOWN;
 
         /**
-         * Sets the name of the virtual camera instance.
+         * Creates a new instance of {@link Builder}.
+         *
+         * @param name The name of the {@link VirtualCamera}.
          */
-        @NonNull
-        public Builder setName(@NonNull String name) {
-            mName = requireNonNull(name, "Display name cannot be null");
-            return this;
+        public Builder(@NonNull String name) {
+            mName = requireNonNull(name, "Name cannot be null");
         }
 
         /**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 67a3627..b8d7543 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3657,8 +3657,8 @@
      * On Android {@link android.os.Build.VERSION_CODES#S} and later,
      * if the application is in a state where the service
      * can not be started (such as not in the foreground in a state when services are allowed),
-     * {@link android.app.BackgroundServiceStartNotAllowedException} is thrown
-     * This excemption extends {@link IllegalStateException}, so apps can
+     * {@link android.app.BackgroundServiceStartNotAllowedException} is thrown.
+     * This exception extends {@link IllegalStateException}, so apps can
      * use {@code catch (IllegalStateException)} to catch both.
      *
      * @see #startForegroundService(Intent)
@@ -4243,6 +4243,7 @@
             GRAMMATICAL_INFLECTION_SERVICE,
             SECURITY_STATE_SERVICE,
            //@hide: ECM_ENHANCED_CONFIRMATION_SERVICE,
+            CONTACT_KEYS_SERVICE,
 
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -6542,6 +6543,16 @@
     public static final String ECM_ENHANCED_CONFIRMATION_SERVICE = "ecm_enhanced_confirmation";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.provider.ContactKeysManager} to managing contact keys.
+     *
+     * @see #getSystemService(String)
+     * @see android.provider.ContactKeysManager
+     */
+    @FlaggedApi(android.provider.Flags.FLAG_USER_KEYS)
+    public static final String CONTACT_KEYS_SERVICE = "contact_keys";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index ad3acd7..79af65a 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -16,11 +16,13 @@
 
 package android.content;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.pm.Flags;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -175,6 +177,7 @@
     private static final String ACTION_STR = "action";
     private static final String AUTO_VERIFY_STR = "autoVerify";
     private static final String EXTRAS_STR = "extras";
+    private static final String URI_RELATIVE_FILTER_GROUP_STR = "uriRelativeFilterGroup";
 
     private static final int[] EMPTY_INT_ARRAY = new int[0];
     private static final long[] EMPTY_LONG_ARRAY = new long[0];
@@ -324,6 +327,7 @@
     private ArrayList<PatternMatcher> mDataSchemeSpecificParts = null;
     private ArrayList<AuthorityEntry> mDataAuthorities = null;
     private ArrayList<PatternMatcher> mDataPaths = null;
+    private ArrayList<UriRelativeFilterGroup> mUriRelativeFilterGroups = null;
     private ArrayList<String> mStaticDataTypes = null;
     private ArrayList<String> mDataTypes = null;
     private ArrayList<String> mMimeGroups = null;
@@ -520,6 +524,10 @@
         if (o.mDataPaths != null) {
             mDataPaths = new ArrayList<PatternMatcher>(o.mDataPaths);
         }
+        if (o.mUriRelativeFilterGroups != null) {
+            mUriRelativeFilterGroups =
+                    new ArrayList<UriRelativeFilterGroup>(o.mUriRelativeFilterGroups);
+        }
         if (o.mMimeGroups != null) {
             mMimeGroups = new ArrayList<String>(o.mMimeGroups);
         }
@@ -1563,6 +1571,63 @@
     }
 
     /**
+     * Add a new URI relative filter group to match against the Intent data.  The
+     * intent filter must include one or more schemes (via {@link #addDataScheme})
+     * <em>and</em> one or more authorities (via {@link #addDataAuthority}) for
+     * the group to be considered.
+     *
+     * <p>Groups will be matched in the order they were added and matching will only
+     * be done if no data paths match or if none are included. If both data paths and
+     * groups are not included, then only the scheme/authority must match.</p>
+     *
+     * @param group A {@link UriRelativeFilterGroup} to match the URI.
+     *
+     * @see UriRelativeFilterGroup
+     * @see #matchData
+     * @see #addDataScheme
+     * @see #addDataAuthority
+     */
+    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+    public final void addUriRelativeFilterGroup(@NonNull UriRelativeFilterGroup group) {
+        Objects.requireNonNull(group);
+        if (mUriRelativeFilterGroups == null) {
+            mUriRelativeFilterGroups = new ArrayList<>();
+        }
+        mUriRelativeFilterGroups.add(group);
+    }
+
+    /**
+     * Return the number of URI relative filter groups in the intent filter.
+     */
+    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+    public final int countUriRelativeFilterGroups() {
+        return mUriRelativeFilterGroups == null ? 0 : mUriRelativeFilterGroups.size();
+    }
+
+    /**
+     * Return a URI relative filter group in the intent filter.
+     *
+     * <p>Note: use of this method will result in a NullPointerException
+     * if no groups exists for this intent filter.</p>
+     *
+     * @param index index of the element to return
+     * @throws IndexOutOfBoundsException if index is out of range
+     */
+    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+    @NonNull
+    public final UriRelativeFilterGroup getUriRelativeFilterGroup(int index) {
+        return mUriRelativeFilterGroups.get(index);
+    }
+
+    /**
+     * Removes all existing URI relative filter groups in the intent filter.
+     */
+    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+    public final void clearUriRelativeFilterGroups() {
+        mUriRelativeFilterGroups = null;
+    }
+
+    /**
      * Match this intent filter against the given Intent data.  This ignores
      * the data scheme -- unlike {@link #matchData}, the authority will match
      * regardless of whether there is a matching scheme.
@@ -1677,12 +1742,24 @@
                     int authMatch = matchDataAuthority(data, wildcardSupported);
                     if (authMatch >= 0) {
                         final ArrayList<PatternMatcher> paths = mDataPaths;
-                        if (paths == null) {
-                            match = authMatch;
-                        } else if (hasDataPath(data.getPath(), wildcardSupported)) {
-                            match = MATCH_CATEGORY_PATH;
+                        final ArrayList<UriRelativeFilterGroup> groups = mUriRelativeFilterGroups;
+                        if (Flags.relativeReferenceIntentFilters()) {
+                            if (paths == null && groups == null) {
+                                match = authMatch;
+                            } else if (hasDataPath(data.getPath(), wildcardSupported)
+                                    || matchRelRefGroups(data)) {
+                                match = MATCH_CATEGORY_PATH;
+                            } else {
+                                return NO_MATCH_DATA;
+                            }
                         } else {
-                            return NO_MATCH_DATA;
+                            if (paths == null) {
+                                match = authMatch;
+                            } else if (hasDataPath(data.getPath(), wildcardSupported)) {
+                                match = MATCH_CATEGORY_PATH;
+                            } else {
+                                return NO_MATCH_DATA;
+                            }
                         }
                     } else {
                         return NO_MATCH_DATA;
@@ -1726,6 +1803,19 @@
         return match + MATCH_ADJUSTMENT_NORMAL;
     }
 
+    private boolean matchRelRefGroups(Uri data) {
+        if (mUriRelativeFilterGroups == null) {
+            return false;
+        }
+        for (int i = 0; i < mUriRelativeFilterGroups.size(); i++) {
+            UriRelativeFilterGroup group = mUriRelativeFilterGroups.get(i);
+            if (group.matchData(data)) {
+                return group.getAction() == UriRelativeFilterGroup.ACTION_ALLOW;
+            }
+        }
+        return false;
+    }
+
     /**
      * Add a new Intent category to match against.  The semantics of
      * categories is the opposite of actions -- an Intent includes the
@@ -2486,6 +2576,12 @@
             }
             serializer.endTag(null, EXTRAS_STR);
         }
+        if (Flags.relativeReferenceIntentFilters()) {
+            N = countUriRelativeFilterGroups();
+            for (int i = 0; i < N; i++) {
+                mUriRelativeFilterGroups.get(i).writeToXml(serializer);
+            }
+        }
     }
 
     /**
@@ -2614,6 +2710,9 @@
                 }
             } else if (tagName.equals(EXTRAS_STR)) {
                 mExtras = PersistableBundle.restoreFromXml(parser);
+            } else if (Flags.relativeReferenceIntentFilters()
+                    && URI_RELATIVE_FILTER_GROUP_STR.equals(tagName)) {
+                addUriRelativeFilterGroup(new UriRelativeFilterGroup(parser));
             } else {
                 Log.w("IntentFilter", "Unknown tag parsing IntentFilter: " + tagName);
             }
@@ -2680,6 +2779,12 @@
         if (mExtras != null) {
             mExtras.dumpDebug(proto, IntentFilterProto.EXTRAS);
         }
+        if (Flags.relativeReferenceIntentFilters() && mUriRelativeFilterGroups != null) {
+            Iterator<UriRelativeFilterGroup> it = mUriRelativeFilterGroups.iterator();
+            while (it.hasNext()) {
+                it.next().dumpDebug(proto, IntentFilterProto.URI_RELATIVE_FILTER_GROUPS);
+            }
+        }
         proto.end(token);
     }
 
@@ -2744,6 +2849,15 @@
                 du.println(sb.toString());
             }
         }
+        if (mUriRelativeFilterGroups != null) {
+            Iterator<UriRelativeFilterGroup> it = mUriRelativeFilterGroups.iterator();
+            while (it.hasNext()) {
+                sb.setLength(0);
+                sb.append(prefix); sb.append("UriRelativeFilterGroup: \"");
+                sb.append(it.next()); sb.append("\"");
+                du.println(sb.toString());
+            }
+        }
         if (mStaticDataTypes != null) {
             Iterator<String> it = mStaticDataTypes.iterator();
             while (it.hasNext()) {
@@ -2883,6 +2997,15 @@
         } else {
             dest.writeInt(0);
         }
+        if (Flags.relativeReferenceIntentFilters() && mUriRelativeFilterGroups != null) {
+            final int N = mUriRelativeFilterGroups.size();
+            dest.writeInt(N);
+            for (int i = 0; i < N; i++) {
+                mUriRelativeFilterGroups.get(i).writeToParcel(dest, flags);
+            }
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /**
@@ -2989,6 +3112,13 @@
         if (source.readInt() != 0) {
             mExtras = PersistableBundle.CREATOR.createFromParcel(source);
         }
+        N = source.readInt();
+        if (Flags.relativeReferenceIntentFilters() && N > 0) {
+            mUriRelativeFilterGroups = new ArrayList<UriRelativeFilterGroup>(N);
+            for (int i = 0; i < N; i++) {
+                mUriRelativeFilterGroups.add(new UriRelativeFilterGroup(source));
+            }
+        }
     }
 
     private boolean hasPartialTypes() {
diff --git a/core/java/android/content/UriRelativeFilter.java b/core/java/android/content/UriRelativeFilter.java
new file mode 100644
index 0000000..9866cd0
--- /dev/null
+++ b/core/java/android/content/UriRelativeFilter.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.Flags;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.util.proto.ProtoOutputStream;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A filter for matching Intent URI Data as part of a
+ * {@link UriRelativeFilterGroup}. A single filter can only be
+ * matched against either a URI path, query or fragment
+ */
+@FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+public final class UriRelativeFilter {
+    private static final String FILTER_STR = "filter";
+    private static final String PART_STR = "part";
+    private static final String PATTERN_STR = "pattern";
+    static final String URI_RELATIVE_FILTER_STR = "uriRelativeFilter";
+
+    /**
+     * Value to indicate that the filter is to be applied to a URI path.
+     */
+    public static final int PATH = 0;
+    /**
+     * Value to indicate that the filter is to be applied to a URI query.
+     */
+    public static final int QUERY = 1;
+    /**
+     * Value to indicate that the filter is to be applied to a URI fragment.
+     */
+    public static final int FRAGMENT = 2;
+
+    /** @hide */
+    @IntDef(value = {
+            PATH,
+            QUERY,
+            FRAGMENT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UriPart {}
+
+    private final @UriPart int mUriPart;
+    private final @PatternMatcher.PatternType int mPatternType;
+    private final String mFilter;
+
+    /**
+     * Creates a new UriRelativeFilter.
+     *
+     * @param uriPart The URI part this filter operates on. Can be either a
+     *                {@link UriRelativeFilter#PATH}, {@link UriRelativeFilter#QUERY},
+     *                or {@link UriRelativeFilter#FRAGMENT}.
+     * @param patternType The pattern type of the filter. Can be either a
+     *                    {@link PatternMatcher#PATTERN_LITERAL},
+     *                    {@link PatternMatcher#PATTERN_PREFIX},
+*                         {@link PatternMatcher#PATTERN_SUFFIX},
+     *                    {@link PatternMatcher#PATTERN_SIMPLE_GLOB},
+     *                    or {@link PatternMatcher#PATTERN_ADVANCED_GLOB}.
+     * @param filter A literal or pattern string depedning on patterType
+     *               used to match a uriPart .
+     */
+    public UriRelativeFilter(
+            @UriPart int uriPart,
+            @PatternMatcher.PatternType int patternType,
+            @NonNull String filter) {
+        mUriPart = uriPart;
+        com.android.internal.util.AnnotationValidations.validate(
+                UriPart.class, null, mUriPart);
+        mPatternType = patternType;
+        com.android.internal.util.AnnotationValidations.validate(
+                PatternMatcher.PatternType.class, null, mPatternType);
+        mFilter = filter;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFilter);
+    }
+
+    /**
+     * The URI part this filter operates on.
+     */
+    public @UriPart int getUriPart() {
+        return mUriPart;
+    }
+
+    /**
+     * The pattern type of the filter.
+     */
+    public @PatternMatcher.PatternType int getPatternType() {
+        return mPatternType;
+    }
+
+    /**
+     * The string used to filter the URI.
+     */
+    public @NonNull String getFilter() {
+        return mFilter;
+    }
+
+    /**
+     * Match this URI filter against an Intent's data. QUERY filters can
+     * match against any key value pair in the query string. PATH and
+     * FRAGMENT filters must match the entire string.
+     *
+     * @param data The full data string to match against, as supplied in
+     *             Intent.data.
+     *
+     * @return true if there is a match.
+     */
+    public boolean matchData(@NonNull Uri data) {
+        PatternMatcher pe = new PatternMatcher(mFilter, mPatternType);
+        switch (getUriPart()) {
+            case PATH:
+                return pe.match(data.getPath());
+            case QUERY:
+                return matchQuery(pe, data.getQuery());
+            case FRAGMENT:
+                return pe.match(data.getFragment());
+            default:
+                return false;
+        }
+    }
+
+    private boolean matchQuery(PatternMatcher pe, String query) {
+        if (query != null) {
+            String[] params = query.split("&");
+            if (params.length == 1) {
+                params = query.split(";");
+            }
+            for (int i = 0; i < params.length; i++) {
+                if (pe.match(params[i])) return true;
+            }
+        }
+        return false;
+    }
+
+    /** @hide */
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        proto.write(UriRelativeFilterProto.URI_PART, mUriPart);
+        proto.write(UriRelativeFilterProto.PATTERN_TYPE, mPatternType);
+        proto.write(UriRelativeFilterProto.FILTER, mFilter);
+        proto.end(token);
+    }
+
+    /** @hide */
+    public void writeToXml(XmlSerializer serializer) throws IOException {
+        serializer.startTag(null, URI_RELATIVE_FILTER_STR);
+        serializer.attribute(null, PATTERN_STR, Integer.toString(mPatternType));
+        serializer.attribute(null, PART_STR, Integer.toString(mUriPart));
+        serializer.attribute(null, FILTER_STR, mFilter);
+        serializer.endTag(null, URI_RELATIVE_FILTER_STR);
+    }
+
+    private String uriPartToString() {
+        switch (mUriPart) {
+            case PATH:
+                return "PATH";
+            case QUERY:
+                return "QUERY";
+            case FRAGMENT:
+                return "FRAGMENT";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    private String patternTypeToString() {
+        switch (mPatternType) {
+            case PatternMatcher.PATTERN_LITERAL:
+                return "LITERAL";
+            case PatternMatcher.PATTERN_PREFIX:
+                return "PREFIX";
+            case PatternMatcher.PATTERN_SIMPLE_GLOB:
+                return "GLOB";
+            case PatternMatcher.PATTERN_ADVANCED_GLOB:
+                return "ADVANCED_GLOB";
+            case PatternMatcher.PATTERN_SUFFIX:
+                return "SUFFIX";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "UriRelativeFilter { "
+                + "uriPart = " + uriPartToString() + ", "
+                + "patternType = " + patternTypeToString() + ", "
+                + "filter = " + mFilter
+                + " }";
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        UriRelativeFilter that = (UriRelativeFilter) o;
+        return mUriPart == that.mUriPart
+                && mPatternType == that.mPatternType
+                && java.util.Objects.equals(mFilter, that.mFilter);
+    }
+
+    @Override
+    public int hashCode() {
+        int _hash = 1;
+        _hash = 31 * _hash + mUriPart;
+        _hash = 31 * _hash + mPatternType;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mFilter);
+        return _hash;
+    }
+
+    /** @hide */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mUriPart);
+        dest.writeInt(mPatternType);
+        dest.writeString(mFilter);
+    }
+
+    /** @hide */
+    UriRelativeFilter(@NonNull android.os.Parcel in) {
+        mUriPart = in.readInt();
+        mPatternType = in.readInt();
+        mFilter = in.readString();
+    }
+
+    /** @hide */
+    public UriRelativeFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
+        mUriPart = Integer.parseInt(parser.getAttributeValue(null, PART_STR));
+        mPatternType = Integer.parseInt(parser.getAttributeValue(null, PATTERN_STR));
+        mFilter = parser.getAttributeValue(null, FILTER_STR);
+    }
+}
diff --git a/core/java/android/content/UriRelativeFilterGroup.java b/core/java/android/content/UriRelativeFilterGroup.java
new file mode 100644
index 0000000..72c396a
--- /dev/null
+++ b/core/java/android/content/UriRelativeFilterGroup.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.pm.Flags;
+import android.net.Uri;
+import android.os.Parcel;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Objects;
+
+/**
+ * An intent data matching group based on a URI's relative reference which
+ * includes the path, query and fragment.  The group is only considered as
+ * matching if <em>all</em> UriRelativeFilters in the group match.  Each
+ * UriRelativeFilter defines a matching rule for a URI path, query or fragment.
+ * A group must contain one or more UriRelativeFilters to match but does not need to
+ * contain UriRelativeFilters for all existing parts of a URI to match.
+ *
+ * <p>For example, given a URI that contains path, query and fragment parts,
+ * a group containing only a path filter will match the URI if the path
+ * filter matches the URI path.  If the group contains a path and query
+ * filter, then the group will only match if both path and query filters
+ * match.  If a URI contains only a path with no query or fragment then a
+ * group can only match if it contains only a matching path filter. If the
+ * group also contained additional query or fragment filters then it will
+ * not match.</p>
+ */
+@FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+public final class UriRelativeFilterGroup {
+    private static final String ALLOW_STR = "allow";
+    private static final String URI_RELATIVE_FILTER_GROUP_STR = "uriRelativeFilterGroup";
+
+    /**
+     * Value to indicate that the group match is allowed.
+     */
+    public static final int ACTION_ALLOW = 0;
+    /**
+     * Value to indicate that the group match is blocked.
+     */
+    public static final int ACTION_BLOCK = 1;
+
+    /** @hide */
+    @IntDef(value = {
+            ACTION_ALLOW,
+            ACTION_BLOCK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Action {}
+
+    private final @Action int mAction;
+    private final ArraySet<UriRelativeFilter> mUriRelativeFilters = new ArraySet<>();
+
+    /**
+     * New UriRelativeFilterGroup that matches a Intent data.
+     *
+     * @param action Whether this matching group should be allowed or disallowed.
+     */
+    public UriRelativeFilterGroup(@Action int action) {
+        mAction = action;
+    }
+
+    /** @hide */
+    public UriRelativeFilterGroup(XmlPullParser parser) throws XmlPullParserException, IOException {
+        mAction = Integer.parseInt(parser.getAttributeValue(null, ALLOW_STR));
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG
+                    || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals(UriRelativeFilter.URI_RELATIVE_FILTER_STR)) {
+                addUriRelativeFilter(new UriRelativeFilter(parser));
+            } else {
+                Log.w("IntentFilter", "Unknown tag parsing IntentFilter: " + tagName);
+            }
+            XmlUtils.skipCurrentTag(parser);
+        }
+    }
+
+    /**
+     * Return {@link UriRelativeFilterGroup#ACTION_ALLOW} if a URI is allowed when matched
+     * and {@link UriRelativeFilterGroup#ACTION_BLOCK} if a URI is blacked when matched.
+     */
+    public @Action int getAction() {
+        return mAction;
+    }
+
+    /**
+     * Add a filter to the group.
+     */
+    public void addUriRelativeFilter(@NonNull UriRelativeFilter uriRelativeFilter) {
+        Objects.requireNonNull(uriRelativeFilter);
+        if (!CollectionUtils.contains(mUriRelativeFilters, uriRelativeFilter)) {
+            mUriRelativeFilters.add(uriRelativeFilter);
+        }
+    }
+
+    /**
+     * Returns a unmodifiable view of the UriRelativeFilters list in this group.
+     */
+    @NonNull
+    public Collection<UriRelativeFilter> getUriRelativeFilters() {
+        return Collections.unmodifiableCollection(mUriRelativeFilters);
+    }
+
+    /**
+     * Match all URI filter in this group against {@link Intent#getData()}.
+     *
+     * @param data The full data string to match against, as supplied in
+     *             Intent.data.
+     * @return true if all filters match.
+     */
+    public boolean matchData(@NonNull Uri data) {
+        if (mUriRelativeFilters.size() == 0) {
+            return false;
+        }
+        for (UriRelativeFilter filter : mUriRelativeFilters) {
+            if (!filter.matchData(data)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /** @hide */
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        proto.write(UriRelativeFilterGroupProto.ACTION, mAction);
+        Iterator<UriRelativeFilter> it = mUriRelativeFilters.iterator();
+        while (it.hasNext()) {
+            it.next().dumpDebug(proto, UriRelativeFilterGroupProto.URI_RELATIVE_FILTERS);
+        }
+        proto.end(token);
+    }
+
+    /** @hide */
+    public void writeToXml(XmlSerializer serializer) throws IOException {
+        serializer.startTag(null, URI_RELATIVE_FILTER_GROUP_STR);
+        serializer.attribute(null, ALLOW_STR, Integer.toString(mAction));
+        Iterator<UriRelativeFilter> it = mUriRelativeFilters.iterator();
+        while (it.hasNext()) {
+            UriRelativeFilter filter = it.next();
+            filter.writeToXml(serializer);
+        }
+        serializer.endTag(null, URI_RELATIVE_FILTER_GROUP_STR);
+    }
+
+    @Override
+    public String toString() {
+        return "UriRelativeFilterGroup { allow = " + mAction
+                + ", uri_filters = " + mUriRelativeFilters + ",  }";
+    }
+
+    /** @hide */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mAction);
+        final int n = mUriRelativeFilters.size();
+        if (n > 0) {
+            dest.writeInt(n);
+            Iterator<UriRelativeFilter> it = mUriRelativeFilters.iterator();
+            while (it.hasNext()) {
+                it.next().writeToParcel(dest, flags);
+            }
+        } else {
+            dest.writeInt(0);
+        }
+    }
+
+    /** @hide */
+    UriRelativeFilterGroup(@NonNull Parcel src) {
+        mAction = src.readInt();
+        final int n = src.readInt();
+        for (int i = 0; i < n; i++) {
+            mUriRelativeFilters.add(new UriRelativeFilter(src));
+        }
+    }
+}
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index a97de63..62db65f 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -128,4 +128,6 @@
 
     /** Unregister a callback, so that it won't be called when LauncherApps dumps. */
     void unRegisterDumpCallback(IDumpCallback cb);
+
+    void setArchiveCompatibilityOptions(boolean enableIconOverlay, boolean enableUnarchivalConfirmation);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6dc8d47..380de96 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -840,7 +840,7 @@
 
     ArchivedPackageParcel getArchivedPackage(in String packageName, int userId);
 
-    Bitmap getArchivedAppIcon(String packageName, in UserHandle user);
+    Bitmap getArchivedAppIcon(String packageName, in UserHandle user, String callingPackageName);
 
     boolean isAppArchivable(String packageName, in UserHandle user);
 }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 1d2b1af..50be983 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1801,6 +1801,31 @@
         }
     }
 
+    /**
+     * Enable or disable different archive compatibility options of the launcher.
+     *
+     * @param enableIconOverlay Provides a cloud overlay for archived apps to ensure users are aware
+     * that a certain app is archived. True by default.
+     * Launchers might want to disable this operation if they want to provide custom user experience
+     * to differentiate archived apps.
+     * @param enableUnarchivalConfirmation If true, the user is shown a confirmation dialog when
+     * they click an archived app, which explains that the app will be downloaded and restored in
+     * the background. True by default.
+     * Launchers might want to disable this operation if they provide sufficient, alternative user
+     * guidance to highlight that an unarchival is starting and ongoing once an archived app is
+     * tapped. E.g., this could be achieved by showing the unarchival progress around the icon.
+     */
+    @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING)
+    public void setArchiveCompatibilityOptions(boolean enableIconOverlay,
+            boolean enableUnarchivalConfirmation) {
+        try {
+            mService.setArchiveCompatibilityOptions(enableIconOverlay,
+                    enableUnarchivalConfirmation);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
     /** @return position in mCallbacks for callback or -1 if not present. */
     private int findCallbackLocked(Callback callback) {
         if (callback == null) {
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index 269c6c2..1d0e2db 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -16,6 +16,9 @@
 
 package android.content.pm;
 
+import static android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES;
+
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -73,7 +76,7 @@
 
     private static final String ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY =
             "crossProfileContentSharingStrategy";
-
+    private static final String ATTR_PROFILE_API_VISIBILITY = "profileApiVisibility";
     /** Index values of each property (to indicate whether they are present in this object). */
     @IntDef(prefix = "INDEX_", value = {
             INDEX_SHOW_IN_LAUNCHER,
@@ -93,6 +96,7 @@
             INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
             INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
             INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING,
+            INDEX_PROFILE_API_VISIBILITY
     })
     @Retention(RetentionPolicy.SOURCE)
     private @interface PropertyIndex {
@@ -114,6 +118,7 @@
     private static final int INDEX_SHOW_IN_SHARING_SURFACES = 14;
     private static final int INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY = 15;
     private static final int INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING = 16;
+    private static final int INDEX_PROFILE_API_VISIBILITY = 17;
     /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
     private long mPropertiesPresent = 0;
 
@@ -450,6 +455,41 @@
     @SuppressLint("UnflaggedApi") // b/306636213
     public static final int CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT = 1;
 
+    /**
+     * Possible values for the profile visibility in public API surfaces. This indicates whether or
+     * not the information linked to the profile (userId, package names) should not be returned in
+     * API surfaces if a user is marked as hidden.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "PROFILE_API_VISIBILITY_",
+            value = {
+                    PROFILE_API_VISIBILITY_UNKNOWN,
+                    PROFILE_API_VISIBILITY_VISIBLE,
+                    PROFILE_API_VISIBILITY_HIDDEN,
+            }
+    )
+    public @interface ProfileApiVisibility {
+    }
+    /*
+    * The api visibility value for this profile user is undefined or unknown.
+     */
+    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+    public static final int PROFILE_API_VISIBILITY_UNKNOWN = -1;
+
+    /**
+     * Indicates that information about this profile user should be shown in API surfaces.
+     */
+    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+    public static final int PROFILE_API_VISIBILITY_VISIBLE = 0;
+
+    /**
+     * Indicates that information about this profile should be not be visible in API surfaces.
+     */
+    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+    public static final int PROFILE_API_VISIBILITY_HIDDEN = 1;
+
 
     /**
      * Creates a UserProperties (intended for the SystemServer) that stores a reference to the given
@@ -510,6 +550,9 @@
         setShowInQuietMode(orig.getShowInQuietMode());
         setShowInSharingSurfaces(orig.getShowInSharingSurfaces());
         setCrossProfileContentSharingStrategy(orig.getCrossProfileContentSharingStrategy());
+        if (android.multiuser.Flags.supportHidingProfiles()) {
+            setProfileApiVisibility(orig.getProfileApiVisibility());
+        }
     }
 
     /**
@@ -951,9 +994,31 @@
     }
     private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy;
 
+    /**
+     * Returns the visibility of the profile user in API surfaces. Any information linked to the
+     * profile (userId, package names) should be hidden API surfaces if a user is marked as hidden.
+     */
+    @NonNull
+    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+    public @ProfileApiVisibility int getProfileApiVisibility() {
+        if (isPresent(INDEX_PROFILE_API_VISIBILITY)) return mProfileApiVisibility;
+        if (mDefaultProperties != null) return mDefaultProperties.mProfileApiVisibility;
+        throw new SecurityException("You don't have permission to query profileApiVisibility");
+    }
+    /** @hide */
+    @NonNull
+    @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+    public void setProfileApiVisibility(@ProfileApiVisibility int profileApiVisibility) {
+        this.mProfileApiVisibility = profileApiVisibility;
+        setPresent(INDEX_PROFILE_API_VISIBILITY);
+    }
+    private @ProfileApiVisibility int mProfileApiVisibility;
 
     @Override
     public String toString() {
+        String profileApiVisibility =
+                android.multiuser.Flags.supportHidingProfiles() ? ", mProfileApiVisibility="
+                        + getProfileApiVisibility() : "";
         // Please print in increasing order of PropertyIndex.
         return "UserProperties{"
                 + "mPropertiesPresent=" + Long.toBinaryString(mPropertiesPresent)
@@ -977,6 +1042,7 @@
                 + ", mDeleteAppWithParent=" + getDeleteAppWithParent()
                 + ", mAlwaysVisible=" + getAlwaysVisible()
                 + ", mCrossProfileContentSharingStrategy=" + getCrossProfileContentSharingStrategy()
+                + profileApiVisibility
                 + "}";
     }
 
@@ -1010,6 +1076,9 @@
         pw.println(prefix + "    mAlwaysVisible=" + getAlwaysVisible());
         pw.println(prefix + "    mCrossProfileContentSharingStrategy="
                 + getCrossProfileContentSharingStrategy());
+        if (android.multiuser.Flags.supportHidingProfiles()) {
+            pw.println(prefix + "    mProfileApiVisibility=" + getProfileApiVisibility());
+        }
     }
 
     /**
@@ -1093,6 +1162,12 @@
                     break;
                 case ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY:
                     setCrossProfileContentSharingStrategy(parser.getAttributeInt(i));
+                    break;
+                case ATTR_PROFILE_API_VISIBILITY:
+                    if (android.multiuser.Flags.supportHidingProfiles()) {
+                        setProfileApiVisibility(parser.getAttributeInt(i));
+                    }
+                    break;
                 default:
                     Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
             }
@@ -1175,6 +1250,12 @@
             serializer.attributeInt(null, ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
                     mCrossProfileContentSharingStrategy);
         }
+        if (isPresent(INDEX_PROFILE_API_VISIBILITY)) {
+            if (android.multiuser.Flags.supportHidingProfiles()) {
+                serializer.attributeInt(null, ATTR_PROFILE_API_VISIBILITY,
+                        mProfileApiVisibility);
+            }
+        }
     }
 
     // For use only with an object that has already had any permission-lacking fields stripped out.
@@ -1198,6 +1279,7 @@
         dest.writeBoolean(mDeleteAppWithParent);
         dest.writeBoolean(mAlwaysVisible);
         dest.writeInt(mCrossProfileContentSharingStrategy);
+        dest.writeInt(mProfileApiVisibility);
     }
 
     /**
@@ -1225,6 +1307,7 @@
         mDeleteAppWithParent = source.readBoolean();
         mAlwaysVisible = source.readBoolean();
         mCrossProfileContentSharingStrategy = source.readInt();
+        mProfileApiVisibility = source.readInt();
     }
 
     @Override
@@ -1274,6 +1357,7 @@
         private boolean mAlwaysVisible = false;
         private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy =
                 CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION;
+        private @ProfileApiVisibility int mProfileApiVisibility = 0;
 
         /**
          * @hide
@@ -1428,6 +1512,17 @@
             return this;
         }
 
+        /**
+         * Sets the value for {@link #mProfileApiVisibility}
+         * @hide
+         */
+        @NonNull
+        @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+        public Builder setProfileApiVisibility(@ProfileApiVisibility int profileApiVisibility){
+            mProfileApiVisibility = profileApiVisibility;
+            return this;
+        }
+
         /** Builds a UserProperties object with *all* values populated.
          * @hide
          */
@@ -1452,7 +1547,8 @@
                     mAllowStoppingUserWithDelayedLocking,
                     mDeleteAppWithParent,
                     mAlwaysVisible,
-                    mCrossProfileContentSharingStrategy);
+                    mCrossProfileContentSharingStrategy,
+                    mProfileApiVisibility);
         }
     } // end Builder
 
@@ -1473,7 +1569,8 @@
             boolean allowStoppingUserWithDelayedLocking,
             boolean deleteAppWithParent,
             boolean alwaysVisible,
-            @CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy) {
+            @CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy,
+            @ProfileApiVisibility int profileApiVisibility) {
         mDefaultProperties = null;
         setShowInLauncher(showInLauncher);
         setStartWithParent(startWithParent);
@@ -1493,5 +1590,8 @@
         setDeleteAppWithParent(deleteAppWithParent);
         setAlwaysVisible(alwaysVisible);
         setCrossProfileContentSharingStrategy(crossProfileContentSharingStrategy);
+        if (android.multiuser.Flags.supportHidingProfiles()) {
+            setProfileApiVisibility(profileApiVisibility);
+        }
     }
 }
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 903875b..caff457 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -110,6 +110,14 @@
 }
 
 flag {
+    name: "relative_reference_intent_filters"
+    namespace: "package_manager_service"
+    description: "Feature flag to enable relative reference intent filters"
+    bug: "307556883"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "fix_duplicated_flags"
     namespace: "package_manager_service"
     description: "Feature flag to fix duplicated PackageManager flag values"
@@ -161,3 +169,17 @@
     bug: "321258605"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "allow_sdk_sandbox_query_intent_activities"
+    namespace: "package_manager_service"
+    description: "Feature flag to allow the sandbox SDK to query intent activities of the client app."
+    bug: "295842134"
+}
+
+flag {
+    name: "emergency_install_permission"
+    namespace: "permissions"
+    description: "Feature flag to enable permission EMERGENCY_INSTALL_PACKAGES"
+    bug: "321080601"
+}
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 9644d80..efb8607 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -85,6 +85,7 @@
     description: "Enable auto-locking private space on device restarts"
     bug: "296993385"
 }
+
 flag {
     name: "enable_system_user_only_for_services_and_providers"
     namespace: "multiuser"
@@ -92,3 +93,18 @@
     bug: "302354856"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "allow_private_profile_apis"
+    namespace: "profile_experiences"
+    description: "Enable only the API changes to support private space"
+    bug: "299069460"
+}
+
+flag {
+    name: "support_hiding_profiles"
+    namespace: "profile_experiences"
+    description: "Allow the use of a hide_profile property to hide some profiles behind a permission"
+    bug: "316362775"
+    is_fixed_read_only: true
+}
diff --git a/core/java/android/content/res/Element.java b/core/java/android/content/res/Element.java
index 89f4985..6ff96f4 100644
--- a/core/java/android/content/res/Element.java
+++ b/core/java/android/content/res/Element.java
@@ -93,6 +93,7 @@
     protected static final String TAG_SUPPORTS_GL_TEXTURE = "supports-gl-texture";
     protected static final String TAG_SUPPORTS_INPUT = "supports-input";
     protected static final String TAG_SUPPORTS_SCREENS = "supports-screens";
+    protected static final String TAG_URI_RELATIVE_FILTER_GROUP = "uri-relative-filter-group";
     protected static final String TAG_USES_CONFIGURATION = "uses-configuration";
     protected static final String TAG_USES_FEATURE = "uses-feature";
     protected static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
@@ -106,6 +107,11 @@
 
     protected static final String TAG_ATTR_BACKUP_AGENT = "backupAgent";
     protected static final String TAG_ATTR_CATEGORY = "category";
+    protected static final String TAG_ATTR_FRAGMENT = "fragment";
+    protected static final String TAG_ATTR_FRAGMENT_ADVANCED_PATTERN = "fragmentAdvancedPattern";
+    protected static final String TAG_ATTR_FRAGMENT_PATTERN = "fragmentPattern";
+    protected static final String TAG_ATTR_FRAGMENT_PREFIX = "fragmentPrefix";
+    protected static final String TAG_ATTR_FRAGMENT_SUFFIX = "fragmentSuffix";
     protected static final String TAG_ATTR_HOST = "host";
     protected static final String TAG_ATTR_MANAGE_SPACE_ACTIVITY = "manageSpaceActivity";
     protected static final String TAG_ATTR_MIMETYPE = "mimeType";
@@ -122,6 +128,11 @@
     protected static final String TAG_ATTR_PERMISSION_GROUP = "permissionGroup";
     protected static final String TAG_ATTR_PORT = "port";
     protected static final String TAG_ATTR_PROCESS = "process";
+    protected static final String TAG_ATTR_QUERY = "query";
+    protected static final String TAG_ATTR_QUERY_ADVANCED_PATTERN = "queryAdvancedPattern";
+    protected static final String TAG_ATTR_QUERY_PATTERN = "queryPattern";
+    protected static final String TAG_ATTR_QUERY_PREFIX = "queryPrefix";
+    protected static final String TAG_ATTR_QUERY_SUFFIX = "querySuffix";
     protected static final String TAG_ATTR_READ_PERMISSION = "readPermission";
     protected static final String TAG_ATTR_REQUIRED_ACCOUNT_TYPE = "requiredAccountType";
     protected static final String TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_NAME =
@@ -143,7 +154,7 @@
 
     // The length of mTagCounters corresponds to the number of tags defined in getCounterIdx. If new
     // tags are added then the size here should be increased to match.
-    private final TagCounter[] mTagCounters = new TagCounter[34];
+    private final TagCounter[] mTagCounters = new TagCounter[35];
 
     String mTag;
 
@@ -238,9 +249,11 @@
                 return 31;
             case TAG_INTENT:
                 return 32;
+            case TAG_URI_RELATIVE_FILTER_GROUP:
+                return 33;
             default:
                 // The size of the mTagCounters array should be equal to this value+1
-                return 33;
+                return 34;
         }
     }
 
@@ -276,6 +289,7 @@
             case TAG_SERVICE:
             case TAG_SUPPORTS_GL_TEXTURE:
             case TAG_SUPPORTS_SCREENS:
+            case TAG_URI_RELATIVE_FILTER_GROUP:
             case TAG_USES_CONFIGURATION:
             case TAG_USES_FEATURE:
             case TAG_USES_LIBRARY:
@@ -322,6 +336,7 @@
                 break;
             case TAG_INTENT:
             case TAG_INTENT_FILTER:
+                initializeCounter(TAG_URI_RELATIVE_FILTER_GROUP, 100);
                 initializeCounter(TAG_ACTION, 20000);
                 initializeCounter(TAG_CATEGORY, 40000);
                 initializeCounter(TAG_DATA, 40000);
@@ -354,6 +369,9 @@
                 initializeCounter(TAG_INTENT, 2000);
                 initializeCounter(TAG_PROVIDER, 8000);
                 break;
+            case TAG_URI_RELATIVE_FILTER_GROUP:
+                initializeCounter(TAG_DATA, 100);
+                break;
         }
     }
 
@@ -391,11 +409,21 @@
             case TAG_ATTR_VERSION_NAME:
             case TAG_ATTR_ZYGOTE_PRELOAD_NAME:
                 return MAX_ATTR_LEN_NAME;
+            case TAG_ATTR_FRAGMENT:
+            case TAG_ATTR_FRAGMENT_ADVANCED_PATTERN:
+            case TAG_ATTR_FRAGMENT_PATTERN:
+            case TAG_ATTR_FRAGMENT_PREFIX:
+            case TAG_ATTR_FRAGMENT_SUFFIX:
             case TAG_ATTR_PATH:
             case TAG_ATTR_PATH_ADVANCED_PATTERN:
             case TAG_ATTR_PATH_PATTERN:
             case TAG_ATTR_PATH_PREFIX:
             case TAG_ATTR_PATH_SUFFIX:
+            case TAG_ATTR_QUERY:
+            case TAG_ATTR_QUERY_ADVANCED_PATTERN:
+            case TAG_ATTR_QUERY_PATTERN:
+            case TAG_ATTR_QUERY_PREFIX:
+            case TAG_ATTR_QUERY_SUFFIX:
                 return MAX_ATTR_LEN_PATH;
             case TAG_ATTR_VALUE:
                 return MAX_ATTR_LEN_VALUE;
@@ -535,6 +563,16 @@
             case R.styleable.AndroidManifestData_pathPrefix:
             case R.styleable.AndroidManifestData_pathSuffix:
             case R.styleable.AndroidManifestData_pathAdvancedPattern:
+            case R.styleable.AndroidManifestData_query:
+            case R.styleable.AndroidManifestData_queryPattern:
+            case R.styleable.AndroidManifestData_queryPrefix:
+            case R.styleable.AndroidManifestData_querySuffix:
+            case R.styleable.AndroidManifestData_queryAdvancedPattern:
+            case R.styleable.AndroidManifestData_fragment:
+            case R.styleable.AndroidManifestData_fragmentPattern:
+            case R.styleable.AndroidManifestData_fragmentPrefix:
+            case R.styleable.AndroidManifestData_fragmentSuffix:
+            case R.styleable.AndroidManifestData_fragmentAdvancedPattern:
                 return MAX_ATTR_LEN_PATH;
             default:
                 return DEFAULT_MAX_STRING_ATTR_LENGTH;
diff --git a/core/java/android/content/res/FontScaleConverterFactory.java b/core/java/android/content/res/FontScaleConverterFactory.java
index cbe4c62..625d7cb 100644
--- a/core/java/android/content/res/FontScaleConverterFactory.java
+++ b/core/java/android/content/res/FontScaleConverterFactory.java
@@ -58,6 +58,16 @@
         synchronized (LOOKUP_TABLES_WRITE_LOCK) {
             putInto(
                     sLookupTables,
+                    /* scaleKey= */ 1.1f,
+                    new FontScaleConverterImpl(
+                            /* fromSp= */
+                            new float[] {   8f,   10f,   12f,   14f,   18f,   20f,   24f,   30f,  100},
+                            /* toDp=   */
+                            new float[] { 8.8f,   11f, 13.2f, 15.6f, 19.2f, 21.2f, 24.8f,   30f,  100})
+            );
+
+            putInto(
+                    sLookupTables,
                     /* scaleKey= */ 1.15f,
                     new FontScaleConverterImpl(
                             /* fromSp= */
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java
index 530fead..73361ad 100644
--- a/core/java/android/credentials/GetCandidateCredentialsResponse.java
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java
@@ -19,7 +19,7 @@
 import android.annotation.Hide;
 import android.annotation.NonNull;
 import android.app.PendingIntent;
-import android.credentials.ui.GetCredentialProviderData;
+import android.credentials.selection.GetCredentialProviderData;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/credentials/ui/AuthenticationEntry.java b/core/java/android/credentials/selection/AuthenticationEntry.java
similarity index 96%
rename from core/java/android/credentials/ui/AuthenticationEntry.java
rename to core/java/android/credentials/selection/AuthenticationEntry.java
index 9bd0871..54589e1 100644
--- a/core/java/android/credentials/ui/AuthenticationEntry.java
+++ b/core/java/android/credentials/selection/AuthenticationEntry.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -41,6 +44,7 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class AuthenticationEntry implements Parcelable {
     @NonNull
     private final String mKey;
diff --git a/core/java/android/credentials/ui/BaseDialogResult.java b/core/java/android/credentials/selection/BaseDialogResult.java
similarity index 81%
rename from core/java/android/credentials/ui/BaseDialogResult.java
rename to core/java/android/credentials/selection/BaseDialogResult.java
index e985a46..d4a73c3 100644
--- a/core/java/android/credentials/ui/BaseDialogResult.java
+++ b/core/java/android/credentials/selection/BaseDialogResult.java
@@ -14,11 +14,16 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -35,6 +40,10 @@
  *
  * @hide
  */
+@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
+@SuppressLint("ParcelNotFinal") // Test API only. This is never intended to be officially exposed.
+// Instead proper final wrapper classes are defined (e.g. {@code FailureDialogResult}).
 public class BaseDialogResult implements Parcelable {
     /** Parses and returns a BaseDialogResult from the given resultData. */
     @Nullable
@@ -54,7 +63,8 @@
      * The intent extra key for the {@code BaseDialogResult} object when the credential
      * selector activity finishes.
      */
-    private static final String EXTRA_BASE_RESULT = "android.credentials.ui.extra.BASE_RESULT";
+    private static final String EXTRA_BASE_RESULT =
+            "android.credentials.selection.extra.BASE_RESULT";
 
     /** @hide **/
     @IntDef(prefix = {"RESULT_CODE_"}, value = {
@@ -92,13 +102,19 @@
         mRequestToken = requestToken;
     }
 
-    /** Returns the unique identifier for the request that launched the operation. */
+    /**
+     * Returns the unique identifier for the request that launched the operation.
+     *
+     * @deprecated do not use
+     */
     @Nullable
     @Deprecated
     public IBinder getRequestToken() {
         return mRequestToken;
     }
 
+    @SuppressLint("ParcelConstructor") // Test API only. This is never intended to be officially
+    // exposed. Instead proper final wrapper classes are defined (e.g. {@code FailureDialogResult}).
     protected BaseDialogResult(@NonNull Parcel in) {
         IBinder requestToken = in.readStrongBinder();
         mRequestToken = requestToken;
diff --git a/core/java/android/credentials/ui/CancelUiRequest.java b/core/java/android/credentials/selection/CancelUiRequest.java
similarity index 96%
rename from core/java/android/credentials/ui/CancelUiRequest.java
rename to core/java/android/credentials/selection/CancelUiRequest.java
index 712424ce..fca0e2a 100644
--- a/core/java/android/credentials/ui/CancelUiRequest.java
+++ b/core/java/android/credentials/selection/CancelUiRequest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
 import android.annotation.NonNull;
 import android.os.IBinder;
@@ -38,7 +38,7 @@
      */
     @NonNull
     public static final String EXTRA_CANCEL_UI_REQUEST =
-            "android.credentials.ui.extra.CANCEL_UI_REQUEST";
+            "android.credentials.selection.extra.CANCEL_UI_REQUEST";
 
     @NonNull
     private final IBinder mToken;
diff --git a/core/java/android/credentials/ui/Constants.java b/core/java/android/credentials/selection/Constants.java
similarity index 86%
rename from core/java/android/credentials/ui/Constants.java
rename to core/java/android/credentials/selection/Constants.java
index 68f28e7..7e6c781 100644
--- a/core/java/android/credentials/ui/Constants.java
+++ b/core/java/android/credentials/selection/Constants.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
 /**
  * Constants for the ui protocol that doesn't fit into other individual data structures.
@@ -27,14 +27,14 @@
      * The intent extra key for the {@code ResultReceiver} object when launching the UX activities.
      */
     public static final String EXTRA_RESULT_RECEIVER =
-            "android.credentials.ui.extra.RESULT_RECEIVER";
+            "android.credentials.selection.extra.RESULT_RECEIVER";
 
     /**
      * The intent extra key for indicating whether the bottom sheet should be started directly
      * on the 'All Options' screen.
      */
     public static final String EXTRA_REQ_FOR_ALL_OPTIONS =
-            "android.credentials.ui.extra.REQ_FOR_ALL_OPTIONS";
+            "android.credentials.selection.extra.REQ_FOR_ALL_OPTIONS";
 
     private Constants() {}
 }
diff --git a/core/java/android/credentials/ui/CreateCredentialProviderData.java b/core/java/android/credentials/selection/CreateCredentialProviderData.java
similarity index 94%
rename from core/java/android/credentials/ui/CreateCredentialProviderData.java
rename to core/java/android/credentials/selection/CreateCredentialProviderData.java
index d7a4f5b..fc80ea8 100644
--- a/core/java/android/credentials/ui/CreateCredentialProviderData.java
+++ b/core/java/android/credentials/selection/CreateCredentialProviderData.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -33,6 +36,7 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class CreateCredentialProviderData extends ProviderData implements Parcelable {
     @NonNull
     private final List<Entry> mSaveEntries;
@@ -112,6 +116,7 @@
      * @hide
      */
     @TestApi
+    @FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
     public static final class Builder {
         @NonNull private String mProviderFlattenedComponentName;
         @NonNull private List<Entry> mSaveEntries = new ArrayList<>();
diff --git a/core/java/android/credentials/ui/CreateCredentialProviderInfo.java b/core/java/android/credentials/selection/CreateCredentialProviderInfo.java
similarity index 98%
rename from core/java/android/credentials/ui/CreateCredentialProviderInfo.java
rename to core/java/android/credentials/selection/CreateCredentialProviderInfo.java
index 41ca852..78b9fd44 100644
--- a/core/java/android/credentials/ui/CreateCredentialProviderInfo.java
+++ b/core/java/android/credentials/selection/CreateCredentialProviderInfo.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/core/java/android/credentials/ui/DisabledProviderData.java b/core/java/android/credentials/selection/DisabledProviderData.java
similarity index 90%
rename from core/java/android/credentials/ui/DisabledProviderData.java
rename to core/java/android/credentials/selection/DisabledProviderData.java
index 8bccdc9..b6f6ad4 100644
--- a/core/java/android/credentials/ui/DisabledProviderData.java
+++ b/core/java/android/credentials/selection/DisabledProviderData.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -27,6 +30,7 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class DisabledProviderData extends ProviderData implements Parcelable {
 
     public DisabledProviderData(
diff --git a/core/java/android/credentials/ui/DisabledProviderInfo.java b/core/java/android/credentials/selection/DisabledProviderInfo.java
similarity index 97%
rename from core/java/android/credentials/ui/DisabledProviderInfo.java
rename to core/java/android/credentials/selection/DisabledProviderInfo.java
index 7ce6368..7d7dbc2 100644
--- a/core/java/android/credentials/ui/DisabledProviderInfo.java
+++ b/core/java/android/credentials/selection/DisabledProviderInfo.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
 import android.annotation.NonNull;
 
diff --git a/core/java/android/credentials/ui/Entry.java b/core/java/android/credentials/selection/Entry.java
similarity index 95%
rename from core/java/android/credentials/ui/Entry.java
rename to core/java/android/credentials/selection/Entry.java
index 8469447..bcf4ee3 100644
--- a/core/java/android/credentials/ui/Entry.java
+++ b/core/java/android/credentials/selection/Entry.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -34,6 +37,7 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class Entry implements Parcelable {
     @NonNull
     private final String mKey;
diff --git a/core/java/android/credentials/ui/FailureDialogResult.java b/core/java/android/credentials/selection/FailureDialogResult.java
similarity index 88%
rename from core/java/android/credentials/ui/FailureDialogResult.java
rename to core/java/android/credentials/selection/FailureDialogResult.java
index abd5a92..218aa46 100644
--- a/core/java/android/credentials/ui/FailureDialogResult.java
+++ b/core/java/android/credentials/selection/FailureDialogResult.java
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -28,6 +32,8 @@
  *
  * @hide
  */
+@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class FailureDialogResult extends BaseDialogResult implements Parcelable {
     /** Parses and returns a UserSelectionDialogResult from the given resultData. */
     @Nullable
@@ -50,7 +56,7 @@
      * selector activity finishes.
      */
     private static final String EXTRA_FAILURE_RESULT =
-            "android.credentials.ui.extra.FAILURE_RESULT";
+            "android.credentials.selection.extra.FAILURE_RESULT";
 
     @Nullable
     private final String mErrorMessage;
@@ -66,7 +72,7 @@
         return mErrorMessage;
     }
 
-    protected FailureDialogResult(@NonNull Parcel in) {
+    private FailureDialogResult(@NonNull Parcel in) {
         super(in);
         mErrorMessage = in.readString8();
     }
diff --git a/core/java/android/credentials/ui/FailureResult.java b/core/java/android/credentials/selection/FailureResult.java
similarity index 90%
rename from core/java/android/credentials/ui/FailureResult.java
rename to core/java/android/credentials/selection/FailureResult.java
index ec58417..93ba671 100644
--- a/core/java/android/credentials/ui/FailureResult.java
+++ b/core/java/android/credentials/selection/FailureResult.java
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -28,7 +32,9 @@
  *
  * @hide
  */
-public final class FailureResult implements UiResult {
+@SystemApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
+public final class FailureResult {
     @Nullable
     private final String mErrorMessage;
     @NonNull
diff --git a/core/java/android/credentials/ui/GetCredentialProviderData.java b/core/java/android/credentials/selection/GetCredentialProviderData.java
similarity index 95%
rename from core/java/android/credentials/ui/GetCredentialProviderData.java
rename to core/java/android/credentials/selection/GetCredentialProviderData.java
index 481419b..2d09f60 100644
--- a/core/java/android/credentials/ui/GetCredentialProviderData.java
+++ b/core/java/android/credentials/selection/GetCredentialProviderData.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -33,6 +36,7 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class GetCredentialProviderData extends ProviderData implements Parcelable {
     @NonNull
     private final List<Entry> mCredentialEntries;
@@ -141,6 +145,7 @@
      * @hide
      */
     @TestApi
+    @FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
     public static final class Builder {
         @NonNull
         private String mProviderFlattenedComponentName;
diff --git a/core/java/android/credentials/ui/GetCredentialProviderInfo.java b/core/java/android/credentials/selection/GetCredentialProviderInfo.java
similarity index 99%
rename from core/java/android/credentials/ui/GetCredentialProviderInfo.java
rename to core/java/android/credentials/selection/GetCredentialProviderInfo.java
index bac7147..db0fb84 100644
--- a/core/java/android/credentials/ui/GetCredentialProviderInfo.java
+++ b/core/java/android/credentials/selection/GetCredentialProviderInfo.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/core/java/android/credentials/ui/IntentFactory.java b/core/java/android/credentials/selection/IntentFactory.java
similarity index 95%
rename from core/java/android/credentials/ui/IntentFactory.java
rename to core/java/android/credentials/selection/IntentFactory.java
index 5e1e0ef..c3a09ae 100644
--- a/core/java/android/credentials/ui/IntentFactory.java
+++ b/core/java/android/credentials/selection/IntentFactory.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
@@ -34,6 +37,7 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public class IntentFactory {
 
     /**
diff --git a/core/java/android/credentials/ui/IntentHelper.java b/core/java/android/credentials/selection/IntentHelper.java
similarity index 98%
rename from core/java/android/credentials/ui/IntentHelper.java
rename to core/java/android/credentials/selection/IntentHelper.java
index c5f34c1..6bcd05a 100644
--- a/core/java/android/credentials/ui/IntentHelper.java
+++ b/core/java/android/credentials/selection/IntentHelper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/core/java/android/credentials/ui/ProviderData.java b/core/java/android/credentials/selection/ProviderData.java
similarity index 81%
rename from core/java/android/credentials/ui/ProviderData.java
rename to core/java/android/credentials/selection/ProviderData.java
index 1e5aa24..e7a7d77 100644
--- a/core/java/android/credentials/ui/ProviderData.java
+++ b/core/java/android/credentials/selection/ProviderData.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
@@ -30,6 +33,7 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 @SuppressLint({"ParcelCreator", "ParcelNotFinal"})
 public abstract class ProviderData implements Parcelable {
 
@@ -38,13 +42,13 @@
      * launching the UX activities.
      */
     public static final String EXTRA_ENABLED_PROVIDER_DATA_LIST =
-            "android.credentials.ui.extra.ENABLED_PROVIDER_DATA_LIST";
+            "android.credentials.selection.extra.ENABLED_PROVIDER_DATA_LIST";
     /**
      * The intent extra key for the list of {@code ProviderData} from disabled providers when
      * launching the UX activities.
      */
     public static final String EXTRA_DISABLED_PROVIDER_DATA_LIST =
-            "android.credentials.ui.extra.DISABLED_PROVIDER_DATA_LIST";
+            "android.credentials.selection.extra.DISABLED_PROVIDER_DATA_LIST";
 
     @NonNull
     private final String mProviderFlattenedComponentName;
@@ -63,6 +67,9 @@
         return mProviderFlattenedComponentName;
     }
 
+    @SuppressLint("ParcelConstructor") // Test API only. This is never intended to be officially
+    // exposed. Instead proper final wrapper classes are defined (e.g.
+    // {@code GetCredentialProviderInfo}).
     protected ProviderData(@NonNull Parcel in) {
         String providerFlattenedComponentName = in.readString8();
         mProviderFlattenedComponentName = providerFlattenedComponentName;
diff --git a/core/java/android/credentials/selection/ProviderPendingIntentResponse.java b/core/java/android/credentials/selection/ProviderPendingIntentResponse.java
new file mode 100644
index 0000000..281f34a
--- /dev/null
+++ b/core/java/android/credentials/selection/ProviderPendingIntentResponse.java
@@ -0,0 +1,124 @@
+/*
+ * 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 android.credentials.selection;
+
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ResultReceiver;
+
+/**
+ * Result of launching a provider's PendingIntent associated with an {@link Entry} after it is
+ * selected by the user.
+ *
+ * The provider sets the credential creation / retrieval result through
+ * {@link android.app.Activity#setResult(int, Intent)}, which is then directly propagated back
+ * through this data structure.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
+public final class ProviderPendingIntentResponse implements Parcelable {
+    private final int mResultCode;
+    @Nullable
+    private final Intent mResultData;
+
+    /**
+     * Constructs a {@link ProviderPendingIntentResponse}.
+     *
+     * When a user makes a selection, you should launch the associated provider PendingIntent,
+     * and expect the provider activity to complete and set
+     * {@link android.app.Activity#setResult(int, Intent)}. You should then immediately pass back
+     * the provider activity result code and data to the system service using this data class,
+     * via the {@link ResultHelper#sendUserSelectionResult(ResultReceiver, UserSelectionResult)}
+     * API.
+     *
+     * @param resultCode the resultCode returned from the provider activity
+     * @param resultData the result data returned from the provider activity; only set to null if
+     *                   the provider result (a provider would set it via
+     *                   {@link android.app.Activity#setResult(int, Intent)}) your UI received
+     *                   was actually null
+     */
+    public ProviderPendingIntentResponse(int resultCode, @Nullable Intent resultData) {
+        mResultCode = resultCode;
+        mResultData = resultData;
+    }
+
+    private ProviderPendingIntentResponse(@NonNull Parcel in) {
+        mResultCode = in.readInt();
+        mResultData = in.readTypedObject(Intent.CREATOR);
+    }
+
+    public static final @NonNull Creator<ProviderPendingIntentResponse> CREATOR =
+            new Creator<>() {
+                @Override
+                public ProviderPendingIntentResponse createFromParcel(@NonNull Parcel in) {
+                    return new ProviderPendingIntentResponse(in);
+                }
+
+                @Override
+                public ProviderPendingIntentResponse[] newArray(int size) {
+                    return new ProviderPendingIntentResponse[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mResultCode);
+        dest.writeTypedObject(mResultData, flags);
+    }
+
+    /**
+     * Returns the result code associated with this provider PendingIntent activity result, i.e.
+     * the {@code resultCode} that the provider activity has set using the
+     * {@link android.app.Activity#setResult(int, Intent)} API.
+     */
+    public int getResultCode() {
+        return mResultCode;
+    }
+
+    /**
+     * Returns the result data associated with this provider PendingIntent activity result, i.e.
+     * the {@code data} that the provider activity has set using the
+     * {@link android.app.Activity#setResult(int, Intent)} API.
+     *
+     * Notice that this value can be null if the provider UI result (a provider would set it via
+     * {@link android.app.Activity#setResult(int, Intent)}) that your UI received was actually null,
+     * which indicates an implementation error on the provider side. The system service will
+     * gracefully handle this by passing back an API exception (
+     * {@link android.credentials.GetCredentialException} or
+     * {@link android.credentials.CreateCredentialException}).
+     */
+    @SuppressLint("IntentBuilderName") // Not building a new intent.
+    @Nullable
+    public Intent getResultData() {
+        return mResultData;
+    }
+}
diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/selection/RequestInfo.java
similarity index 82%
rename from core/java/android/credentials/ui/RequestInfo.java
rename to core/java/android/credentials/selection/RequestInfo.java
index f651584..7d6ea7e 100644
--- a/core/java/android/credentials/ui/RequestInfo.java
+++ b/core/java/android/credentials/selection/RequestInfo.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
@@ -39,39 +42,46 @@
  * @hide
  */
 @TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class RequestInfo implements Parcelable {
 
     /**
      * The intent extra key for the {@code RequestInfo} object when launching the UX
      * activities.
      */
-    @NonNull public static final String EXTRA_REQUEST_INFO =
-            "android.credentials.ui.extra.REQUEST_INFO";
+    @NonNull
+    public static final String EXTRA_REQUEST_INFO =
+            "android.credentials.selection.extra.REQUEST_INFO";
 
     /**
      * Type value for any request that does not require UI.
      */
-    @NonNull public static final String TYPE_UNDEFINED = "android.credentials.ui.TYPE_UNDEFINED";
+    @NonNull
+    public static final String TYPE_UNDEFINED = "android.credentials.selection.TYPE_UNDEFINED";
     /**
      * Type value for a getCredential request.
      */
-    @NonNull public static final String TYPE_GET = "android.credentials.ui.TYPE_GET";
+    @NonNull
+    public static final String TYPE_GET = "android.credentials.selection.TYPE_GET";
     /**
      * Type value for a getCredential request that utilizes the credential registry.
      *
      * @hide
      */
-    @NonNull public static final String TYPE_GET_VIA_REGISTRY =
-            "android.credentials.ui.TYPE_GET_VIA_REGISTRY";
+    @NonNull
+    public static final String TYPE_GET_VIA_REGISTRY =
+            "android.credentials.selection.TYPE_GET_VIA_REGISTRY";
     /**
      * Type value for a createCredential request.
      */
-    @NonNull public static final String TYPE_CREATE = "android.credentials.ui.TYPE_CREATE";
+    @NonNull
+    public static final String TYPE_CREATE = "android.credentials.selection.TYPE_CREATE";
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef(value = { TYPE_GET, TYPE_CREATE })
-    public @interface RequestType {}
+    @StringDef(value = {TYPE_GET, TYPE_CREATE})
+    public @interface RequestType {
+    }
 
     @NonNull
     private final IBinder mToken;
@@ -82,6 +92,9 @@
     @NonNull
     private final List<String> mDefaultProviderIds;
 
+    @NonNull
+    private final List<String> mRegistryProviderIds;
+
     @Nullable
     private final GetCredentialRequest mGetCredentialRequest;
 
@@ -105,11 +118,7 @@
                 /*defaultProviderIds=*/ new ArrayList<>());
     }
 
-    /**
-     * Creates new {@code RequestInfo} for a create-credential flow.
-     *
-     * @hide
-     */
+    /** Creates new {@code RequestInfo} for a create-credential flow. */
     @NonNull
     public static RequestInfo newCreateRequestInfo(
             @NonNull IBinder token, @NonNull CreateCredentialRequest createCredentialRequest,
@@ -120,11 +129,7 @@
                 hasPermissionToOverrideDefault, defaultProviderIds);
     }
 
-    /**
-     * Creates new {@code RequestInfo} for a get-credential flow.
-     *
-     * @hide
-     */
+    /** Creates new {@code RequestInfo} for a get-credential flow. */
     @NonNull
     public static RequestInfo newGetRequestInfo(
             @NonNull IBinder token, @NonNull GetCredentialRequest getCredentialRequest,
@@ -147,11 +152,7 @@
     }
 
 
-    /**
-     * Returns whether the calling package has the permission
-     *
-     * @hide
-     */
+    /** Returns whether the calling package has the permission. */
     public boolean hasPermissionToOverrideDefault() {
         return mHasPermissionToOverrideDefault;
     }
@@ -185,13 +186,11 @@
     }
 
     /**
-     * Returns default provider identifier (flattened component name) configured from the user
+     * Returns default provider identifiers (component or package name) configured from the user
      * settings.
      *
      * Will only be possibly non-empty for the create use case. Not meaningful for the sign-in use
      * case.
-     *
-     * @hide
      */
     @NonNull
     public List<String> getDefaultProviderIds() {
@@ -199,6 +198,15 @@
     }
 
     /**
+     * Returns provider identifiers (component or package name) that have been validated to provide
+     * registry entries.
+     */
+    @NonNull
+    public List<String> getRegistryProviderIds() {
+        return mRegistryProviderIds;
+    }
+
+    /**
      * Returns the non-null GetCredentialRequest when the type of the request is {@link
      * #TYPE_GET}, or null otherwise.
      */
@@ -220,6 +228,7 @@
         mGetCredentialRequest = getCredentialRequest;
         mHasPermissionToOverrideDefault = hasPermissionToOverrideDefault;
         mDefaultProviderIds = defaultProviderIds == null ? new ArrayList<>() : defaultProviderIds;
+        mRegistryProviderIds = new ArrayList<>();
     }
 
     private RequestInfo(@NonNull Parcel in) {
@@ -241,6 +250,7 @@
         mGetCredentialRequest = getCredentialRequest;
         mHasPermissionToOverrideDefault = in.readBoolean();
         mDefaultProviderIds = in.createStringArrayList();
+        mRegistryProviderIds = in.createStringArrayList();
     }
 
     @Override
@@ -252,6 +262,7 @@
         dest.writeTypedObject(mGetCredentialRequest, flags);
         dest.writeBoolean(mHasPermissionToOverrideDefault);
         dest.writeStringList(mDefaultProviderIds);
+        dest.writeStringList(mRegistryProviderIds);
     }
 
     @Override
@@ -259,7 +270,8 @@
         return 0;
     }
 
-    @NonNull public static final Creator<RequestInfo> CREATOR = new Creator<>() {
+    @NonNull
+    public static final Creator<RequestInfo> CREATOR = new Creator<>() {
         @Override
         public RequestInfo createFromParcel(@NonNull Parcel in) {
             return new RequestInfo(in);
diff --git a/core/java/android/credentials/ui/ResultHelper.java b/core/java/android/credentials/selection/ResultHelper.java
similarity index 73%
rename from core/java/android/credentials/ui/ResultHelper.java
rename to core/java/android/credentials/selection/ResultHelper.java
index 7b9d5e8..d6347b0 100644
--- a/core/java/android/credentials/ui/ResultHelper.java
+++ b/core/java/android/credentials/selection/ResultHelper.java
@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.ResultReceiver;
@@ -26,13 +30,16 @@
  *
  * @hide
  */
+@SystemApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class ResultHelper {
     /**
      * Sends the {@code failureResult} that caused the UI to stop back to the CredentialManager
      * service.
      *
-     * The {code resultReceiver} for a UI flow can be extracted from the UI launch intent via
-     * {@link IntentHelper#extractResultReceiver(Intent)}.
+     * @param resultReceiver the ResultReceiver sent from the system service, that can be extracted
+     *                      from the launch intent via
+     *                      {@link IntentHelper#extractResultReceiver(Intent)}
      */
     public static void sendFailureResult(@NonNull ResultReceiver resultReceiver,
             @NonNull FailureResult failureResult) {
@@ -46,8 +53,9 @@
     /**
      * Sends the completed {@code userSelectionResult} back to the CredentialManager service.
      *
-     * The {code resultReceiver} for a UI flow can be extracted from the UI launch intent via
-     * {@link IntentHelper#extractResultReceiver(Intent)}.
+     * @param resultReceiver the ResultReceiver sent from the system service, that can be extracted
+     *                       from the launch intent via
+     *                       {@link IntentHelper#extractResultReceiver(Intent)}
      */
     public static void sendUserSelectionResult(@NonNull ResultReceiver resultReceiver,
             @NonNull UserSelectionResult userSelectionResult) {
diff --git a/core/java/android/credentials/ui/UserSelectionDialogResult.java b/core/java/android/credentials/selection/UserSelectionDialogResult.java
similarity index 79%
rename from core/java/android/credentials/ui/UserSelectionDialogResult.java
rename to core/java/android/credentials/selection/UserSelectionDialogResult.java
index 3089bf6..50d5aa3 100644
--- a/core/java/android/credentials/ui/UserSelectionDialogResult.java
+++ b/core/java/android/credentials/selection/UserSelectionDialogResult.java
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.credentials.selection;
 
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -30,17 +34,19 @@
  *
  * @hide
  */
+@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
 public final class UserSelectionDialogResult extends BaseDialogResult implements Parcelable {
     /** Parses and returns a UserSelectionDialogResult from the given resultData. */
     @Nullable
     public static UserSelectionDialogResult fromResultData(@NonNull Bundle resultData) {
         return resultData.getParcelable(
-            EXTRA_USER_SELECTION_RESULT, UserSelectionDialogResult.class);
+                EXTRA_USER_SELECTION_RESULT, UserSelectionDialogResult.class);
     }
 
     /**
      * Used for the UX to construct the {@code resultData Bundle} to send via the {@code
-     *  ResultReceiver}.
+     * ResultReceiver}.
      */
     public static void addToBundle(
             @NonNull UserSelectionDialogResult result, @NonNull Bundle bundle) {
@@ -52,12 +58,16 @@
      * selector activity finishes.
      */
     private static final String EXTRA_USER_SELECTION_RESULT =
-            "android.credentials.ui.extra.USER_SELECTION_RESULT";
+            "android.credentials.selection.extra.USER_SELECTION_RESULT";
 
-    @NonNull private final String mProviderId;
-    @NonNull private final String mEntryKey;
-    @NonNull private final String mEntrySubkey;
-    @Nullable private ProviderPendingIntentResponse mProviderPendingIntentResponse;
+    @NonNull
+    private final String mProviderId;
+    @NonNull
+    private final String mEntryKey;
+    @NonNull
+    private final String mEntrySubkey;
+    @Nullable
+    private ProviderPendingIntentResponse mProviderPendingIntentResponse;
 
     public UserSelectionDialogResult(
             @Nullable IBinder requestToken, @NonNull String providerId,
@@ -103,7 +113,7 @@
         return mProviderPendingIntentResponse;
     }
 
-    protected UserSelectionDialogResult(@NonNull Parcel in) {
+    private UserSelectionDialogResult(@NonNull Parcel in) {
         super(in);
         String providerId = in.readString8();
         String entryKey = in.readString8();
@@ -134,14 +144,14 @@
 
     public static final @NonNull Creator<UserSelectionDialogResult> CREATOR =
             new Creator<UserSelectionDialogResult>() {
-        @Override
-        public UserSelectionDialogResult createFromParcel(@NonNull Parcel in) {
-            return new UserSelectionDialogResult(in);
-        }
+                @Override
+                public UserSelectionDialogResult createFromParcel(@NonNull Parcel in) {
+                    return new UserSelectionDialogResult(in);
+                }
 
-        @Override
-        public UserSelectionDialogResult[] newArray(int size) {
-            return new UserSelectionDialogResult[size];
-        }
-    };
+                @Override
+                public UserSelectionDialogResult[] newArray(int size) {
+                    return new UserSelectionDialogResult[size];
+                }
+            };
 }
diff --git a/core/java/android/credentials/selection/UserSelectionResult.java b/core/java/android/credentials/selection/UserSelectionResult.java
new file mode 100644
index 0000000..235a5d5
--- /dev/null
+++ b/core/java/android/credentials/selection/UserSelectionResult.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 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 android.credentials.selection;
+
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Result sent back from the UI after the user chose an option and completed the following
+ * transaction launched through the provider PendingIntent associated with that option.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
+public final class UserSelectionResult {
+    @NonNull
+    private final String mProviderId;
+    @NonNull
+    private final String mEntryKey;
+    @NonNull
+    private final String mEntrySubkey;
+    @Nullable
+    private ProviderPendingIntentResponse mProviderPendingIntentResponse;
+
+    /**
+     * Constructs a {@link UserSelectionResult}.
+     *
+     * @param providerId the provider identifier (component name or package name) whose entry was
+     *                  selected by the user; the value should map to the
+     *                  {@link GetCredentialProviderInfo#getProviderName()} that provided this entry
+     * @param entryKey the identifier of this selected entry, i.e. the selected entry's
+     *                 {@link Entry#getKey()}
+     * @param entrySubkey the sub-identifier of this selected entry, i.e. the selected entry's
+     *                    {@link Entry#getSubkey()}
+     * @param providerPendingIntentResponse the provider activity result of launching the provider
+     *                                      PendingIntent associated with this selection; or null
+     *                                      if the associated selection didn't have an associated
+     *                                      provider PendingIntent
+     * @throws IllegalArgumentException if {@code providerId}, {@code entryKey}, or
+     *                                  {@code entrySubkey} is empty
+     */
+
+    public UserSelectionResult(@NonNull String providerId,
+            @NonNull String entryKey, @NonNull String entrySubkey,
+            @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
+        mProviderId = Preconditions.checkStringNotEmpty(providerId);
+        mEntryKey = Preconditions.checkStringNotEmpty(entryKey);
+        mEntrySubkey = Preconditions.checkStringNotEmpty(entrySubkey);
+        mProviderPendingIntentResponse = providerPendingIntentResponse;
+    }
+
+    /**
+     * Returns the provider identifier (component name or package name) whose entry was selected by
+     * the user.
+     */
+    @NonNull
+    public String getProviderId() {
+        return mProviderId;
+    }
+
+    /** Returns the identifier of the visual entry that the user selected. */
+    @NonNull
+    public String getEntryKey() {
+        return mEntryKey;
+    }
+
+    /** Returns the sub-identifier of the visual entry that the user selected. */
+    @NonNull
+    public String getEntrySubkey() {
+        return mEntrySubkey;
+    }
+
+    /** Returns the pending intent response from the provider. */
+    @Nullable
+    public ProviderPendingIntentResponse getPendingIntentProviderResponse() {
+        return mProviderPendingIntentResponse;
+    }
+
+    @NonNull
+    UserSelectionDialogResult toUserSelectionDialogResult() {
+        return new UserSelectionDialogResult(/*requestToken=*/null, mProviderId, mEntryKey,
+                mEntrySubkey, mProviderPendingIntentResponse);
+    }
+}
diff --git a/core/java/android/credentials/ui/ProviderPendingIntentResponse.java b/core/java/android/credentials/ui/ProviderPendingIntentResponse.java
deleted file mode 100644
index 11cc21f9..0000000
--- a/core/java/android/credentials/ui/ProviderPendingIntentResponse.java
+++ /dev/null
@@ -1,87 +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 android.credentials.ui;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Result of launching a provider's PendingIntent associated with an {@link Entry} after it is
- * selected by the user.
- *
- * The provider sets the credential creation / retrieval result through
- * {@link android.app.Activity#setResult(int, Intent)}, which is then directly propagated back
- * through this data structure.
- *
- * @hide
- */
-public final class ProviderPendingIntentResponse implements Parcelable {
-    private final int mResultCode;
-    @Nullable
-    private final Intent mResultData;
-
-    /** Constructs a {@link ProviderPendingIntentResponse}. */
-    public ProviderPendingIntentResponse(int resultCode, @Nullable Intent resultData) {
-        mResultCode = resultCode;
-        mResultData = resultData;
-    }
-
-    private ProviderPendingIntentResponse(@NonNull Parcel in) {
-        mResultCode = in.readInt();
-        mResultData = in.readTypedObject(Intent.CREATOR);
-    }
-
-    public static final @NonNull Creator<ProviderPendingIntentResponse> CREATOR =
-            new Creator<>() {
-                @Override
-                public ProviderPendingIntentResponse createFromParcel(@NonNull Parcel in) {
-                    return new ProviderPendingIntentResponse(in);
-                }
-
-                @Override
-                public ProviderPendingIntentResponse[] newArray(int size) {
-                    return new ProviderPendingIntentResponse[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mResultCode);
-        dest.writeTypedObject(mResultData, flags);
-    }
-
-    /** Returns the result code associated with this provider PendingIntent activity result. */
-    public int getResultCode() {
-        return mResultCode;
-    }
-
-    /** Returns the result data associated with this provider PendingIntent activity result. */
-    @SuppressLint("IntentBuilderName") // Not building a new intent.
-    @NonNull
-    public Intent getResultData() {
-        return mResultData;
-    }
-}
diff --git a/core/java/android/credentials/ui/UserSelectionResult.java b/core/java/android/credentials/ui/UserSelectionResult.java
deleted file mode 100644
index 431dc63..0000000
--- a/core/java/android/credentials/ui/UserSelectionResult.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 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 android.credentials.ui;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import com.android.internal.util.Preconditions;
-
-/**
- * Result sent back from the UI after the user chose an option and completed the following
- * transaction launched through the provider PendingIntent associated with that option.
- *
- * @hide
- */
-public final class UserSelectionResult implements UiResult {
-    @NonNull
-    private final String mProviderId;
-    @NonNull
-    private final String mEntryKey;
-    @NonNull
-    private final String mEntrySubkey;
-    @Nullable
-    private ProviderPendingIntentResponse mProviderPendingIntentResponse;
-
-    /**
-     * Constructs a {@link UserSelectionResult}.
-     *
-     * @throws IllegalArgumentException if {@code providerId} is empty
-     */
-
-    public UserSelectionResult(@NonNull String providerId,
-            @NonNull String entryKey, @NonNull String entrySubkey,
-            @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
-        mProviderId = Preconditions.checkStringNotEmpty(providerId);
-        mEntryKey = Preconditions.checkNotNull(entryKey);
-        mEntrySubkey = Preconditions.checkNotNull(entrySubkey);
-        mProviderPendingIntentResponse = providerPendingIntentResponse;
-    }
-
-    /** Returns provider package name whose entry was selected by the user. */
-    @NonNull
-    public String getProviderId() {
-        return mProviderId;
-    }
-
-    /** Returns the key of the visual entry that the user selected. */
-    @NonNull
-    public String getEntryKey() {
-        return mEntryKey;
-    }
-
-    /** Returns the subkey of the visual entry that the user selected. */
-    @NonNull
-    public String getEntrySubkey() {
-        return mEntrySubkey;
-    }
-
-    /** Returns the pending intent response from the provider. */
-    @Nullable
-    public ProviderPendingIntentResponse getPendingIntentProviderResponse() {
-        return mProviderPendingIntentResponse;
-    }
-
-    @NonNull
-    UserSelectionDialogResult toUserSelectionDialogResult() {
-        return new UserSelectionDialogResult(/*requestToken=*/null, mProviderId, mEntryKey,
-                mEntrySubkey, mProviderPendingIntentResponse);
-    }
-}
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index 0047b7d..ce0f9f59 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -115,14 +115,16 @@
     @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V)
     public static final int R_8           = 0x38;
     /**
-     * Format: 16 bits red. Bits should be represented in unsigned integer, instead of the
-     * implicit unsigned normalized.
+     * Format: 16 bits red. When sampled on the GPU this is represented as an
+     * unsigned integer instead of implicit unsigned normalize.
+     * For more information see https://www.khronos.org/opengl/wiki/Normalized_Integer
      */
     @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V)
     public static final int R_16          = 0x39;
     /**
-     * Format: 16 bits each red, green. Bits should be represented in unsigned integer,
-     * instead of the implicit unsigned normalized.
+     * Format: 16 bits each red, green. When sampled on the GPU this is represented
+     * as an unsigned integer instead of implicit unsigned normalize.
+     * For more information see https://www.khronos.org/opengl/wiki/Normalized_Integer
      */
     @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V)
     public static final int RG_1616       = 0x3a;
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index c0424db..bdaf9d7 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -16,7 +16,7 @@
 
 package android.hardware.biometrics;
 
-import static android.Manifest.permission.MANAGE_BIOMETRIC_DIALOG;
+import static android.Manifest.permission.SET_BIOMETRIC_DIALOG_LOGO;
 import static android.Manifest.permission.TEST_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
@@ -174,9 +174,9 @@
          * @return This builder.
          */
         @FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
-        @RequiresPermission(MANAGE_BIOMETRIC_DIALOG)
+        @RequiresPermission(SET_BIOMETRIC_DIALOG_LOGO)
         @NonNull
-        public BiometricPrompt.Builder setLogo(@DrawableRes int logoRes) {
+        public BiometricPrompt.Builder setLogoRes(@DrawableRes int logoRes) {
             mPromptInfo.setLogoRes(logoRes);
             return this;
         }
@@ -193,9 +193,9 @@
          * @return This builder.
          */
         @FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
-        @RequiresPermission(MANAGE_BIOMETRIC_DIALOG)
+        @RequiresPermission(SET_BIOMETRIC_DIALOG_LOGO)
         @NonNull
-        public BiometricPrompt.Builder setLogo(@NonNull Bitmap logoBitmap) {
+        public BiometricPrompt.Builder setLogoBitmap(@NonNull Bitmap logoBitmap) {
             mPromptInfo.setLogoBitmap(logoBitmap);
             return this;
         }
@@ -719,25 +719,25 @@
 
     /**
      * Gets the drawable resource of the logo for the prompt, as set by
-     * {@link Builder#setLogo(int)}. Currently for system applications use only.
+     * {@link Builder#setLogoRes(int)}. Currently for system applications use only.
      *
      * @return The drawable resource of the logo, or -1 if the prompt has no logo resource set.
      */
     @FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
-    @RequiresPermission(MANAGE_BIOMETRIC_DIALOG)
+    @RequiresPermission(SET_BIOMETRIC_DIALOG_LOGO)
     @DrawableRes
     public int getLogoRes() {
         return mPromptInfo.getLogoRes();
     }
 
     /**
-     * Gets the logo bitmap for the prompt, as set by {@link Builder#setLogo(Bitmap)}. Currently for
-     * system applications use only.
+     * Gets the logo bitmap for the prompt, as set by {@link Builder#setLogoBitmap(Bitmap)}.
+     * Currently for system applications use only.
      *
      * @return The logo bitmap of the prompt, or null if the prompt has no logo bitmap set.
      */
     @FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
-    @RequiresPermission(MANAGE_BIOMETRIC_DIALOG)
+    @RequiresPermission(SET_BIOMETRIC_DIALOG_LOGO)
     @Nullable
     public Bitmap getLogoBitmap() {
         return mPromptInfo.getLogoBitmap();
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index d788b37..0f9cadc 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -166,9 +166,9 @@
     }
 
     /**
-     * Returns whether MANAGE_BIOMETRIC_DIALOG is contained.
+     * Returns whether SET_BIOMETRIC_DIALOG_LOGO is contained.
      */
-    public boolean containsManageBioApiConfigurations() {
+    public boolean containsSetLogoApiConfigurations() {
         if (mLogoRes != -1) {
             return true;
         } else if (mLogoBitmap != null) {
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
index 7c54a9b..509bcb8 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
+++ b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
@@ -26,6 +26,7 @@
     Surface surface;
     int imageFormat;
     int capacity;
+    long usage;
 
     const int TYPE_SURFACE = 0;
     const int TYPE_IMAGEREADER = 1;
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 98bc311..f6c8f36 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -1182,7 +1182,8 @@
                     return null;
                 }
                 ImageReader reader = ImageReader.newInstance(output.size.width,
-                        output.size.height, output.imageFormat, output.capacity);
+                        output.size.height, output.imageFormat, output.capacity,
+                        output.usage);
                 mReaderMap.put(output.outputId.id, reader);
                 return reader.getSurface();
             case CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER:
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index d939532..fdbd319 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -17,6 +17,7 @@
 package android.hardware.input;
 
 import static com.android.hardware.input.Flags.keyboardA11yBounceKeysFlag;
+import static com.android.hardware.input.Flags.keyboardA11ySlowKeysFlag;
 import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag;
 import static com.android.input.flags.Flags.enableInputFilterRustImpl;
 
@@ -68,6 +69,12 @@
      */
     public static final int MAX_ACCESSIBILITY_BOUNCE_KEYS_THRESHOLD_MILLIS = 5000;
 
+    /**
+     * The maximum allowed Accessibility slow keys threshold.
+     * @hide
+     */
+    public static final int MAX_ACCESSIBILITY_SLOW_KEYS_THRESHOLD_MILLIS = 5000;
+
     private InputSettings() {
     }
 
@@ -419,6 +426,86 @@
     }
 
     /**
+     * Whether Accessibility slow keys feature flags is enabled.
+     *
+     * <p>
+     * 'Slow keys' is an accessibility feature to aid users who have physical disabilities, that
+     * allows the user to specify the duration for which one must press-and-hold a key before the
+     * system accepts the keypress.
+     * </p>
+     *
+     * @hide
+     */
+    public static boolean isAccessibilitySlowKeysFeatureFlagEnabled() {
+        return keyboardA11ySlowKeysFlag() && enableInputFilterRustImpl();
+    }
+
+    /**
+     * Whether Accessibility slow keys is enabled.
+     *
+     * <p>
+     * 'Slow keys' is an accessibility feature to aid users who have physical disabilities, that
+     * allows the user to specify the duration for which one must press-and-hold a key before the
+     * system accepts the keypress.
+     * </p>
+     *
+     * @hide
+     */
+    public static boolean isAccessibilitySlowKeysEnabled(@NonNull Context context) {
+        return getAccessibilitySlowKeysThreshold(context) != 0;
+    }
+
+    /**
+     * Get Accessibility slow keys threshold duration in milliseconds.
+     *
+     * <p>
+     * 'Slow keys' is an accessibility feature to aid users who have physical disabilities, that
+     * allows the user to specify the duration for which one must press-and-hold a key before the
+     * system accepts the keypress.
+     * </p>
+     *
+     * @hide
+     */
+    public static int getAccessibilitySlowKeysThreshold(@NonNull Context context) {
+        if (!isAccessibilitySlowKeysFeatureFlagEnabled()) {
+            return 0;
+        }
+        return Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SLOW_KEYS, 0, UserHandle.USER_CURRENT);
+    }
+
+    /**
+     * Set Accessibility slow keys threshold duration in milliseconds.
+     * @param thresholdTimeMillis time duration for which a key should be pressed to be registered
+     *                            in the system. The threshold must be between 0 and
+     *                            {@link MAX_ACCESSIBILITY_SLOW_KEYS_THRESHOLD_MILLIS}
+     *
+     * <p>
+     * 'Slow keys' is an accessibility feature to aid users who have physical disabilities, that
+     * allows the user to specify the duration for which one must press-and-hold a key before the
+     * system accepts the keypress.
+     * </p>
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setAccessibilitySlowKeysThreshold(@NonNull Context context,
+            int thresholdTimeMillis) {
+        if (!isAccessibilitySlowKeysFeatureFlagEnabled()) {
+            return;
+        }
+        if (thresholdTimeMillis < 0
+                || thresholdTimeMillis > MAX_ACCESSIBILITY_SLOW_KEYS_THRESHOLD_MILLIS) {
+            throw new IllegalArgumentException(
+                    "Provided Slow keys threshold should be in range [0, "
+                            + MAX_ACCESSIBILITY_SLOW_KEYS_THRESHOLD_MILLIS + "]");
+        }
+        Settings.Secure.putIntForUser(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SLOW_KEYS, thresholdTimeMillis,
+                UserHandle.USER_CURRENT);
+    }
+
+    /**
      * Whether Accessibility sticky keys feature is enabled.
      *
      * <p>
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 362fe78..0ed6569 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -29,4 +29,11 @@
     name: "pointer_coords_is_resampled_api"
     description: "Makes MotionEvent.PointerCoords#isResampled() a public API"
     bug: "298197511"
+}
+
+flag {
+    namespace: "input_native"
+    name: "keyboard_a11y_slow_keys_flag"
+    description: "Controls if the slow keys accessibility feature for physical keyboard is available to the user"
+    bug: "294546335"
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index db14c08..da6b9c2 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -507,10 +507,16 @@
      *
      * @param key The key the value is stored under.
      * @return a bitmap identifier or 0 if it's missing.
-     * @hide This API is not thoroughly elaborated yet
+     * @throws NullPointerException if metadata key is {@code null}
+     * @throws IllegalArgumentException if the metadata with the key is not found in
+     * metadata or the key is not of bitmap-key type
      */
+    @FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED)
     public int getBitmapId(@NonNull String key) {
-        if (!METADATA_KEY_ICON.equals(key) && !METADATA_KEY_ART.equals(key)) return 0;
+        Objects.requireNonNull(key, "Metadata key can not be null");
+        if (!METADATA_KEY_ICON.equals(key) && !METADATA_KEY_ART.equals(key)) {
+            throw new IllegalArgumentException("Failed to retrieve key " + key + " as bitmap key");
+        }
         return getInt(key);
     }
 
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index 9b2bcde..7c5c003 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -17,6 +17,7 @@
 package android.hardware.radio;
 
 import android.Manifest;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -332,29 +333,30 @@
     public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
 
     /**
-     * Retrieves a {@link Bitmap} for the given image ID or null,
+     * Retrieves a {@link Bitmap} for the given image ID or throw {@link IllegalArgumentException},
      * if the image was missing from the tuner.
      *
      * <p>This involves doing a call to the tuner, so the bitmap should be cached
      * on the application side.
      *
-     * <p>If the method returns null for non-zero ID, it means the image was
-     * updated on the tuner side. There is a race conditon between fetching
-     * image for an old ID and tuner updating the image (and cleaning up the
+     * <p>If the method throws {@link IllegalArgumentException} for non-zero ID, it
+     * means the image was updated on the tuner side. There is a race condition between
+     * fetching image for an old ID and tuner updating the image (and cleaning up the
      * old image). In such case, a new ProgramInfo with updated image id will
      * be sent with a {@link Callback#onProgramInfoChanged(RadioManager.ProgramInfo)}
      * callback.
      *
      * @param id The image identifier, retrieved with
      *           {@link RadioMetadata#getBitmapId(String)}.
-     * @return A {@link Bitmap} or null.
-     * @throws IllegalArgumentException if id==0
-     * @hide This API is not thoroughly elaborated yet
+     * @return A {@link Bitmap} for the given image ID.
+     * @throws IllegalArgumentException if id is 0 or the referenced image id no longer exists.
      */
-    @SuppressWarnings("HiddenAbstractMethod")
+    @FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED)
     @RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
-    public abstract @Nullable Bitmap getMetadataImage(int id);
-
+    public @NonNull Bitmap getMetadataImage(int id) {
+        throw new UnsupportedOperationException(
+                "Getting metadata image must be implemented in child classes");
+    }
     /**
      * Initiates a background scan to update internally cached program list.
      *
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index ba31ca3..63b2d4c 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Bitmap;
 import android.os.RemoteException;
@@ -251,10 +252,18 @@
     }
 
     @Override
-    @Nullable
+    @NonNull
     public Bitmap getMetadataImage(int id) {
+        if (id == 0) {
+            throw new IllegalArgumentException("Invalid metadata image id 0");
+        }
         try {
-            return mTuner.getImage(id);
+            Bitmap bitmap = mTuner.getImage(id);
+            if (bitmap == null) {
+                throw new IllegalArgumentException("Metadata image with id " + id
+                        + " is not available");
+            }
+            return bitmap;
         } catch (RemoteException e) {
             throw new RuntimeException("Service died", e);
         }
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 05b7827f..b7556df 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -292,7 +292,7 @@
         sWarnOnBlockingOnCurrentThread.set(sWarnOnBlocking);
     }
 
-    private static ThreadLocal<SomeArgs> sIdentity$ravenwood;
+    private static volatile ThreadLocal<SomeArgs> sIdentity$ravenwood;
 
     @android.ravenwood.annotation.RavenwoodKeepWholeClass
     private static class IdentitySupplier implements Supplier<SomeArgs> {
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index fcd5731..36730cb 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -35,6 +35,7 @@
     public HandlerThread(String name) {
         super(name);
         mPriority = Process.THREAD_PRIORITY_DEFAULT;
+        onCreated();
     }
     
     /**
@@ -46,8 +47,21 @@
     public HandlerThread(String name, int priority) {
         super(name);
         mPriority = priority;
+        onCreated();
     }
-    
+
+    /** @hide */
+    @android.ravenwood.annotation.RavenwoodReplace
+    protected void onCreated() {
+    }
+
+    /** @hide */
+    protected void onCreated$ravenwood() {
+        // Mark ourselves as daemon to enable tests to terminate quickly when finished, despite
+        // any HandlerThread instances that may be lingering around
+        setDaemon(true);
+    }
+
     /**
      * Call back method that can be explicitly overridden if needed to execute some
      * setup before Looper loops.
diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java
index b5425b4..79a2c59 100644
--- a/core/java/android/os/PatternMatcher.java
+++ b/core/java/android/os/PatternMatcher.java
@@ -16,9 +16,12 @@
 
 package android.os;
 
+import android.annotation.IntDef;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 
 /**
@@ -68,6 +71,17 @@
      */
     public static final int PATTERN_SUFFIX = 4;
 
+    /** @hide */
+    @IntDef(value = {
+            PATTERN_LITERAL,
+            PATTERN_PREFIX,
+            PATTERN_SIMPLE_GLOB,
+            PATTERN_ADVANCED_GLOB,
+            PATTERN_SUFFIX,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PatternType {}
+
     // token types for advanced matching
     private static final int TOKEN_TYPE_LITERAL = 0;
     private static final int TOKEN_TYPE_ANY = 1;
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 02704f5..236194d 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -294,6 +294,43 @@
         XmlUtils.writeMapXml(mMap, out, this);
     }
 
+    /**
+     * Checks whether all keys and values are within the given character limit.
+     * Note: Maximum character limit of String that can be saved to XML as part of bundle is 65535.
+     * Otherwise IOException is thrown.
+     * @param limit length of String keys and values in the PersistableBundle, including nested
+     *                    PersistableBundles to check against.
+     *
+     * @hide
+     */
+    public boolean isBundleContentsWithinLengthLimit(int limit) {
+        unparcel();
+        if (mMap == null) {
+            return true;
+        }
+        for (int i = 0; i < mMap.size(); i++) {
+            if (mMap.keyAt(i) != null && mMap.keyAt(i).length() > limit) {
+                return false;
+            }
+            final Object value = mMap.valueAt(i);
+            if (value instanceof String && ((String) value).length() > limit) {
+                return false;
+            } else if (value instanceof String[]) {
+                String[] stringArray =  (String[]) value;
+                for (int j = 0; j < stringArray.length; j++) {
+                    if (stringArray[j] != null
+                            && stringArray[j].length() > limit) {
+                        return false;
+                    }
+                }
+            } else if (value instanceof PersistableBundle
+                    && !((PersistableBundle) value).isBundleContentsWithinLengthLimit(limit)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /** @hide */
     static class MyReadMapCallback implements  XmlUtils.ReadMapCallback {
         @Override
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index dd0436c..3e7b6c9 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -844,7 +844,7 @@
         return "amd64".equals(System.getProperty("os.arch"));
     }
 
-    private static ThreadLocal<SomeArgs> sIdentity$ravenwood;
+    private static volatile ThreadLocal<SomeArgs> sIdentity$ravenwood;
 
     /** @hide */
     @android.ravenwood.annotation.RavenwoodKeep
@@ -1589,7 +1589,15 @@
     @UnsupportedAppUsage
     public static final native long getPss(int pid);
 
-    /** @hide */
+    /**
+     * Gets the total Rss value for a given process, in bytes.
+     *
+     * @param pid the process to the Rss for
+     * @return an ordered array containing multiple values, they are:
+     *  [total_rss, file, anon, swap, shmem].
+     *  or NULL if the value cannot be determined
+     * @hide
+     */
     public static final native long[] getRss(int pid);
 
     /**
diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java
index 5e7549f..4b16c1d 100644
--- a/core/java/android/os/TestLooperManager.java
+++ b/core/java/android/os/TestLooperManager.java
@@ -28,6 +28,7 @@
  * The test code may use {@link #next()} to acquire messages that have been queued to this
  * {@link Looper}/{@link MessageQueue} and then {@link #execute} to run any that desires.
  */
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
 public class TestLooperManager {
 
     private static final ArraySet<Looper> sHeldLoopers = new ArraySet<>();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 91ef2fa..d6df8d9 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -107,6 +107,21 @@
     /** Whether the device is in headless system user mode; null until cached. */
     private static Boolean sIsHeadlessSystemUser = null;
 
+    /** Maximum length of username.
+     * @hide
+     */
+    public static final int MAX_USER_NAME_LENGTH = 100;
+
+    /** Maximum length of user property String value.
+     * @hide
+     */
+    public static final int MAX_ACCOUNT_STRING_LENGTH = 500;
+
+    /** Maximum length of account options String values.
+     * @hide
+     */
+    public static final int MAX_ACCOUNT_OPTIONS_LENGTH = 1000;
+
     /**
      * User type representing a {@link UserHandle#USER_SYSTEM system} user that is a human user.
      * This type of user cannot be created; it can only pre-exist on first boot.
@@ -1883,6 +1898,30 @@
             "no_near_field_communication_radio";
 
     /**
+     * This user restriction specifies if Thread network is disallowed on the device. If Thread
+     * network is disallowed it cannot be turned on via Settings.
+     *
+     * <p>This restriction can only be set by a device owner or a profile owner of an
+     * organization-owned managed profile on the parent profile.
+     * In both cases, the restriction applies globally on the device and will turn off the
+     * Thread network radio if it's currently on and prevent the radio from being turned
+     * on in the future.
+     *
+     * <p> <a href="https://www.threadgroup.org">Thread</a> is a low-power and low-latency wireless
+     * mesh networking protocol built on IPv6.
+     *
+     * <p>Default is <code>false</code>.
+     *
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+    public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
+
+    /**
      * List of key values that can be passed into the various user restriction related methods
      * in {@link UserManager} & {@link DevicePolicyManager}.
      * Note: This is slightly different from the real set of user restrictions listed in {@link
@@ -1968,6 +2007,7 @@
             DISALLOW_ULTRA_WIDEBAND_RADIO,
             DISALLOW_GRANT_ADMIN,
             DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
+            DISALLOW_THREAD_NETWORK,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface UserRestrictionKey {}
@@ -4431,15 +4471,15 @@
      * This API should only be called if the current user is an {@link #isAdminUser() admin} user,
      * as otherwise the returned intent will not be able to create a user.
      *
-     * @param userName Optional name to assign to the user.
+     * @param userName Optional name to assign to the user. Character limit is 100.
      * @param accountName Optional account name that will be used by the setup wizard to initialize
-     *                    the user.
+     *                    the user. Character limit is 500.
      * @param accountType Optional account type for the account to be created. This is required
-     *                    if the account name is specified.
+     *                    if the account name is specified. Character limit is 500.
      * @param accountOptions Optional bundle of data to be passed in during account creation in the
      *                       new user via {@link AccountManager#addAccount(String, String, String[],
      *                       Bundle, android.app.Activity, android.accounts.AccountManagerCallback,
-     *                       Handler)}.
+     *                       Handler)}. Character limit is 1000.
      * @return An Intent that can be launched from an Activity.
      * @see #USER_CREATION_FAILED_NOT_PERMITTED
      * @see #USER_CREATION_FAILED_NO_MORE_USERS
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 9587db1..3a57e84 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1669,12 +1669,6 @@
         }
     }
 
-    /** {@hide} */
-    @TestApi
-    public static boolean isUserKeyUnlocked(int userId) {
-        return isCeStorageUnlocked(userId);
-    }
-
     /**
      * Returns true if the user's credential-encrypted (CE) storage is unlocked.
      *
diff --git a/core/java/android/provider/ContactKeysManager.java b/core/java/android/provider/ContactKeysManager.java
new file mode 100644
index 0000000..ecde699
--- /dev/null
+++ b/core/java/android/provider/ContactKeysManager.java
@@ -0,0 +1,1129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.provider;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * ContactKeysManager provides the access to the E2EE contact keys provider.
+ * It manages two types of keys - {@link ContactKey} of other users' and the owner's keys -
+ * {@link SelfKey}.
+ * <ul>
+ * <li>
+ * For {@link ContactKey} this API allows the insert/update, removal, changing of the
+ * verification state, retrieving the keys (either created by or visible to the caller app)
+ * operations.
+ * </li>
+ * <li>
+ * For {@link SelfKey} this API allows the insert/update, removal, retrieving the self keys
+ * (either created by or visible to the caller app) operations.
+ * </li>
+ * </ul>
+ * Keys are uniquely identified by:
+ * <ul>
+ * <li>
+ * ownerPackageName - package name of an app that the key belongs to.
+ * </li>
+ * <li>
+ * deviceId - an app-specified identifier for the device, defined by the app. Within that app,
+ * the deviceID should be unique among devices belonging to that user.
+ * </li>
+ * <li>
+ * accountId - the app-specified identifier for the account for which the contact key can be used.
+ * Usually a phone number.
+ * </li>
+ * </ul>
+ * Contact keys also use lookupKey which is an opaque value used to identify a contact in
+ * ContactsProvider.
+ */
+@FlaggedApi(Flags.FLAG_USER_KEYS)
+public class ContactKeysManager {
+    /**
+     * The authority for the contact keys provider.
+     * @hide
+     */
+    public static final String AUTHORITY = "com.android.contactkeys.contactkeysprovider";
+
+    /**
+     * A content:// style uri to the authority for the contact keys provider.
+     * @hide
+     */
+    @NonNull
+    public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+    /**
+     * Maximum size of a contact key.
+     */
+    private static final int MAX_KEY_SIZE_BYTES = 5000;
+
+    /**
+     * Special value to distinguish a null array in a parcelable object.
+     */
+    private static final int ARRAY_IS_NULL = -1;
+
+    @NonNull
+    private final ContentResolver mContentResolver;
+
+    /** @hide */
+    public ContactKeysManager(@NonNull Context context) {
+        Objects.requireNonNull(context);
+        mContentResolver = context.getContentResolver();
+    }
+
+    /**
+     * Inserts a new entry into the contact keys table or updates one if it already exists.
+     * The inserted/updated contact key is owned by the caller app.
+     *
+     * @param lookupKey value that references the contact
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     * @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
+     */
+    @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+    public void updateOrInsertContactKey(@NonNull String lookupKey,
+            @NonNull String deviceId,
+            @NonNull String accountId,
+            @NonNull byte[] keyValue) {
+        validateKeyLength(keyValue);
+
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
+
+        nullSafeCall(mContentResolver,
+                ContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras);
+    }
+
+    /**
+     * Retrieves a contact key entry given the lookup key, device ID, accountId and inferred
+     * caller package name.
+     *
+     * @param lookupKey the value that references the contact
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     *
+     * @return a {@link ContactKey} object containing the contact key information,
+     * or null if no contact key is found.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+    @Nullable
+    public ContactKey getContactKey(
+            @NonNull String lookupKey,
+            @NonNull String deviceId,
+            @NonNull String accountId) {
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.GET_CONTACT_KEY_METHOD, extras);
+
+        if (response == null) {
+            return null;
+        }
+        return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, ContactKey.class);
+    }
+
+    /**
+     * Retrieves all contact key entries that belong to apps visible to the caller.
+     * The keys will be stripped of deviceId, timeUpdated and keyValue data.
+     *
+     * @param lookupKey the value that references the contact
+     *
+     * @return a list of {@link ContactKey} objects containing the contact key
+     * information, or an empty list if no keys are found.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+    @NonNull
+    public List<ContactKey> getAllContactKeys(@NonNull String lookupKey) {
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras);
+
+        if (response == null) {
+            return new ArrayList<>();
+        }
+        List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
+                ContactKey.class);
+        if (value == null) {
+            return new ArrayList<>();
+        }
+        return value;
+    }
+
+    /**
+     * Retrieves all contact key entries for a given lookupKey that belong to the caller app.
+     *
+     * @param lookupKey the value that references the contact
+     *
+     * @return a list of {@link ContactKey} objects containing the contact key
+     * information, or an empty list if no keys are found.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+    @NonNull
+    public List<ContactKey> getOwnerContactKeys(@NonNull String lookupKey) {
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras);
+
+        if (response == null) {
+            return new ArrayList<>();
+        }
+        List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
+                ContactKey.class);
+        if (value == null) {
+            return new ArrayList<>();
+        }
+        return value;
+    }
+
+    /**
+     * Updates a contact key entry's local verification state that belongs to the caller app.
+     *
+     * @param lookupKey the value that references the contact
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     * @param localVerificationState the new local verification state
+     *
+     * @return true if the entry was updated, false otherwise.
+     */
+    @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+    public boolean updateContactKeyLocalVerificationState(@NonNull String lookupKey,
+            @NonNull String deviceId,
+            @NonNull String accountId,
+            @VerificationState int localVerificationState) {
+        validateVerificationState(localVerificationState);
+
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(ContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
+
+        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+    }
+
+    /**
+     * Updates a contact key entry's remote verification state that belongs to the caller app.
+     *
+     * @param lookupKey the value that references the contact
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     * @param remoteVerificationState the new remote verification state
+     *
+     * @return true if the entry was updated, false otherwise.
+     */
+    @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+    public boolean updateContactKeyRemoteVerificationState(@NonNull String lookupKey,
+            @NonNull String deviceId,
+            @NonNull String accountId,
+            @VerificationState int remoteVerificationState) {
+        validateVerificationState(remoteVerificationState);
+
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+
+        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+    }
+
+    private static void validateVerificationState(int verificationState) {
+        if (verificationState != UNVERIFIED
+                && verificationState != VERIFICATION_FAILED
+                && verificationState != VERIFIED) {
+            throw new IllegalArgumentException("Verification state value "
+                    + verificationState + " is not supported");
+        }
+    }
+
+    /**
+     * Removes a contact key entry that belongs to the caller app.
+     *
+     * @param lookupKey the value that references the contact
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     *
+     * @return true if the entry was removed, false otherwise.
+     */
+    @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+    public boolean removeContactKey(@NonNull String lookupKey,
+            @NonNull String deviceId,
+            @NonNull String accountId) {
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.REMOVE_CONTACT_KEY_METHOD, extras);
+
+        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+    }
+
+    /**
+     * Inserts a new entry into the self keys table or updates one if it already exists.
+
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     * @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
+     *
+     * @return true if the entry was added or updated, false otherwise.
+     */
+    @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+    public boolean updateOrInsertSelfKey(@NonNull String deviceId,
+            @NonNull String accountId,
+            @NonNull byte[] keyValue) {
+        validateKeyLength(keyValue);
+
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras);
+
+        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+    }
+
+    private static void validateKeyLength(byte[] keyValue) {
+        Objects.requireNonNull(keyValue);
+        if (keyValue.length == 0 || keyValue.length > getMaxKeySizeBytes()) {
+            throw new IllegalArgumentException("Key value length is " + keyValue.length + "."
+                    + " Should be more than 0 and less than " + getMaxKeySizeBytes());
+        }
+    }
+
+    /**
+     * Updates a self key entry's remote verification state.
+     *
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     * @param remoteVerificationState the new remote verification state
+     *
+     * @return true if the entry was updated, false otherwise.
+     */
+    @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+    public boolean updateSelfKeyRemoteVerificationState(@NonNull String deviceId,
+            @NonNull String accountId,
+            @VerificationState int remoteVerificationState) {
+        validateVerificationState(remoteVerificationState);
+
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+
+        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+    }
+
+    /**
+     * Maximum size of a contact key.
+     */
+    public static int getMaxKeySizeBytes() {
+        return MAX_KEY_SIZE_BYTES;
+    }
+
+    /**
+     * Returns a self key entry given the deviceId and the inferred package name of the caller.
+     *
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     *
+     * @return a {@link SelfKey} object containing the self key information, or null if no self key
+     * is found.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+    @Nullable
+    public SelfKey getSelfKey(@NonNull String deviceId,
+            @NonNull String accountId) {
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.GET_SELF_KEY_METHOD, extras);
+
+        if (response == null) {
+            return null;
+        }
+        return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, SelfKey.class);
+    }
+
+    /**
+     * Returns all self key entries that belong to apps visible to the caller.
+     * The keys will be stripped of deviceId, timeUpdated and keyValue data.
+     *
+     * @return a list of {@link SelfKey} objects containing the self key information, or
+     * an empty list if no keys are found.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+    @NonNull
+    public List<SelfKey> getAllSelfKeys() {
+        Bundle extras = new Bundle();
+
+        Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_ALL_SELF_KEYS_METHOD,
+                extras);
+
+        if (response == null) {
+            return new ArrayList<>();
+        }
+        List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
+                SelfKey.class);
+        if (value == null) {
+            return new ArrayList<>();
+        }
+        return value;
+    }
+
+    /**
+     * Returns all self key entries that are owned by the caller app.
+     *
+     * @return a list of {@link SelfKey} objects containing the self key information, or
+     * an empty list if no keys are found.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+    @NonNull
+    public List<SelfKey> getOwnerSelfKeys() {
+        Bundle extras = new Bundle();
+
+        Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_OWNER_SELF_KEYS_METHOD,
+                extras);
+
+        if (response == null) {
+            return new ArrayList<>();
+        }
+        List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
+                SelfKey.class);
+        if (value == null) {
+            return new ArrayList<>();
+        }
+        return value;
+    }
+
+    /**
+     * Removes a self key entry given the deviceId and the inferred package name of the caller.
+
+     * @param deviceId an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     *
+     * @return true if the entry was removed, false otherwise.
+     */
+    @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+    public boolean removeSelfKey(@NonNull String deviceId,
+            @NonNull String accountId) {
+        Bundle extras = new Bundle();
+        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+
+        Bundle response = nullSafeCall(mContentResolver,
+                ContactKeys.REMOVE_SELF_KEY_METHOD, extras);
+
+        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+    }
+
+    private Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull String method,
+            @Nullable Bundle extras) {
+        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY_URI)) {
+            return client.call(method, null, extras);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Possible values of verification state.
+     * @hide
+     */
+    @IntDef(prefix = {"VERIFICATION_STATE_"}, value = {
+            UNVERIFIED,
+            VERIFICATION_FAILED,
+            VERIFIED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VerificationState {}
+
+    /**
+     * Unverified state of a contact E2EE key.
+     */
+    public static final int UNVERIFIED = 0;
+    /**
+     * Failed verification state of a contact E2EE key.
+     */
+    public static final int VERIFICATION_FAILED = 1;
+    /**
+     * Verified state of a contact E2EE key.
+     */
+    public static final int VERIFIED = 2;
+
+    /** @hide */
+    public static final class ContactKeys {
+
+        private ContactKeys() {}
+
+        /**
+         * <p>
+         * An opaque value that contains hints on how to find the contact if
+         * its row id changed as a result of a sync or aggregation.
+         * </p>
+         */
+        public static final String LOOKUP_KEY = "lookup";
+
+        /**
+         * <p>
+         * An app-specified identifier for the device for which the contact key can be used.
+         * </p>
+         */
+        public static final String DEVICE_ID = "device_id";
+
+        /**
+         * <p>
+         * An app-specified identifier for the account for which the contact key can be used.
+         * Usually a phone number.
+         * </p>
+         */
+        public static final String ACCOUNT_ID = "account_id";
+
+        /**
+         * <p>
+         * The display name for the contact.
+         * </p>
+         */
+        public static final String DISPLAY_NAME = "display_name";
+
+        /**
+         * <p>
+         * The phone number as the user entered it.
+         * </p>
+         */
+        public static final String PHONE_NUMBER = "number";
+
+        /**
+         * <p>
+         * The email address.
+         * </p>
+         */
+        public static final String EMAIL_ADDRESS = "address";
+
+        /**
+         * <p>
+         * Timestamp at which the key was updated.
+         * </p>
+         */
+        public static final String TIME_UPDATED = "time_updated";
+
+        /**
+         * <p>
+         * The raw bytes for the key.
+         * </p>
+         */
+        public static final String KEY_VALUE = "key_value";
+
+        /**
+         * <p>
+         * The package name of the package that created the key.
+         * </p>
+         */
+        public static final String OWNER_PACKAGE_NAME = "owner_package_name";
+
+        /**
+         * <p>
+         * Describes the local verification state for the key, for instance QR-code based
+         * verification.
+         * </p>
+         */
+        public static final String LOCAL_VERIFICATION_STATE = "local_verification_state";
+
+        /**
+         * <p>
+         * Describes the remote verification state for the key, for instance through a key
+         * transparency server.
+         * </p>
+         */
+        public static final String REMOTE_VERIFICATION_STATE = "remote_verification_state";
+
+        /**
+         * The method to invoke in order to add a new key for a contact.
+         */
+        public static final String UPDATE_OR_INSERT_CONTACT_KEY_METHOD = "updateOrInsertContactKey";
+
+        /**
+         * The method to invoke in order to retrieve key for a single contact.
+         */
+        public static final String GET_CONTACT_KEY_METHOD = "getContactKey";
+
+        /**
+         * The method to invoke in order to retrieve all contact keys.
+         */
+        public static final String GET_ALL_CONTACT_KEYS_METHOD = "getAllContactKeys";
+
+        /**
+         * The method to invoke in order to retrieve contact keys that belong to the caller.
+         */
+        public static final String GET_OWNER_CONTACT_KEYS_METHOD = "getOwnerContactKeys";
+
+        /**
+         * The method to invoke in order to update a contact key local verification state.
+         */
+        public static final String UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD =
+                "updateContactKeyLocalVerificationState";
+
+        /**
+         * The method to invoke in order to update a contact key remote verification state.
+         */
+        public static final String UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD =
+                "updateContactKeyRemoteVerificationState";
+
+        /**
+         * The method to invoke in order to remove a contact key.
+         */
+        public static final String REMOVE_CONTACT_KEY_METHOD = "removeContactKey";
+
+        /**
+         * The method to invoke in order to add a new self key.
+         */
+        public static final String UPDATE_OR_INSERT_SELF_KEY_METHOD = "updateOrInsertSelfKey";
+
+        /**
+         * The method to invoke in order to update a self key remote verification state.
+         */
+        public static final String UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD =
+                "updateSelfKeyRemoteVerificationState";
+
+        /**
+         * The method to invoke in order to retrieve a self key.
+         */
+        public static final String GET_SELF_KEY_METHOD = "getSelfKey";
+
+        /**
+         * The method to invoke in order to retrieve all self keys.
+         */
+        public static final String GET_ALL_SELF_KEYS_METHOD = "getAllSelfKeys";
+
+        /**
+         * The method to invoke in order to retrieve self keys that belong to the caller.
+         */
+        public static final String GET_OWNER_SELF_KEYS_METHOD = "getOwnerSelfKeys";
+
+        /**
+         * The method to invoke in order to remove a new self key.
+         */
+        public static final String REMOVE_SELF_KEY_METHOD = "removeSelfKey";
+
+        /**
+         * Key in the incoming Bundle for all the contact keys.
+         */
+        public static final String KEY_CONTACT_KEYS = "key_contact_keys";
+
+        /**
+         * Key in the incoming Bundle for a single contact key.
+         */
+        public static final String KEY_CONTACT_KEY = "key_contact_key";
+
+        /**
+         * Key in the incoming Bundle for a number of modified rows.
+         */
+        public static final String KEY_UPDATED_ROWS = "key_updated_rows";
+    }
+
+    /**
+     * A parcelable class encapsulating other users' E2EE contact key.
+     */
+    public static final class ContactKey implements Parcelable {
+        /**
+         * An app-specified identifier for the device for which the contact key can be used.
+         */
+        private final String mDeviceId;
+
+        /**
+         * An app-specified identifier for the account for which the contact key can be used.
+         * Usually a phone number.
+         */
+        private final String mAccountId;
+
+        /**
+         * Owner application package name.
+         */
+        private final String mOwnerPackageName;
+
+        /**
+         * Timestamp at which the key was updated.
+         */
+        private final long mTimeUpdated;
+
+        /**
+         * The raw bytes for the key.
+         */
+        private final byte[] mKeyValue;
+
+        /**
+         * Describes the local verification state for the key, for instance QR-code based
+         * verification.
+         */
+        private final int mLocalVerificationState;
+
+        /**
+         * Describes the remote verification state for the key, for instance through a key
+         * transparency server.
+         */
+        private final int mRemoteVerificationState;
+
+        /**
+         * The display name for the contact.
+         */
+        private final String mDisplayName;
+
+        /**
+         * The phone number as the user entered it.
+         */
+        private final String mPhoneNumber;
+
+        /**
+         * The email address.
+         */
+        private final String mEmailAddress;
+
+        /**
+         * @hide
+         */
+        public ContactKey(@Nullable String deviceId, @NonNull String accountId,
+                @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
+                @VerificationState int localVerificationState,
+                @VerificationState int remoteVerificationState,
+                @Nullable String displayName,
+                @Nullable String phoneNumber, @Nullable String emailAddress) {
+            this.mDeviceId = deviceId;
+            this.mAccountId = accountId;
+            this.mOwnerPackageName = ownerPackageName;
+            this.mTimeUpdated = timeUpdated;
+            this.mKeyValue = keyValue == null ? null : Arrays.copyOf(keyValue, keyValue.length);
+            this.mLocalVerificationState = localVerificationState;
+            this.mRemoteVerificationState = remoteVerificationState;
+            this.mDisplayName = displayName;
+            this.mPhoneNumber = phoneNumber;
+            this.mEmailAddress = emailAddress;
+        }
+
+        /**
+         * Gets the app-specified identifier for the device for which the contact key can be used.
+         * Returns null if the app doesn't have the required visibility into the contact key.
+         *
+         * @return An app-specified identifier for the device.
+         */
+        @Nullable
+        public String getDeviceId() {
+            return mDeviceId;
+        }
+
+        /**
+         * Gets the app-specified identifier for the account for which the contact key can be used.
+         * Usually a phone number.
+         *
+         * @return An app-specified identifier for the account.
+         */
+        @NonNull
+        public String getAccountId() {
+            return mAccountId;
+        }
+
+        /**
+         * Gets the owner application package name.
+         *
+         * @return The owner application package name.
+         */
+        @NonNull
+        public String getOwnerPackageName() {
+            return mOwnerPackageName;
+        }
+
+        /**
+         * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the
+         * required visibility into the contact key.
+         *
+         * @return The timestamp at which the key was updated in the System.currentTimeMillis()
+         * base.
+         */
+        public long getTimeUpdated() {
+            return mTimeUpdated;
+        }
+
+        /**
+         * Gets the raw bytes for the key.
+         * Returns null if the app doesn't have the required visibility into the contact key.
+         *
+         * @return A copy of the raw bytes for the key.
+         */
+        @Nullable
+        public byte[] getKeyValue() {
+            return mKeyValue == null ? null : Arrays.copyOf(mKeyValue, mKeyValue.length);
+        }
+
+        /**
+         * Gets the local verification state for the key, for instance QR-code based verification.
+         *
+         * @return The local verification state for the key.
+         */
+        public @VerificationState int getLocalVerificationState() {
+            return mLocalVerificationState;
+        }
+
+        /**
+         * Gets the remote verification state for the key, for instance through a key transparency
+         * server.
+         *
+         * @return The remote verification state for the key.
+         */
+        public @VerificationState int getRemoteVerificationState() {
+            return mRemoteVerificationState;
+        }
+
+        /**
+         * Gets the display name for the contact.
+         *
+         * @return The display name for the contact.
+         */
+        @Nullable
+        public String getDisplayName() {
+            return mDisplayName;
+        }
+
+        /**
+         * Gets the phone number as the user entered it.
+         *
+         * @return The phone number as the user entered it.
+         */
+        @Nullable
+        public String getPhoneNumber() {
+            return mPhoneNumber;
+        }
+
+        /**
+         * Gets the email address.
+         *
+         * @return The email address.
+         */
+        @Nullable
+        public String getEmailAddress() {
+            return mEmailAddress;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mDeviceId, mAccountId, mOwnerPackageName, mTimeUpdated,
+                    Arrays.hashCode(mKeyValue), mLocalVerificationState, mRemoteVerificationState,
+                    mDisplayName, mPhoneNumber, mEmailAddress);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) return false;
+            if (obj == this) return true;
+
+            if (!(obj instanceof ContactKey toCompare)) {
+                return false;
+            }
+
+            return Objects.equals(mDeviceId, toCompare.mDeviceId)
+                    && Objects.equals(mAccountId, toCompare.mAccountId)
+                    && Objects.equals(mOwnerPackageName, toCompare.mOwnerPackageName)
+                    && mTimeUpdated == toCompare.mTimeUpdated
+                    && Arrays.equals(mKeyValue, toCompare.mKeyValue)
+                    && mLocalVerificationState == toCompare.mLocalVerificationState
+                    && mRemoteVerificationState == toCompare.mRemoteVerificationState
+                    && Objects.equals(mDisplayName, toCompare.mDisplayName)
+                    && Objects.equals(mPhoneNumber, toCompare.mPhoneNumber)
+                    && Objects.equals(mEmailAddress, toCompare.mEmailAddress);
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeString8(mDeviceId);
+            dest.writeString8(mAccountId);
+            dest.writeString8(mOwnerPackageName);
+            dest.writeLong(mTimeUpdated);
+            dest.writeInt(mKeyValue != null ? mKeyValue.length : ARRAY_IS_NULL);
+            if (mKeyValue != null) {
+                dest.writeByteArray(mKeyValue);
+            }
+            dest.writeInt(mLocalVerificationState);
+            dest.writeInt(mRemoteVerificationState);
+            dest.writeString8(mDisplayName);
+            dest.writeString8(mPhoneNumber);
+            dest.writeString8(mEmailAddress);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @NonNull
+        public static final Creator<ContactKey> CREATOR =
+                new Creator<>() {
+                    @Override
+                    public ContactKey createFromParcel(Parcel source) {
+                        String deviceId = source.readString8();
+                        String accountId = source.readString8();
+                        String ownerPackageName = source.readString8();
+                        long timeUpdated = source.readLong();
+                        int keyValueLength = source.readInt();
+                        byte[] keyValue;
+                        if (keyValueLength > 0) {
+                            keyValue = new byte[keyValueLength];
+                            source.readByteArray(keyValue);
+                        } else {
+                            keyValue = null;
+                        }
+                        int localVerificationState = source.readInt();
+                        int remoteVerificationState = source.readInt();
+                        String displayName = source.readString8();
+                        String number = source.readString8();
+                        String address = source.readString8();
+                        return new ContactKey(deviceId, accountId, ownerPackageName,
+                                timeUpdated, keyValue, localVerificationState,
+                                remoteVerificationState, displayName, number, address);
+                    }
+
+                    @Override
+                    public ContactKey[] newArray(int size) {
+                        return new ContactKey[size];
+                    }
+                };
+    }
+
+    /**
+     * A parcelable class encapsulating self E2EE contact key.
+     */
+    public static final class SelfKey implements Parcelable {
+        /**
+         * An app-specified identifier for the device for which the contact key can be used.
+         */
+        private final String mDeviceId;
+
+        /**
+         * An app-specified identifier for the account for which the contact key can be used.
+         * Usually a phone number.
+         */
+        private final String mAccountId;
+
+        /**
+         * Owner application package name.
+         */
+        private final String mOwnerPackageName;
+
+        /**
+         * Timestamp at which the key was updated.
+         */
+        private final long mTimeUpdated;
+
+        /**
+         * The raw bytes for the key.
+         */
+        private final byte[] mKeyValue;
+
+
+        /**
+         * Describes the remote verification state for the key, for instance through a key
+         * transparency server.
+         */
+        private final int mRemoteVerificationState;
+
+        /**
+         * @hide
+         */
+        public SelfKey(@Nullable String deviceId, @NonNull String accountId,
+                @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
+                @VerificationState int remoteVerificationState) {
+            this.mDeviceId = deviceId;
+            this.mAccountId = accountId;
+            this.mOwnerPackageName = ownerPackageName;
+            this.mTimeUpdated = timeUpdated;
+            this.mKeyValue = keyValue == null ? null : Arrays.copyOf(keyValue, keyValue.length);
+            this.mRemoteVerificationState = remoteVerificationState;
+        }
+
+        /**
+         * Gets the app-specified identifier for the device for which the contact key can be used.
+         * Returns null if the app doesn't have the required visibility into the contact key.
+         *
+         * @return An app-specified identifier for the device.
+         */
+        @Nullable
+        public String getDeviceId() {
+            return mDeviceId;
+        }
+
+        /**
+         * Gets the app-specified identifier for the account for which the contact key can be used.
+         * Usually a phone number.
+         *
+         * @return An app-specified identifier for the device.
+         */
+        @NonNull
+        public String getAccountId() {
+            return mAccountId;
+        }
+
+        /**
+         * Gets the owner application package name.
+         *
+         * @return The owner application package name.
+         */
+        @NonNull
+        public String getOwnerPackageName() {
+            return mOwnerPackageName;
+        }
+
+        /**
+         * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the
+         * required visibility into the contact key.
+         *
+         * @return The timestamp at which the key was updated in the System.currentTimeMillis()
+         * base.
+         */
+        public long getTimeUpdated() {
+            return mTimeUpdated;
+        }
+
+        /**
+         * Gets the raw bytes for the key.
+         * Returns null if the app doesn't have the required visibility into the contact key.
+         *
+         * @return A copy of the raw bytes for the key.
+         */
+        @Nullable
+        public byte[] getKeyValue() {
+            return mKeyValue == null ? null : Arrays.copyOf(mKeyValue, mKeyValue.length);
+        }
+
+        /**
+         * Gets the remote verification state for the key, for instance through a key transparency
+         * server.
+         *
+         * @return The remote verification state for the key.
+         */
+        public @VerificationState int getRemoteVerificationState() {
+            return mRemoteVerificationState;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mDeviceId, mAccountId, mOwnerPackageName, mTimeUpdated,
+                    Arrays.hashCode(mKeyValue), mRemoteVerificationState);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) return false;
+            if (obj == this) return true;
+
+            if (!(obj instanceof SelfKey toCompare)) {
+                return false;
+            }
+
+            return Objects.equals(mDeviceId, toCompare.mDeviceId)
+                    && Objects.equals(mAccountId, toCompare.mAccountId)
+                    && Objects.equals(mOwnerPackageName, toCompare.mOwnerPackageName)
+                    && mTimeUpdated == toCompare.mTimeUpdated
+                    && Arrays.equals(mKeyValue, toCompare.mKeyValue)
+                    && mRemoteVerificationState == toCompare.mRemoteVerificationState;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeString8(mDeviceId);
+            dest.writeString8(mAccountId);
+            dest.writeString8(mOwnerPackageName);
+            dest.writeLong(mTimeUpdated);
+            dest.writeInt(mKeyValue != null ? mKeyValue.length : ARRAY_IS_NULL);
+            if (mKeyValue != null) {
+                dest.writeByteArray(mKeyValue);
+            }
+            dest.writeInt(mRemoteVerificationState);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @NonNull
+        public static final Creator<SelfKey> CREATOR =
+                new Creator<>() {
+                    @Override
+                    public SelfKey createFromParcel(Parcel source) {
+                        String deviceId = source.readString8();
+                        String accountId = source.readString8();
+                        String ownerPackageName = source.readString8();
+                        long timeUpdated = source.readLong();
+                        int keyValueLength = source.readInt();
+                        byte[] keyValue;
+                        if (keyValueLength > 0) {
+                            keyValue = new byte[keyValueLength];
+                            source.readByteArray(keyValue);
+                        } else {
+                            keyValue = null;
+                        }
+                        int remoteVerificationState = source.readInt();
+                        return new SelfKey(deviceId, accountId, ownerPackageName,
+                                timeUpdated, keyValue, remoteVerificationState);
+                    }
+
+                    @Override
+                    public SelfKey[] newArray(int size) {
+                        return new SelfKey[size];
+                    }
+                };
+    }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ecd6f22..e238080 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -444,6 +444,18 @@
             "android.settings.ACCESSIBILITY_DETAILS_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of an accessibility
+     * shortcut belonging to an accessibility feature or features.
+     * <p>
+     * Input: ":settings:show_fragment_args" must contain "targets" denoting the services to edit.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     **/
+    public static final String ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS =
+            "android.settings.ACCESSIBILITY_SHORTCUT_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of accessibility color and motion.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -4513,10 +4525,11 @@
         /** @hide */
         public static void adjustConfigurationForUser(ContentResolver cr, Configuration outConfig,
                 int userHandle, boolean updateSettingsIfEmpty) {
+            final float defaultFontScale = getDefaultFontScale(cr, userHandle);
             outConfig.fontScale = Settings.System.getFloatForUser(
-                    cr, FONT_SCALE, DEFAULT_FONT_SCALE, userHandle);
+                    cr, FONT_SCALE, defaultFontScale, userHandle);
             if (outConfig.fontScale < 0) {
-                outConfig.fontScale = DEFAULT_FONT_SCALE;
+                outConfig.fontScale = defaultFontScale;
             }
             outConfig.fontWeightAdjustment = Settings.Secure.getIntForUser(
                     cr, Settings.Secure.FONT_WEIGHT_ADJUSTMENT, DEFAULT_FONT_WEIGHT, userHandle);
@@ -4541,6 +4554,12 @@
             }
         }
 
+        private static float getDefaultFontScale(ContentResolver cr, int userHandle) {
+            return com.android.window.flags.Flags.configurableFontScaleDefault()
+                    ? Settings.System.getFloatForUser(cr, DEFAULT_DEVICE_FONT_SCALE,
+                    DEFAULT_FONT_SCALE, userHandle) : DEFAULT_FONT_SCALE;
+        }
+
         /**
          * @hide Erase the fields in the Configuration that should be applied
          * by the settings.
@@ -4907,6 +4926,16 @@
         public static final String FONT_SCALE = "font_scale";
 
         /**
+         * Default scaling factor for fonts for the specific device, float.
+         * The value is read from the {@link R.dimen.def_device_font_scale}
+         * configuration property.
+         *
+         * @hide
+         */
+        @Readable
+        public static final String DEFAULT_DEVICE_FONT_SCALE = "device_font_scale";
+
+        /**
          * The serialized system locale value.
          *
          * Do not use this value directory.
@@ -6245,6 +6274,7 @@
             PRIVATE_SETTINGS.add(CAMERA_FLASH_NOTIFICATION);
             PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION);
             PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION_COLOR);
+            PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE);
         }
 
         /**
@@ -7881,6 +7911,17 @@
         public static final String ACCESSIBILITY_BOUNCE_KEYS = "accessibility_bounce_keys";
 
         /**
+         * Whether to enable slow keys for Physical Keyboard accessibility.
+         *
+         * If set to non-zero value, any key press on physical keyboard needs to be pressed and
+         * held for the provided threshold duration (in milliseconds) to be registered in the
+         * system.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SLOW_KEYS = "accessibility_slow_keys";
+
+        /**
          * Whether to enable sticky keys for Physical Keyboard accessibility.
          *
          * This is a boolean value that determines if Sticky keys feature is enabled.
@@ -12276,6 +12317,8 @@
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
             CLONE_TO_MANAGED_PROFILE.add(SHOW_IME_WITH_HARD_KEYBOARD);
             CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_BOUNCE_KEYS);
+            CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_SLOW_KEYS);
+            CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_STICKY_KEYS);
             CLONE_TO_MANAGED_PROFILE.add(NOTIFICATION_BUBBLES);
             CLONE_TO_MANAGED_PROFILE.add(NOTIFICATION_HISTORY_ENABLED);
         }
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index d47ff2e..af688e9 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4927,7 +4927,7 @@
         /**
          * TelephonyProvider column name for satellite attach enabled for carrier. The value of this
          * column is set based on user settings.
-         * By default, it's disabled.
+         * By default, it's enabled.
          *
          * @hide
          */
diff --git a/core/java/android/provider/flags.aconfig b/core/java/android/provider/flags.aconfig
index 3dd7692..0f12b13 100644
--- a/core/java/android/provider/flags.aconfig
+++ b/core/java/android/provider/flags.aconfig
@@ -6,3 +6,10 @@
     description: "Enable Settings.System.resetToDefault APIs."
     bug: "279083734"
 }
+
+flag {
+    name: "user_keys"
+    namespace: "privacy_infra_policy"
+    description: "This flag controls new E2EE contact keys API"
+    bug: "290696572"
+}
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index fe6c4a4..0bae459 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -27,3 +27,17 @@
     description: "Enables the content URI permission APIs"
     bug: "293467489"
 }
+
+flag {
+    name: "enforce_intent_filter_match"
+    namespace: "responsible_apis"
+    description: "Make delivered intents match components' intent filters"
+    bug: "293560872"
+}
+
+flag {
+    name: "block_null_action_intents"
+    namespace: "responsible_apis"
+    description: "Do not allow intents without an action to match any intent filters"
+    bug: "293560872"
+}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 5ad2502..298bdb8 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -622,6 +622,15 @@
                     new FillCallback(callback, request.getId())));
         }
 
+        @Override
+        public void onConvertCredentialRequest(
+                @NonNull ConvertCredentialRequest convertCredentialRequest,
+                @NonNull IConvertCredentialCallback convertCredentialCallback) {
+            mHandler.sendMessage(obtainMessage(
+                    AutofillService::onConvertCredentialRequest,
+                    AutofillService.this, convertCredentialRequest,
+                    new ConvertCredentialCallback(convertCredentialCallback)));
+        }
 
         @Override
         public void onFillCredentialRequest(FillRequest request, IFillCallback callback,
@@ -707,7 +716,19 @@
      */
     public void onFillCredentialRequest(@NonNull FillRequest request,
             @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback,
-            IAutoFillManagerClient autofillClientCallback) {}
+            @NonNull IAutoFillManagerClient autofillClientCallback) {}
+
+    /**
+     * Called by the Android system to convert a credential manager response to a dataset
+     *
+     * @param convertCredentialRequest the request that has the original credential manager response
+     * @param convertCredentialCallback callback used to notify the result of the request.
+     *
+     * @hide
+     */
+    public void onConvertCredentialRequest(
+            @NonNull ConvertCredentialRequest convertCredentialRequest,
+            @NonNull ConvertCredentialCallback convertCredentialCallback){}
 
     /**
      * Called when the user requests the service to save the contents of a screen.
diff --git a/core/java/android/service/autofill/ConvertCredentialCallback.java b/core/java/android/service/autofill/ConvertCredentialCallback.java
new file mode 100644
index 0000000..a39f011
--- /dev/null
+++ b/core/java/android/service/autofill/ConvertCredentialCallback.java
@@ -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 android.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+
+/**
+ * <p><code>ConvertCredentialCallback</code> handles convertCredentialResponse from Autofill
+ * Service.
+ *
+ * @hide
+ */
+public final class ConvertCredentialCallback {
+
+    private static final String TAG = "ConvertCredentialCallback";
+
+    private final IConvertCredentialCallback mCallback;
+
+    /** @hide */
+    public ConvertCredentialCallback(IConvertCredentialCallback callback) {
+        mCallback = callback;
+    }
+
+    /**
+     * Notifies the Android System that a convertCredentialRequest was fulfilled by the service.
+     *
+     * @param convertCredentialResponse the result
+     */
+    public void onSuccess(@NonNull ConvertCredentialResponse convertCredentialResponse) {
+        try {
+            mCallback.onSuccess(convertCredentialResponse);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Notifies the Android System that a convert credential request has failed
+     *
+     * @param message the error message
+     */
+    public void onFailure(@Nullable CharSequence message) {
+        try {
+            mCallback.onFailure(message);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+}
diff --git a/core/java/android/credentials/ui/UiResult.java b/core/java/android/service/autofill/ConvertCredentialRequest.aidl
similarity index 68%
copy from core/java/android/credentials/ui/UiResult.java
copy to core/java/android/service/autofill/ConvertCredentialRequest.aidl
index 692584d..79681e2 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/core/java/android/service/autofill/ConvertCredentialRequest.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2024 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.
  * 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,
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.service.autofill;
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+parcelable ConvertCredentialRequest;
\ No newline at end of file
diff --git a/core/java/android/service/autofill/ConvertCredentialRequest.java b/core/java/android/service/autofill/ConvertCredentialRequest.java
new file mode 100644
index 0000000..d2d7556
--- /dev/null
+++ b/core/java/android/service/autofill/ConvertCredentialRequest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.service.autofill;
+
+import android.annotation.NonNull;
+import android.credentials.GetCredentialResponse;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+
+/**
+ * This class represents a request to an autofill service to convert the credential manager response
+ * to a dataset.
+ *
+ * @hide
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = true,
+        genHiddenConstDefs = true)
+public final class ConvertCredentialRequest implements Parcelable {
+    private final @NonNull GetCredentialResponse mGetCredentialResponse;
+    private final @NonNull Bundle mClientState;
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/ConvertCredentialRequest.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new ConvertCredentialRequest.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public ConvertCredentialRequest(
+            @NonNull GetCredentialResponse getCredentialResponse,
+            @NonNull Bundle clientState) {
+        this.mGetCredentialResponse = getCredentialResponse;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mGetCredentialResponse);
+        this.mClientState = clientState;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mClientState);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull GetCredentialResponse getGetCredentialResponse() {
+        return mGetCredentialResponse;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull Bundle getClientState() {
+        return mClientState;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ConvertCredentialRequest { " +
+                "getCredentialResponse = " + mGetCredentialResponse + ", " +
+                "clientState = " + mClientState +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mGetCredentialResponse, flags);
+        dest.writeBundle(mClientState);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ ConvertCredentialRequest(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        GetCredentialResponse getCredentialResponse = (GetCredentialResponse) in.readTypedObject(GetCredentialResponse.CREATOR);
+        Bundle clientState = in.readBundle();
+
+        this.mGetCredentialResponse = getCredentialResponse;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mGetCredentialResponse);
+        this.mClientState = clientState;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mClientState);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ConvertCredentialRequest> CREATOR
+            = new Parcelable.Creator<ConvertCredentialRequest>() {
+        @Override
+        public ConvertCredentialRequest[] newArray(int size) {
+            return new ConvertCredentialRequest[size];
+        }
+
+        @Override
+        public ConvertCredentialRequest createFromParcel(@NonNull Parcel in) {
+            return new ConvertCredentialRequest(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1706132305002L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/service/autofill/ConvertCredentialRequest.java",
+            inputSignatures = "private final @android.annotation.NonNull android.credentials.GetCredentialResponse mGetCredentialResponse\nprivate final @android.annotation.NonNull android.os.Bundle mClientState\nclass ConvertCredentialRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/credentials/ui/UiResult.java b/core/java/android/service/autofill/ConvertCredentialResponse.aidl
similarity index 68%
copy from core/java/android/credentials/ui/UiResult.java
copy to core/java/android/service/autofill/ConvertCredentialResponse.aidl
index 692584d..98ac6f6 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/core/java/android/service/autofill/ConvertCredentialResponse.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2024 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.
  * 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,
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.service.autofill;
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+parcelable ConvertCredentialResponse;
\ No newline at end of file
diff --git a/core/java/android/service/autofill/ConvertCredentialResponse.java b/core/java/android/service/autofill/ConvertCredentialResponse.java
new file mode 100644
index 0000000..5da4f63
--- /dev/null
+++ b/core/java/android/service/autofill/ConvertCredentialResponse.java
@@ -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 android.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Response for a {@Link ConvertCredentialRequest}
+ *
+ * @hide
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = true,
+        genHiddenConstDefs = true)
+public final class ConvertCredentialResponse implements Parcelable {
+    private final @NonNull Dataset mDataset;
+    private final @Nullable Bundle mClientState;
+
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/ConvertCredentialResponse.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new ConvertCredentialResponse.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public ConvertCredentialResponse(
+            @NonNull Dataset dataset,
+            @Nullable Bundle clientState) {
+        this.mDataset = dataset;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDataset);
+        this.mClientState = clientState;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull Dataset getDataset() {
+        return mDataset;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable Bundle getClientState() {
+        return mClientState;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ConvertCredentialResponse { " +
+                "dataset = " + mDataset + ", " +
+                "clientState = " + mClientState +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mClientState != null) flg |= 0x2;
+        dest.writeByte(flg);
+        dest.writeTypedObject(mDataset, flags);
+        if (mClientState != null) dest.writeBundle(mClientState);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ ConvertCredentialResponse(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        Dataset dataset = (Dataset) in.readTypedObject(Dataset.CREATOR);
+        Bundle clientState = (flg & 0x2) == 0 ? null : in.readBundle();
+
+        this.mDataset = dataset;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDataset);
+        this.mClientState = clientState;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ConvertCredentialResponse> CREATOR
+            = new Parcelable.Creator<ConvertCredentialResponse>() {
+        @Override
+        public ConvertCredentialResponse[] newArray(int size) {
+            return new ConvertCredentialResponse[size];
+        }
+
+        @Override
+        public ConvertCredentialResponse createFromParcel(@NonNull Parcel in) {
+            return new ConvertCredentialResponse(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1706132669373L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/service/autofill/ConvertCredentialResponse.java",
+            inputSignatures = "private final @android.annotation.NonNull android.service.autofill.Dataset mDataset\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nclass ConvertCredentialResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 5d58120..98dda10 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -309,12 +309,19 @@
         /** The autofill suggestion is shown as a dialog presentation. */
         public static final int UI_TYPE_DIALOG = 3;
 
+        /**
+         *  The autofill suggestion is shown os a credman bottom sheet
+         *  @hide
+         */
+        public static final int UI_TYPE_CREDMAN_BOTTOM_SHEET = 4;
+
         /** @hide */
         @IntDef(prefix = { "UI_TYPE_" }, value = {
                 UI_TYPE_UNKNOWN,
                 UI_TYPE_MENU,
                 UI_TYPE_INLINE,
-                UI_TYPE_DIALOG
+                UI_TYPE_DIALOG,
+                UI_TYPE_CREDMAN_BOTTOM_SHEET
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface UiType {}
@@ -755,6 +762,8 @@
                     return "UI_TYPE_INLINE";
                 case UI_TYPE_DIALOG:
                     return "UI_TYPE_FILL_DIALOG";
+                case UI_TYPE_CREDMAN_BOTTOM_SHEET:
+                    return "UI_TYPE_CREDMAN_BOTTOM_SHEET";
                 default:
                     return "UI_TYPE_UNKNOWN";
             }
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 7ea74d3..09ec933 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -28,6 +28,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.app.Activity;
+import android.app.PendingIntent;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
@@ -116,6 +117,7 @@
     private final boolean mShowFillDialogIcon;
     private final boolean mShowSaveDialogIcon;
     private final @Nullable FieldClassification[] mDetectedFieldTypes;
+    private final @Nullable PendingIntent mDialogPendingIntent;
 
     /**
     * Creates a shollow copy of the provided FillResponse.
@@ -150,7 +152,8 @@
                 r.mServiceDisplayNameResourceId,
                 r.mShowFillDialogIcon,
                 r.mShowSaveDialogIcon,
-                r.mDetectedFieldTypes);
+                r.mDetectedFieldTypes,
+                r.mDialogPendingIntent);
     }
 
     private FillResponse(ParceledListSlice<Dataset> datasets, SaveInfo saveInfo, Bundle clientState,
@@ -163,7 +166,7 @@
             int[] cancelIds, boolean supportsInlineSuggestions, int iconResourceId,
             int serviceDisplayNameResourceId, boolean showFillDialogIcon,
             boolean showSaveDialogIcon,
-            FieldClassification[] detectedFieldTypes) {
+            FieldClassification[] detectedFieldTypes, PendingIntent dialogPendingIntent) {
         mDatasets = datasets;
         mSaveInfo = saveInfo;
         mClientState = clientState;
@@ -190,6 +193,7 @@
         mShowFillDialogIcon = showFillDialogIcon;
         mShowSaveDialogIcon = showSaveDialogIcon;
         mDetectedFieldTypes = detectedFieldTypes;
+        mDialogPendingIntent = dialogPendingIntent;
     }
 
     private FillResponse(@NonNull Builder builder) {
@@ -219,6 +223,7 @@
         mShowFillDialogIcon = builder.mShowFillDialogIcon;
         mShowSaveDialogIcon = builder.mShowSaveDialogIcon;
         mDetectedFieldTypes = builder.mDetectedFieldTypes;
+        mDialogPendingIntent = builder.mDialogPendingIntent;
     }
 
     /** @hide */
@@ -399,6 +404,7 @@
         private boolean mShowFillDialogIcon = true;
         private boolean mShowSaveDialogIcon = true;
         private FieldClassification[] mDetectedFieldTypes;
+        private PendingIntent mDialogPendingIntent;
 
         /**
          * Adds a new {@link FieldClassification} to this response, to
@@ -1079,6 +1085,24 @@
         }
 
         /**
+         * Sets credential dialog pending intent. Framework will use the intent to launch the
+         * selector UI. A replacement for previous fill bottom sheet.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called.
+         * @throws NullPointerException if {@code pendingIntent} is {@code null}.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setDialogPendingIntent(@NonNull PendingIntent pendingIntent) {
+            throwIfDestroyed();
+            Preconditions.checkNotNull(pendingIntent,
+                    "can't pass a null object to setDialogPendingIntent");
+            mDialogPendingIntent = pendingIntent;
+            return this;
+        }
+
+        /**
          * Builds a new {@link FillResponse} instance.
          *
          * @throws IllegalStateException if any of the following conditions occur:
@@ -1187,6 +1211,9 @@
         if (mAuthentication != null) {
             builder.append(", hasAuthentication");
         }
+        if (mDialogPendingIntent != null) {
+            builder.append(", hasDialogPendingIntent");
+        }
         if (mAuthenticationIds != null) {
             builder.append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds));
         }
@@ -1232,6 +1259,7 @@
         parcel.writeParcelable(mInlineTooltipPresentation, flags);
         parcel.writeParcelable(mDialogPresentation, flags);
         parcel.writeParcelable(mDialogHeader, flags);
+        parcel.writeParcelable(mDialogPendingIntent, flags);
         parcel.writeParcelableArray(mFillDialogTriggerIds, flags);
         parcel.writeParcelable(mHeader, flags);
         parcel.writeParcelable(mFooter, flags);
@@ -1282,6 +1310,11 @@
             if (dialogHeader != null) {
                 builder.setDialogHeader(dialogHeader);
             }
+            final PendingIntent dialogPendingIntent = parcel.readParcelable(null,
+                    PendingIntent.class);
+            if (dialogPendingIntent != null) {
+                builder.setDialogPendingIntent(dialogPendingIntent);
+            }
             final AutofillId[] triggerIds = parcel.readParcelableArray(null, AutofillId.class);
             if (triggerIds != null) {
                 builder.setFillDialogTriggerIds(triggerIds);
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index 03ead32..2c2feae 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -16,6 +16,8 @@
 
 package android.service.autofill;
 
+import android.service.autofill.ConvertCredentialRequest;
+import android.service.autofill.IConvertCredentialCallback;
 import android.service.autofill.FillRequest;
 import android.service.autofill.IFillCallback;
 import android.service.autofill.ISaveCallback;
@@ -32,7 +34,8 @@
     void onConnectedStateChanged(boolean connected);
     void onFillRequest(in FillRequest request, in IFillCallback callback);
     void onFillCredentialRequest(in FillRequest request, in IFillCallback callback,
-    in IAutoFillManagerClient client);
+        in IAutoFillManagerClient client);
     void onSaveRequest(in SaveRequest request, in ISaveCallback callback);
     void onSavedPasswordCountRequest(in IResultReceiver receiver);
+    void onConvertCredentialRequest(in ConvertCredentialRequest convertCredentialRequest, in IConvertCredentialCallback convertCredentialCallback);
 }
diff --git a/core/java/android/credentials/ui/UiResult.java b/core/java/android/service/autofill/IConvertCredentialCallback.aidl
similarity index 63%
copy from core/java/android/credentials/ui/UiResult.java
copy to core/java/android/service/autofill/IConvertCredentialCallback.aidl
index 692584d..9dfc294 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/core/java/android/service/autofill/IConvertCredentialCallback.aidl
@@ -14,11 +14,18 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.service.autofill;
+
+import android.os.ICancellationSignal;
+
+import android.service.autofill.ConvertCredentialResponse;
 
 /**
- * Base class for different types of ui results.
+ * Interface to receive the result of a convert credential request
  *
  * @hide
  */
-public interface UiResult {}
+oneway interface IConvertCredentialCallback {
+    void onSuccess(in ConvertCredentialResponse convertCredentialResponse);
+    void onFailure(CharSequence message);
+}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 9895551..d4a5356 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1053,7 +1053,7 @@
                 out);
 
         if (Flags.modesApi()) {
-            writeZenPolicyState(ALLOW_ATT_CHANNELS, policy.getPriorityChannels(), out);
+            writeZenPolicyState(ALLOW_ATT_CHANNELS, policy.getPriorityChannelsAllowed(), out);
         }
     }
 
@@ -1381,7 +1381,7 @@
         int state = defaultPolicy.state;
         if (Flags.modesApi()) {
             state = Policy.policyState(defaultPolicy.hasPriorityChannels(),
-                    ZenPolicy.stateToBoolean(zenPolicy.getPriorityChannels(),
+                    ZenPolicy.stateToBoolean(zenPolicy.getPriorityChannelsAllowed(),
                             DEFAULT_ALLOW_PRIORITY_CHANNELS));
         }
 
@@ -2297,6 +2297,18 @@
                     component, configurationActivity, pkg, id, enabler, zenPolicy, modified);
         }
 
+        /** Returns a deep copy of the {@link ZenRule}. */
+        public ZenRule copy() {
+            final Parcel parcel = Parcel.obtain();
+            try {
+                writeToParcel(parcel, 0);
+                parcel.setDataPosition(0);
+                return new ZenRule(parcel);
+            } finally {
+                parcel.recycle();
+            }
+        }
+
         public boolean isAutomaticActive() {
             return enabled && !snoozing && getPkg() != null && isTrueOrUnknown();
         }
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index d8318a6..786d768 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -570,7 +570,7 @@
      * with {@link NotificationChannel#canBypassDnd()} will be intercepted.
      */
     @FlaggedApi(Flags.FLAG_MODES_API)
-    public @State int getPriorityChannels() {
+    public @State int getPriorityChannelsAllowed() {
         switch (mAllowChannels) {
             case CHANNEL_POLICY_PRIORITY:
                 return STATE_ALLOW;
@@ -1529,7 +1529,7 @@
         proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders());
 
         if (Flags.modesApi()) {
-            proto.write(DNDPolicyProto.ALLOW_CHANNELS, getPriorityChannels());
+            proto.write(DNDPolicyProto.ALLOW_CHANNELS, getPriorityChannelsAllowed());
         }
 
         proto.flush();
diff --git a/core/java/android/service/notification/flags.aconfig b/core/java/android/service/notification/flags.aconfig
index 3008b8d..446fe3d 100644
--- a/core/java/android/service/notification/flags.aconfig
+++ b/core/java/android/service/notification/flags.aconfig
@@ -8,14 +8,6 @@
 }
 
 flag {
-  name: "notification_lifetime_extension_refactor"
-    namespace: "systemui"
-    description: "Enables moving notification lifetime extension management from SystemUI to "
-        "Notification Manager Service"
-    bug: "299448097"
-}
-
-flag {
   name: "redact_sensitive_notifications_from_untrusted_listeners"
   namespace: "systemui"
   description: "This flag controls the redacting of sensitive notifications from untrusted NotificationListenerServices"
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 2105420b..99bd2ff 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -30,6 +30,7 @@
 import android.graphics.text.LineBreakConfig;
 import android.graphics.text.LineBreaker;
 import android.os.Build;
+import android.os.Trace;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
 import android.text.style.LineHeightSpan;
@@ -534,7 +535,12 @@
             if (recycle == null) {
                 recycle = new StaticLayout();
             }
-            recycle.generate(this, mIncludePad, trackpadding);
+            Trace.beginSection("Generating StaticLayout For DynamicLayout");
+            try {
+                recycle.generate(this, mIncludePad, trackpadding);
+            } finally {
+                Trace.endSection();
+            }
             return recycle;
         }
 
@@ -689,7 +695,12 @@
         mLeftIndents = b.mLeftIndents;
         mRightIndents = b.mRightIndents;
 
-        generate(b, b.mIncludePad, trackPadding);
+        Trace.beginSection("Constructing StaticLayout");
+        try {
+            generate(b, b.mIncludePad, trackPadding);
+        } finally {
+            Trace.endSection();
+        }
     }
 
     private static int getBaseHyphenationFrequency(int frequency) {
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index f28574e..27c509a 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -197,9 +197,28 @@
      * Transfer the currently in progress touch gesture from the host to the requested
      * {@link SurfaceControlViewHost.SurfacePackage}. This requires that the
      * SurfaceControlViewHost was created with the current host's inputToken.
+     * <p>
+     * When the touch is transferred, the window currently receiving touch gets an ACTION_CANCEL
+     * and does not receive any further input events for this gesture.
+     * <p>
+     * The transferred-to window receives an ACTION_DOWN event and then the remainder of the
+     * input events for this gesture. It does not receive any of the previous events of this gesture
+     * that the originating window received.
+     * <p>
+     * The "transferTouch" API only works for the current gesture. When a new gesture arrives,
+     * input dispatcher will do a new round of hit testing. So, if the "host" window is still the
+     * first thing that's being touched, then it will receive the new gesture again. It will
+     * again be up to the host to transfer this new gesture to the embedded.
+     * <p>
+     * Once the transferred-to window receives the gesture, it can choose to give up this gesture
+     * and send it to another window that it's linked to (it can't be an arbitrary window for
+     * security reasons) using the same transferTouch API. Only the window currently receiving
+     * touch is allowed to transfer the gesture.
      *
      * @param surfacePackage The SurfacePackage to transfer the gesture to.
      * @return Whether the touch stream was transferred.
+     * @see SurfaceControlViewHost#transferTouchGestureToHost() for the reverse to transfer touch
+     * gesture from the embedded to the host.
      */
     @FlaggedApi(Flags.FLAG_TRANSFER_GESTURE_TO_EMBEDDED)
     default boolean transferHostTouchGestureToEmbedded(
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1d81be1..d2c25cd 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -235,7 +235,7 @@
      */
     oneway void setWallpaperDisplayOffset(IBinder windowToken, int x, int y);
 
-    Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
+    oneway void sendWallpaperCommand(IBinder window, String action, int x, int y,
             int z, in Bundle extras, boolean sync);
 
     @UnsupportedAppUsage
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 86ab213..bc33d5e 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static android.view.InsetsSourceProto.FRAME;
+import static android.view.InsetsSourceProto.TYPE;
 import static android.view.InsetsSourceProto.TYPE_NUMBER;
 import static android.view.InsetsSourceProto.VISIBLE;
 import static android.view.InsetsSourceProto.VISIBLE_FRAME;
@@ -442,6 +443,10 @@
      */
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
+        if (!android.os.Flags.androidOsBuildVanillaIceCream()) {
+            // Deprecated since V.
+            proto.write(TYPE, WindowInsets.Type.toString(mType));
+        }
         mFrame.dumpDebug(proto, FRAME);
         if (mVisibleFrame != null) {
             mVisibleFrame.dumpDebug(proto, VISIBLE_FRAME);
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ba7874e..6c6e8b2 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -1073,8 +1073,7 @@
             if (error == -EINVAL) {
                 throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
             } else if (error != 0) {
-                throw new RuntimeException("Failed to set frame rate on Surface. Native error: "
-                        + error);
+                Log.e(TAG, "Failed to set frame rate on Surface. Native error: " + error);
             }
         }
     }
@@ -1256,13 +1255,13 @@
     }
 
     private static void registerNativeMemoryUsage() {
-        if (Flags.enableSurfaceNativeAllocRegistration()) {
+        if (Flags.enableSurfaceNativeAllocRegistrationRo()) {
             VMRuntime.getRuntime().registerNativeAllocation(SURFACE_NATIVE_ALLOCATION_SIZE_BYTES);
         }
     }
 
     private static void freeNativeMemoryUsage() {
-        if (Flags.enableSurfaceNativeAllocRegistration()) {
+        if (Flags.enableSurfaceNativeAllocRegistrationRo()) {
             VMRuntime.getRuntime().registerNativeFree(SURFACE_NATIVE_ALLOCATION_SIZE_BYTES);
         }
     }
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 4840f00..5249fd5 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -538,8 +538,8 @@
     }
 
     private void addWindowToken(WindowManager.LayoutParams attrs) {
-        final WindowManagerImpl wm =
-                (WindowManagerImpl) mViewRoot.mContext.getSystemService(Context.WINDOW_SERVICE);
+        final WindowManager wm =
+                (WindowManager) mViewRoot.mContext.getSystemService(Context.WINDOW_SERVICE);
         attrs.token = wm.getDefaultToken();
     }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 42355bb..c788261 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -6022,8 +6022,8 @@
      * This is different from
      * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
      * SurfaceControlInputReceiver)} in that the input events are received batched. The caller must
-     * invoke {@link #unregisterSurfaceControlInputReceiver(IBinder)} to clean up the resources when
-     * no longer needing to use the {@link SurfaceControlInputReceiver}
+     * invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up the
+     * resources when no longer needing to use the {@link SurfaceControlInputReceiver}
      *
      * @param displayId      The display that the SurfaceControl will be placed on. Input will
      *                       only work
@@ -6035,14 +6035,9 @@
      * @param choreographer  The Choreographer used for batching. This should match the rendering
      *                       Choreographer.
      * @param receiver       The SurfaceControlInputReceiver that will receive the input events
-     * @return an {@link IBinder} token that is used to unregister the input receiver via
-     * {@link #unregisterSurfaceControlInputReceiver(IBinder)}.
-     * @see #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
-     * SurfaceControlInputReceiver)
      */
     @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
-    @NonNull
-    default IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+    default void registerBatchedSurfaceControlInputReceiver(int displayId,
             @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
             @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
         throw new UnsupportedOperationException(
@@ -6054,8 +6049,8 @@
      * receive every input event. This is different than calling @link
      * #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
      * SurfaceControlInputReceiver)} in that the input events are received unbatched. The caller
-     * must invoke {@link #unregisterSurfaceControlInputReceiver(IBinder)} to clean up the resources
-     * when no longer needing to use the {@link SurfaceControlInputReceiver}
+     * must invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up the
+     * resources when no longer needing to use the {@link SurfaceControlInputReceiver}
      *
      * @param displayId      The display that the SurfaceControl will be placed on. Input will only
      *                       work if SurfaceControl is on that display and that display was
@@ -6066,14 +6061,9 @@
      * @param surfaceControl The SurfaceControl to register the InputChannel for
      * @param looper         The looper to use when invoking callbacks.
      * @param receiver       The SurfaceControlInputReceiver that will receive the input events
-     * @return an {@link IBinder} token that is used to unregister the input receiver via
-     * {@link #unregisterSurfaceControlInputReceiver(IBinder)}.
-     * @see #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
-     * SurfaceControlInputReceiver)
      **/
     @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
-    @NonNull
-    default IBinder registerUnbatchedSurfaceControlInputReceiver(int displayId,
+    default void registerUnbatchedSurfaceControlInputReceiver(int displayId,
             @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
             @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
         throw new UnsupportedOperationException(
@@ -6091,17 +6081,40 @@
      * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
      * SurfaceControlInputReceiver)}
      *
-     * @param token The token that was returned via
-     *              {@link #registerBatchedSurfaceControlInputReceiver(int, IBinder,
-     *              SurfaceControl,
-     *              Choreographer, SurfaceControlInputReceiver)} or
-     *              {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder,
-     *              SurfaceControl,
-     *              Looper, SurfaceControlInputReceiver)}
+     * @param surfaceControl The SurfaceControl to remove and unregister the input channel for.
      */
     @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
-    default void unregisterSurfaceControlInputReceiver(@NonNull IBinder token) {
+    default void unregisterSurfaceControlInputReceiver(@NonNull SurfaceControl surfaceControl) {
         throw new UnsupportedOperationException(
                 "unregisterSurfaceControlInputReceiver is not implemented");
     }
+
+    /**
+     * Returns the input client token for the {@link SurfaceControl}. This will only return non null
+     * if the SurfaceControl was registered for input via
+     * { #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
+     * SurfaceControlInputReceiver)} or
+     * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+     * SurfaceControlInputReceiver)}.
+     * <p>
+     * This is helpful for testing to ensure the test waits for the layer to be registered with
+     * SurfaceFlinger and Input before proceeding with the test.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+    @TestApi
+    @Nullable
+    default IBinder getSurfaceControlInputClientToken(@NonNull SurfaceControl surfaceControl) {
+        throw new UnsupportedOperationException(
+                "getSurfaceControlInputClientToken is not implemented");
+    }
+
+    /**
+     * @hide
+     */
+    default @NonNull IBinder getDefaultToken() {
+        throw new UnsupportedOperationException(
+                "getDefaultToken is not implemented");
+    }
 }
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 8d40f9a..c49fce5 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -38,10 +38,12 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.inputmethod.InputMethodManager;
 import android.window.ITrustedPresentationListener;
 import android.window.TrustedPresentationThresholds;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.FastPrintWriter;
 
 import java.io.FileDescriptor;
@@ -50,7 +52,6 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.WeakHashMap;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.IntConsumer;
@@ -156,8 +157,9 @@
     private final TrustedPresentationListener mTrustedPresentationListener =
             new TrustedPresentationListener();
 
-    private final ConcurrentHashMap<IBinder, InputEventReceiver> mSurfaceControlInputReceivers =
-            new ConcurrentHashMap<>();
+    @GuardedBy("mSurfaceControlInputReceivers")
+    private final SparseArray<SurfaceControlInputReceiverInfo>
+            mSurfaceControlInputReceivers = new SparseArray<>();
 
     private WindowManagerGlobal() {
     }
@@ -816,7 +818,7 @@
         mTrustedPresentationListener.removeListener(listener);
     }
 
-    IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+    void registerBatchedSurfaceControlInputReceiver(int displayId,
             @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
             @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
         IBinder clientToken = new Binder();
@@ -830,19 +832,21 @@
             e.rethrowAsRuntimeException();
         }
 
-        mSurfaceControlInputReceivers.put(clientToken,
-                new BatchedInputEventReceiver(inputChannel, choreographer.getLooper(),
-                        choreographer) {
-                    @Override
-                    public void onInputEvent(InputEvent event) {
-                        boolean handled = receiver.onInputEvent(event);
-                        finishInputEvent(event, handled);
-                    }
-                });
-        return clientToken;
+        synchronized (mSurfaceControlInputReceivers) {
+            mSurfaceControlInputReceivers.put(surfaceControl.getLayerId(),
+                    new SurfaceControlInputReceiverInfo(clientToken,
+                            new BatchedInputEventReceiver(inputChannel, choreographer.getLooper(),
+                                    choreographer) {
+                                @Override
+                                public void onInputEvent(InputEvent event) {
+                                    boolean handled = receiver.onInputEvent(event);
+                                    finishInputEvent(event, handled);
+                                }
+                            }));
+        }
     }
 
-    IBinder registerUnbatchedSurfaceControlInputReceiver(
+    void registerUnbatchedSurfaceControlInputReceiver(
             int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
             @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
         IBinder clientToken = new Binder();
@@ -856,32 +860,53 @@
             e.rethrowAsRuntimeException();
         }
 
-        mSurfaceControlInputReceivers.put(clientToken,
-                new InputEventReceiver(inputChannel, looper) {
-                    @Override
-                    public void onInputEvent(InputEvent event) {
-                        boolean handled = receiver.onInputEvent(event);
-                        finishInputEvent(event, handled);
-                    }
-                });
-
-        return clientToken;
+        synchronized (mSurfaceControlInputReceivers) {
+            mSurfaceControlInputReceivers.put(surfaceControl.getLayerId(),
+                    new SurfaceControlInputReceiverInfo(clientToken,
+                            new InputEventReceiver(inputChannel, looper) {
+                                @Override
+                                public void onInputEvent(InputEvent event) {
+                                    boolean handled = receiver.onInputEvent(event);
+                                    finishInputEvent(event, handled);
+                                }
+                            }));
+        }
     }
 
-    void unregisterSurfaceControlInputReceiver(IBinder token) {
-        InputEventReceiver inputEventReceiver = mSurfaceControlInputReceivers.get(token);
-        if (inputEventReceiver == null) {
-            Log.w(TAG, "No registered input event receiver with token: " + token);
+    void unregisterSurfaceControlInputReceiver(SurfaceControl surfaceControl) {
+        SurfaceControlInputReceiverInfo surfaceControlInputReceiverInfo;
+        synchronized (mSurfaceControlInputReceivers) {
+            surfaceControlInputReceiverInfo = mSurfaceControlInputReceivers.removeReturnOld(
+                    surfaceControl.getLayerId());
+        }
+
+        if (surfaceControlInputReceiverInfo == null) {
+            Log.w(TAG, "No registered input event receiver with sc: " + surfaceControl);
             return;
         }
         try {
-            WindowManagerGlobal.getWindowSession().remove(token);
+            WindowManagerGlobal.getWindowSession().remove(
+                    surfaceControlInputReceiverInfo.mClientToken);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to remove input channel", e);
             e.rethrowAsRuntimeException();
         }
 
-        inputEventReceiver.dispose();
+        surfaceControlInputReceiverInfo.mInputEventReceiver.dispose();
+    }
+
+    IBinder getSurfaceControlInputClientToken(SurfaceControl surfaceControl) {
+        SurfaceControlInputReceiverInfo surfaceControlInputReceiverInfo;
+        synchronized (mSurfaceControlInputReceivers) {
+            surfaceControlInputReceiverInfo = mSurfaceControlInputReceivers.get(
+                    surfaceControl.getLayerId());
+        }
+
+        if (surfaceControlInputReceiverInfo == null) {
+            Log.w(TAG, "No registered input event receiver with sc: " + surfaceControl);
+            return null;
+        }
+        return surfaceControlInputReceiverInfo.mClientToken;
     }
 
     private final class TrustedPresentationListener extends
@@ -976,6 +1001,17 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    private static class SurfaceControlInputReceiverInfo {
+        final IBinder mClientToken;
+        final InputEventReceiver mInputEventReceiver;
+
+        private SurfaceControlInputReceiverInfo(IBinder clientToken,
+                InputEventReceiver inputEventReceiver) {
+            mClientToken = clientToken;
+            mInputEventReceiver = inputEventReceiver;
+        }
+    }
 }
 
 final class WindowLeaked extends AndroidRuntimeException {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index aaf5fcc..5072ad7 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -458,7 +458,9 @@
         return null;
     }
 
-    IBinder getDefaultToken() {
+    @Override
+    @NonNull
+    public IBinder getDefaultToken() {
         return mDefaultToken;
     }
 
@@ -523,26 +525,30 @@
         mGlobal.unregisterTrustedPresentationListener(listener);
     }
 
-    @NonNull
     @Override
-    public IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+    public void registerBatchedSurfaceControlInputReceiver(int displayId,
             @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
             @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
-        return mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
+        mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
                 surfaceControl, choreographer, receiver);
     }
 
-    @NonNull
     @Override
-    public IBinder registerUnbatchedSurfaceControlInputReceiver(
+    public void registerUnbatchedSurfaceControlInputReceiver(
             int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
             @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
-        return mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostToken,
+        mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostToken,
                 surfaceControl, looper, receiver);
     }
 
     @Override
-    public void unregisterSurfaceControlInputReceiver(@NonNull IBinder token) {
-        mGlobal.unregisterSurfaceControlInputReceiver(token);
+    public void unregisterSurfaceControlInputReceiver(@NonNull SurfaceControl surfaceControl) {
+        mGlobal.unregisterSurfaceControlInputReceiver(surfaceControl);
+    }
+
+    @Override
+    @Nullable
+    public IBinder getSurfaceControlInputClientToken(@NonNull SurfaceControl surfaceControl) {
+        return mGlobal.getSurfaceControlInputClientToken(surfaceControl);
     }
 }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index b95e459..c4d18c6 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -534,9 +534,8 @@
     }
 
     @Override
-    public android.os.Bundle sendWallpaperCommand(android.os.IBinder window,
+    public void sendWallpaperCommand(android.os.IBinder window,
             java.lang.String action, int x, int y, int z, android.os.Bundle extras, boolean sync) {
-        return null;
     }
 
     @Override
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 49d2ceb..ef1bf5a 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -62,10 +62,12 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.IWindow;
+import android.view.SurfaceControl;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent.EventType;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IntPair;
 
@@ -155,22 +157,6 @@
     public static final String ACTION_CHOOSE_ACCESSIBILITY_BUTTON =
             "com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
 
-    /**
-     * Used as an int value for accessibility chooser activity to represent the accessibility button
-     * shortcut type.
-     *
-     * @hide
-     */
-    public static final int ACCESSIBILITY_BUTTON = 0;
-
-    /**
-     * Used as an int value for accessibility chooser activity to represent hardware key shortcut,
-     * such as volume key button.
-     *
-     * @hide
-     */
-    public static final int ACCESSIBILITY_SHORTCUT_KEY = 1;
-
     /** @hide */
     public static final int FLASH_REASON_CALL = 1;
 
@@ -184,32 +170,6 @@
     public static final int FLASH_REASON_PREVIEW = 4;
 
     /**
-     * Annotations for the shortcut type.
-     * <p>Note: Keep in sync with {@link #SHORTCUT_TYPES}.</p>
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = {
-            // LINT.IfChange(shortcut_type_intdef)
-            ACCESSIBILITY_BUTTON,
-            ACCESSIBILITY_SHORTCUT_KEY
-            // LINT.ThenChange(:shortcut_type_array)
-    })
-    public @interface ShortcutType {}
-
-    /**
-     * Used for iterating through {@link ShortcutType}.
-     * <p>Note: Keep in sync with {@link ShortcutType}.</p>
-     * @hide
-     */
-    public static final int[] SHORTCUT_TYPES = {
-            // LINT.IfChange(shortcut_type_array)
-            ACCESSIBILITY_BUTTON,
-            ACCESSIBILITY_SHORTCUT_KEY,
-            // LINT.ThenChange(:shortcut_type_intdef)
-    };
-
-    /**
      * Annotations for content flag of UI.
      * @hide
      */
@@ -1785,7 +1745,8 @@
     @TestApi
     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
     @NonNull
-    public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
+    public List<String> getAccessibilityShortcutTargets(
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         final IAccessibilityManager service;
         synchronized (mLock) {
             service = getServiceLocked();
@@ -2444,4 +2405,29 @@
             throw re.rethrowFromSystemServer();
         }
     }
+
+
+    /**
+     * Attaches a {@link android.view.SurfaceControl} containing an accessibility overlay to the
+     * specified display.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
+    public void attachAccessibilityOverlayToDisplay(
+            int displayId, @NonNull SurfaceControl surfaceControl) {
+        final IAccessibilityManager service;
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
+                return;
+            }
+        }
+        try {
+            service.attachAccessibilityOverlayToDisplay_enforcePermission(
+                    displayId, surfaceControl);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 9c04c27..1c5d29e 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -31,6 +31,7 @@
 import android.view.InputEvent;
 import android.view.IWindow;
 import android.view.MagnificationSpec;
+import android.view.SurfaceControl;
 
 /**
  * Interface implemented by the AccessibilityManagerService called by
@@ -136,4 +137,7 @@
         MagnificationSpec magnificationSpec;
     }
     WindowTransformationSpec getWindowTransformationSpec(int windowId);
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)")
+    void attachAccessibilityOverlayToDisplay_enforcePermission(int displayId, in SurfaceControl surfaceControl);
 }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index dbeffc8..559ccfea7 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -298,6 +298,15 @@
             "android.view.autofill.extra.AUGMENTED_AUTOFILL_CLIENT";
 
     /**
+     * Internal extra used to pass the fill request id in client state of
+     * {@link ConvertCredentialResponse}
+     *
+     * @hide
+     */
+    public static final String EXTRA_AUTOFILL_REQUEST_ID =
+            "android.view.autofill.extra.AUTOFILL_REQUEST_ID";
+
+    /**
      * Autofill Hint to indicate that it can match any field.
      *
      * @hide
diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS
index 37c6f5b..898947a 100644
--- a/core/java/android/view/autofill/OWNERS
+++ b/core/java/android/view/autofill/OWNERS
@@ -4,6 +4,7 @@
 haoranzhang@google.com
 skxu@google.com
 yunicorn@google.com
+reemabajwa@google.com
 
 # Bug component: 543785 = per-file *Augmented*
 per-file *Augmented* = wangqi@google.com
diff --git a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
index 2a3008a..5d3153c 100644
--- a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
+++ b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
@@ -34,3 +34,10 @@
     description: "If true, an appop is logged when a notification is rapidly cleared by a notification listener."
     bug: "289080543"
 }
+
+flag {
+    name: "manage_device_policy_enabled"
+    namespace: "content_protection"
+    description: "If true, the APIs to manage content protection device policy will be enabled."
+    bug: "319477846"
+}
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index befb002..5446428 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -30,6 +30,8 @@
 import android.util.Log;
 import android.view.SurfaceControl;
 
+import com.android.window.flags.Flags;
+
 import libcore.util.NativeAllocationRegistry;
 
 import java.util.concurrent.CountDownLatch;
@@ -48,7 +50,7 @@
     private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
             long captureListener);
     private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
-            long captureListener);
+            long captureListener, boolean sync);
     private static native long nativeCreateScreenCaptureListener(
             ObjIntConsumer<ScreenshotHardwareBuffer> consumer);
     private static native void nativeWriteListenerToParcel(long nativeObject, Parcel out);
@@ -134,7 +136,8 @@
      */
     public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) {
         SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener();
-        int status = captureLayers(captureArgs, syncScreenCapture);
+        int status = nativeCaptureLayers(captureArgs, syncScreenCapture.mNativeObject,
+                Flags.syncScreenCapture());
         if (status != 0) {
             return null;
         }
@@ -171,7 +174,7 @@
      */
     public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
             @NonNull ScreenCaptureListener captureListener) {
-        return nativeCaptureLayers(captureArgs, captureListener.mNativeObject);
+        return nativeCaptureLayers(captureArgs, captureListener.mNativeObject, false /* sync */);
     }
 
     /**
@@ -674,7 +677,7 @@
      * This listener can only be used for a single call to capture content call.
      */
     public static class ScreenCaptureListener implements Parcelable {
-        private final long mNativeObject;
+        final long mNativeObject;
         private static final NativeAllocationRegistry sRegistry =
                 NativeAllocationRegistry.createMalloced(
                         ScreenCaptureListener.class.getClassLoader(), getNativeListenerFinalizer());
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 86804c6..65075ae 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -226,9 +226,6 @@
             setTopOnBackInvokedCallback(null);
         }
 
-        // We should also stop running animations since all callbacks have been removed.
-        // note: mSpring.skipToEnd(), in ProgressAnimator.reset(), requires the main handler.
-        Handler.getMain().post(mProgressAnimator::reset);
         mAllCallbacks.clear();
         mOnBackInvokedCallbacks.clear();
     }
@@ -442,8 +439,7 @@
 
         return WindowOnBackInvokedDispatcher
                 .isOnBackInvokedCallbackEnabled(activityInfo, applicationInfo,
-                        () -> originalContext.obtainStyledAttributes(
-                                new int[] {android.R.attr.windowSwipeToDismiss}), true);
+                        () -> originalContext);
     }
 
     @Override
@@ -501,7 +497,7 @@
      */
     public static boolean isOnBackInvokedCallbackEnabled(@Nullable ActivityInfo activityInfo,
             @NonNull ApplicationInfo applicationInfo,
-            @NonNull Supplier<TypedArray> windowAttrSupplier, boolean recycleTypedArray) {
+            @NonNull Supplier<Context> contextSupplier) {
         // new back is enabled if the feature flag is enabled AND the app does not explicitly
         // request legacy back.
         if (!ENABLE_PREDICTIVE_BACK) {
@@ -547,15 +543,15 @@
             //    setTrigger(true)
             // Use the original context to resolve the styled attribute so that they stay
             // true to the window.
-            TypedArray windowAttr = windowAttrSupplier.get();
+            final Context context = contextSupplier.get();
             boolean windowSwipeToDismiss = true;
-            if (windowAttr != null) {
-                if (windowAttr.getIndexCount() > 0) {
-                    windowSwipeToDismiss = windowAttr.getBoolean(0, true);
+            if (context != null) {
+                final TypedArray array = context.obtainStyledAttributes(
+                            new int[]{android.R.attr.windowSwipeToDismiss});
+                if (array.getIndexCount() > 0) {
+                    windowSwipeToDismiss = array.getBoolean(0, true);
                 }
-                if (recycleTypedArray) {
-                    windowAttr.recycle();
-                }
+                array.recycle();
             }
 
             if (DEBUG) {
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index edfbea4..1de77f6 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -58,3 +58,11 @@
   bug: "319808237"
   is_fixed_read_only: true
 }
+
+flag {
+  name: "camera_compat_for_freeform"
+  namespace: "large_screen_experiences_app_compat"
+  description: "Whether to apply Camera Compat treatment to fixed-orientation apps in freeform windowing mode"
+  bug: "314952133"
+  is_fixed_read_only: true
+}
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 751c1a8..069affb 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -88,3 +88,11 @@
     is_fixed_read_only: true
     bug: "304574518"
 }
+
+flag {
+    namespace: "window_surfaces"
+    name: "sync_screen_capture"
+    description: "Create a screen capture API that blocks in SurfaceFlinger"
+    is_fixed_read_only: true
+    bug: "321263247"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 2c5fbd7..f234637 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -38,14 +38,6 @@
 }
 
 flag {
-  name: "draw_magnifier_border_outside_wmlock"
-  namespace: "windowing_frontend"
-  description: "Avoid holding WM locks for a long time when executing lockCanvas"
-  bug: "316075123"
-  is_fixed_read_only: true
-}
-
-flag {
   name: "introduce_smoother_dimmer"
   namespace: "windowing_frontend"
   description: "Refactor dim to fix flickers"
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 6e5807b..4a6e8d7 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -42,6 +42,14 @@
 
 flag {
     namespace: "windowing_sdk"
+    name: "untrusted_embedding_any_app_permission"
+    description: "Feature flag to enable the permission to embed any app in untrusted mode."
+    bug: "289199433"
+    is_fixed_read_only: true
+}
+
+flag {
+    namespace: "windowing_sdk"
     name: "activity_window_info_flag"
     description: "To dispatch ActivityWindowInfo through ClientTransaction"
     bug: "287582673"
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index de0f070..b4395a7 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -18,7 +18,6 @@
 
 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
 
 import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
 import static com.android.internal.os.RoSystemProperties.SUPPORT_ONE_HANDED_MODE;
@@ -329,7 +328,8 @@
     }
 
     private AlertDialog createShortcutWarningDialog(int userId) {
-        List<AccessibilityTarget> targets = getTargets(mContext, ACCESSIBILITY_SHORTCUT_KEY);
+        List<AccessibilityTarget> targets = getTargets(mContext,
+                ShortcutConstants.UserShortcutType.HARDWARE);
         if (targets.size() == 0) {
             return null;
         }
@@ -541,7 +541,7 @@
     private ComponentName getShortcutTargetComponentName() {
         final List<String> shortcutTargets = mFrameworkObjectProvider
                 .getAccessibilityManagerInstance(mContext)
-                .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY);
+                .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE);
         if (shortcutTargets.size() != 1) {
             return null;
         }
diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
index 7ec8838..353e182 100644
--- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
+++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
@@ -44,19 +44,27 @@
      * choose accessibility shortcut as preferred shortcut.
      * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly
      * tapping screen 3 times as preferred shortcut.
+     * {@code TWO_FINGERS_TRIPLE_TAP} for displaying specifying magnification to be toggled via
+     * quickly tapping screen 3 times with two fingers as preferred shortcut.
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-            UserShortcutType.DEFAULT,
-            UserShortcutType.SOFTWARE,
-            UserShortcutType.HARDWARE,
-            UserShortcutType.TRIPLETAP,
-    })
+    @IntDef(
+            flag = true,
+            value = {
+                    UserShortcutType.DEFAULT,
+                    UserShortcutType.SOFTWARE,
+                    UserShortcutType.HARDWARE,
+                    UserShortcutType.TRIPLETAP,
+                    UserShortcutType.TWO_FINGERS_TRIPLE_TAP,
+            })
     public @interface UserShortcutType {
         int DEFAULT = 0;
-        int SOFTWARE = 1; // 1 << 0
-        int HARDWARE = 2; // 1 << 1
-        int TRIPLETAP = 4; // 1 << 2
+        // LINT.IfChange(shortcut_type_intdef)
+        int SOFTWARE = 1;
+        int HARDWARE = 1 << 1;
+        int TRIPLETAP = 1 << 2;
+        int TWO_FINGERS_TRIPLE_TAP = 1 << 3;
+        // LINT.ThenChange(:shortcut_type_array)
     }
 
     /**
@@ -64,9 +72,12 @@
      * non-default IntDef types.
      */
     public static final int[] USER_SHORTCUT_TYPES = {
+            // LINT.IfChange(shortcut_type_array)
             UserShortcutType.SOFTWARE,
             UserShortcutType.HARDWARE,
-            UserShortcutType.TRIPLETAP
+            UserShortcutType.TRIPLETAP,
+            UserShortcutType.TWO_FINGERS_TRIPLE_TAP,
+            // LINT.ThenChange(:shortcut_type_intdef)
     };
 
 
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java
index 063154d..33048dc 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java
@@ -17,14 +17,13 @@
 package com.android.internal.accessibility.dialog;
 
 import static com.android.internal.accessibility.util.ShortcutUtils.convertToKey;
-import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
 import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained;
 
 import android.accessibilityservice.AccessibilityShortcutInfo;
 import android.annotation.NonNull;
 import android.content.Context;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
 import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
 
@@ -33,7 +32,8 @@
  */
 class AccessibilityActivityTarget extends AccessibilityTarget {
 
-    AccessibilityActivityTarget(Context context, @ShortcutType int shortcutType,
+    AccessibilityActivityTarget(Context context,
+            @ShortcutConstants.UserShortcutType int shortcutType,
             @NonNull AccessibilityShortcutInfo shortcutInfo) {
         super(context,
                 shortcutType,
@@ -44,7 +44,7 @@
                 shortcutInfo.getActivityInfo().applicationInfo.uid,
                 shortcutInfo.getActivityInfo().loadLabel(context.getPackageManager()),
                 shortcutInfo.getActivityInfo().loadIcon(context.getPackageManager()),
-                convertToKey(convertToUserType(shortcutType)));
+                convertToKey(shortcutType));
     }
 
     @Override
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
index 7eb09e5..e084ebd 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
@@ -17,7 +17,6 @@
 package com.android.internal.accessibility.dialog;
 
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
 
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
@@ -36,6 +35,7 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.widget.ResolverDrawerLayout;
 
 import java.util.ArrayList;
@@ -85,7 +85,7 @@
             prompt.setVisibility(View.VISIBLE);
         }
 
-        mTargets.addAll(getTargets(this, ACCESSIBILITY_BUTTON));
+        mTargets.addAll(getTargets(this, ShortcutConstants.UserShortcutType.SOFTWARE));
 
         final GridView gridview = findViewById(R.id.accessibility_button_chooser_grid);
         gridview.setAdapter(new ButtonTargetAdapter(mTargets));
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java
index 2b6913c..7406da4 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java
@@ -17,14 +17,13 @@
 package com.android.internal.accessibility.dialog;
 
 import static com.android.internal.accessibility.util.ShortcutUtils.convertToKey;
-import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
 import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.NonNull;
 import android.content.Context;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
 import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
 
@@ -36,7 +35,9 @@
 
     private final AccessibilityServiceInfo mAccessibilityServiceInfo;
 
-    AccessibilityServiceTarget(Context context, @ShortcutType int shortcutType,
+    AccessibilityServiceTarget(
+            Context context,
+            @ShortcutConstants.UserShortcutType int shortcutType,
             @AccessibilityFragmentType int fragmentType,
             @NonNull AccessibilityServiceInfo serviceInfo) {
         super(context,
@@ -48,7 +49,7 @@
                 serviceInfo.getResolveInfo().serviceInfo.applicationInfo.uid,
                 serviceInfo.getResolveInfo().loadLabel(context.getPackageManager()),
                 serviceInfo.getResolveInfo().loadIcon(context.getPackageManager()),
-                convertToKey(convertToUserType(shortcutType)));
+                convertToKey(shortcutType));
         mAccessibilityServiceInfo = serviceInfo;
     }
 
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 2e80b7e..8e2ec1b 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -15,10 +15,6 @@
  */
 package com.android.internal.accessibility.dialog;
 
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-import static android.view.accessibility.AccessibilityManager.ShortcutType;
-
 import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
 import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.createEnableDialogContentView;
 import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getInstalledTargets;
@@ -42,6 +38,7 @@
 import android.widget.AdapterView;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
@@ -52,8 +49,8 @@
  * activity or allowlisting feature for volume key shortcut.
  */
 public class AccessibilityShortcutChooserActivity extends Activity {
-    @ShortcutType
-    private final int mShortcutType = ACCESSIBILITY_SHORTCUT_KEY;
+    @ShortcutConstants.UserShortcutType
+    private final int mShortcutType = ShortcutConstants.UserShortcutType.HARDWARE;
     private static final String KEY_ACCESSIBILITY_SHORTCUT_MENU_MODE =
             "accessibility_shortcut_menu_mode";
     private final List<AccessibilityTarget> mTargets = new ArrayList<>();
@@ -246,7 +243,7 @@
                 mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT;
         final int selectDialogTitleId = R.string.accessibility_select_shortcut_menu_title;
         final int editDialogTitleId =
-                mShortcutType == ACCESSIBILITY_BUTTON
+                mShortcutType == ShortcutConstants.UserShortcutType.SOFTWARE
                         ? R.string.accessibility_edit_shortcut_menu_button_title
                         : R.string.accessibility_edit_shortcut_menu_volume_title;
 
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
index 652cb52..4ab1ee9 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
@@ -16,10 +16,6 @@
 
 package com.android.internal.accessibility.dialog;
 
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-
-import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
 import static com.android.internal.accessibility.util.ShortcutUtils.optInValueToSettings;
 import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
 
@@ -30,7 +26,6 @@
 import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 
 import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
@@ -47,7 +42,7 @@
 public abstract class AccessibilityTarget implements TargetOperations, OnTargetSelectedListener,
         OnTargetCheckedChangeListener {
     private Context mContext;
-    @ShortcutType
+    @ShortcutConstants.UserShortcutType
     private int mShortcutType;
     @AccessibilityFragmentType
     private int mFragmentType;
@@ -61,7 +56,8 @@
     private CharSequence mStateDescription;
 
     @VisibleForTesting
-    public AccessibilityTarget(Context context, @ShortcutType int shortcutType,
+    public AccessibilityTarget(
+            Context context, @ShortcutConstants.UserShortcutType int shortcutType,
             @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id,
             int uid, CharSequence label, Drawable icon, String key) {
         mContext = context;
@@ -99,10 +95,10 @@
         final AccessibilityManager am =
                 getContext().getSystemService(AccessibilityManager.class);
         switch (getShortcutType()) {
-            case ACCESSIBILITY_BUTTON:
+            case ShortcutConstants.UserShortcutType.SOFTWARE:
                 am.notifyAccessibilityButtonClicked(getContext().getDisplayId(), getId());
                 return;
-            case ACCESSIBILITY_SHORTCUT_KEY:
+            case ShortcutConstants.UserShortcutType.HARDWARE:
                 am.performAccessibilityShortcut(getId());
                 return;
             default:
@@ -114,9 +110,9 @@
     public void onCheckedChanged(boolean isChecked) {
         setShortcutEnabled(isChecked);
         if (isChecked) {
-            optInValueToSettings(getContext(), convertToUserType(getShortcutType()), getId());
+            optInValueToSettings(getContext(), getShortcutType(), getId());
         } else {
-            optOutValueFromSettings(getContext(), convertToUserType(getShortcutType()), getId());
+            optOutValueFromSettings(getContext(), getShortcutType(), getId());
         }
     }
 
@@ -142,7 +138,7 @@
         return mContext;
     }
 
-    public @ShortcutType int getShortcutType() {
+    public @ShortcutConstants.UserShortcutType int getShortcutType() {
         return mShortcutType;
     }
 
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index 51a5ddf..bd63e23 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.accessibility.dialog;
 
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-
 import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
@@ -41,12 +39,12 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
 
 import java.util.ArrayList;
@@ -70,8 +68,9 @@
      * @return The list of {@link AccessibilityTarget}.
      * @hide
      */
-    public static List<AccessibilityTarget> getTargets(Context context,
-            @ShortcutType int shortcutType) {
+    public static List<AccessibilityTarget> getTargets(
+            Context context,
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         // List all accessibility target
         final List<AccessibilityTarget> installedTargets = getInstalledTargets(context,
                 shortcutType);
@@ -113,7 +112,7 @@
      * @return The list of {@link AccessibilityTarget}.
      */
     static List<AccessibilityTarget> getInstalledTargets(Context context,
-            @ShortcutType int shortcutType) {
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         final List<AccessibilityTarget> targets = new ArrayList<>();
         targets.addAll(getAccessibilityFilteredTargets(context, shortcutType));
         targets.addAll(getAllowListingFeatureTargets(context, shortcutType));
@@ -122,7 +121,7 @@
     }
 
     private static List<AccessibilityTarget> getAccessibilityFilteredTargets(Context context,
-            @ShortcutType int shortcutType) {
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         final List<AccessibilityTarget> serviceTargets =
                 getAccessibilityServiceTargets(context, shortcutType);
         final List<AccessibilityTarget> activityTargets =
@@ -155,7 +154,7 @@
     }
 
     private static List<AccessibilityTarget> getAccessibilityServiceTargets(Context context,
-            @ShortcutType int shortcutType) {
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
         final List<AccessibilityServiceInfo> installedServices =
@@ -171,7 +170,7 @@
             final boolean hasRequestAccessibilityButtonFlag =
                     (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
             if ((targetSdk <= Build.VERSION_CODES.Q) && !hasRequestAccessibilityButtonFlag
-                    && (shortcutType == ACCESSIBILITY_BUTTON)) {
+                    && (shortcutType == ShortcutConstants.UserShortcutType.SOFTWARE)) {
                 continue;
             }
 
@@ -182,7 +181,7 @@
     }
 
     private static List<AccessibilityTarget> getAccessibilityActivityTargets(Context context,
-            @ShortcutType int shortcutType) {
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
         final List<AccessibilityShortcutInfo> installedServices =
@@ -201,7 +200,7 @@
     }
 
     private static List<AccessibilityTarget> getAllowListingFeatureTargets(Context context,
-            @ShortcutType int shortcutType) {
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         final List<AccessibilityTarget> targets = new ArrayList<>();
         final int uid = context.getApplicationInfo().uid;
 
@@ -281,8 +280,10 @@
         return targets;
     }
 
-    private static AccessibilityTarget createAccessibilityServiceTarget(Context context,
-            @ShortcutType int shortcutType, @NonNull AccessibilityServiceInfo info) {
+    private static AccessibilityTarget createAccessibilityServiceTarget(
+            Context context,
+            @ShortcutConstants.UserShortcutType int shortcutType,
+            @NonNull AccessibilityServiceInfo info) {
         switch (getAccessibilityServiceFragmentType(info)) {
             case AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE:
                 return new VolumeShortcutToggleAccessibilityServiceTarget(context, shortcutType,
diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java
index 1bc8b84..641a9f1 100644
--- a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java
@@ -16,9 +16,6 @@
 
 package com.android.internal.accessibility.dialog;
 
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-
 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
 import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
 import static com.android.internal.accessibility.util.ShortcutUtils.isComponentIdExistingInSettings;
@@ -28,7 +25,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.UserHandle;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 import android.view.accessibility.Flags;
 
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
@@ -45,7 +41,7 @@
 public class InvisibleToggleAccessibilityServiceTarget extends AccessibilityServiceTarget {
 
     public InvisibleToggleAccessibilityServiceTarget(
-            Context context, @ShortcutType int shortcutType,
+            Context context, @UserShortcutType int shortcutType,
             @NonNull AccessibilityServiceInfo serviceInfo) {
         super(context,
                 shortcutType,
@@ -72,10 +68,10 @@
 
     private boolean isComponentIdExistingInOtherShortcut() {
         switch (getShortcutType()) {
-            case ACCESSIBILITY_BUTTON:
+            case UserShortcutType.SOFTWARE:
                 return isComponentIdExistingInSettings(getContext(), UserShortcutType.HARDWARE,
                         getId());
-            case ACCESSIBILITY_SHORTCUT_KEY:
+            case UserShortcutType.HARDWARE:
                 return isComponentIdExistingInSettings(getContext(), UserShortcutType.SOFTWARE,
                         getId());
             default:
diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
index c22f17d..2204c0b 100644
--- a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
@@ -18,8 +18,8 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
 
 /**
@@ -28,7 +28,8 @@
  */
 class InvisibleToggleAllowListingFeatureTarget extends AccessibilityTarget {
 
-    InvisibleToggleAllowListingFeatureTarget(Context context, @ShortcutType int shortcutType,
+    InvisibleToggleAllowListingFeatureTarget(Context context,
+            @ShortcutConstants.UserShortcutType int shortcutType,
             boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon,
             String key) {
         super(context, shortcutType, AccessibilityFragmentType.INVISIBLE_TOGGLE, isShortcutSwitched,
diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java
index a4ffef6..a6ef73e 100644
--- a/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java
@@ -22,9 +22,9 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.view.View;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
 import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
 import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder;
@@ -45,7 +45,8 @@
         float DISABLED = 0.5f;
     }
 
-    ToggleAccessibilityServiceTarget(Context context, @ShortcutType int shortcutType,
+    ToggleAccessibilityServiceTarget(Context context,
+            @ShortcutConstants.UserShortcutType int shortcutType,
             @NonNull AccessibilityServiceInfo serviceInfo) {
         super(context,
                 shortcutType,
diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
index 11e668f..2a9c555 100644
--- a/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
@@ -21,9 +21,9 @@
 import android.graphics.drawable.Drawable;
 import android.provider.Settings;
 import android.view.View;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
 import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
 import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder;
@@ -34,7 +34,8 @@
  */
 class ToggleAllowListingFeatureTarget extends AccessibilityTarget {
 
-    ToggleAllowListingFeatureTarget(Context context, @ShortcutType int shortcutType,
+    ToggleAllowListingFeatureTarget(Context context,
+            @ShortcutConstants.UserShortcutType int shortcutType,
             boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon,
             String key) {
         super(context, shortcutType, AccessibilityFragmentType.TOGGLE, isShortcutSwitched, id,
diff --git a/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java
index 04f5061..4926e72 100644
--- a/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java
@@ -16,9 +16,6 @@
 
 package com.android.internal.accessibility.dialog;
 
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-
 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
 import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
 import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
@@ -27,7 +24,6 @@
 import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.Context;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 import android.widget.Toast;
 
 import com.android.internal.R;
@@ -39,7 +35,8 @@
  */
 class VolumeShortcutToggleAccessibilityServiceTarget extends AccessibilityServiceTarget {
 
-    VolumeShortcutToggleAccessibilityServiceTarget(Context context, @ShortcutType int shortcutType,
+    VolumeShortcutToggleAccessibilityServiceTarget(Context context,
+            @UserShortcutType int shortcutType,
             @NonNull AccessibilityServiceInfo serviceInfo) {
         super(context,
                 shortcutType,
@@ -50,10 +47,10 @@
     @Override
     public void onCheckedChanged(boolean isChecked) {
         switch (getShortcutType()) {
-            case ACCESSIBILITY_BUTTON:
+            case UserShortcutType.SOFTWARE:
                 onCheckedFromAccessibilityButton(isChecked);
                 return;
-            case ACCESSIBILITY_SHORTCUT_KEY:
+            case UserShortcutType.HARDWARE:
                 super.onCheckedChanged(isChecked);
                 return;
             default:
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index 6b074a6..1e4bcf2 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -21,8 +21,6 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
 
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__DISABLED;
@@ -47,9 +45,8 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.provider.Settings;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.util.FrameworkStatsLog;
 
 /** Methods for logging accessibility states. */
@@ -71,15 +68,15 @@
 
     /**
      * Logs accessibility feature name that is assigned to the given {@code shortcutType}.
-     * Calls this when clicking the shortcut {@link AccessibilityManager#ACCESSIBILITY_BUTTON} or
-     * {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}.
+     * Calls this when clicking the shortcut {@link ShortcutConstants.UserShortcutType.SOFTWARE} or
+     * {@link ShortcutConstants.UserShortcutType.HARDWARE}.
      *
      * @param context context used to retrieve the {@link Settings} provider
      * @param componentName component name of the accessibility feature
      * @param shortcutType  accessibility shortcut type
      */
     public static void logAccessibilityShortcutActivated(Context context,
-            ComponentName componentName, @ShortcutType int shortcutType) {
+            ComponentName componentName, @ShortcutConstants.UserShortcutType int shortcutType) {
         logAccessibilityShortcutActivatedInternal(componentName,
                 convertToLoggingShortcutType(context, shortcutType), UNKNOWN_STATUS);
     }
@@ -87,8 +84,8 @@
     /**
      * Logs accessibility feature name that is assigned to the given {@code shortcutType} and the
      * {@code serviceEnabled} status.
-     * Calls this when clicking the shortcut {@link AccessibilityManager#ACCESSIBILITY_BUTTON}
-     * or {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}.
+     * Calls this when clicking the shortcut {@link ShortcutConstants.UserShortcutType.SOFTWARE}
+     * or {@link ShortcutConstants.UserShortcutType.HARDWARE}.
      *
      * @param context context used to retrieve the {@link Settings} provider
      * @param componentName  component name of the accessibility feature
@@ -96,7 +93,8 @@
      * @param serviceEnabled {@code true} if the service is enabled
      */
     public static void logAccessibilityShortcutActivated(Context context,
-            ComponentName componentName, @ShortcutType int shortcutType, boolean serviceEnabled) {
+            ComponentName componentName, @ShortcutConstants.UserShortcutType int shortcutType,
+            boolean serviceEnabled) {
         logAccessibilityShortcutActivatedInternal(componentName,
                 convertToLoggingShortcutType(context, shortcutType),
                 convertToLoggingServiceStatus(serviceEnabled));
@@ -235,9 +233,9 @@
     }
 
     private static int convertToLoggingShortcutType(Context context,
-            @ShortcutType int shortcutType) {
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         switch (shortcutType) {
-            case ACCESSIBILITY_BUTTON:
+            case ShortcutConstants.UserShortcutType.SOFTWARE:
                 if (isAccessibilityFloatingMenuEnabled(context)) {
                     return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
                 } else if (isAccessibilityGestureEnabled(context)) {
@@ -245,7 +243,7 @@
                 } else {
                     return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
                 }
-            case ACCESSIBILITY_SHORTCUT_KEY:
+            case ShortcutConstants.UserShortcutType.HARDWARE:
                 return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
         }
         return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 3fd3030..276c5c4 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -16,9 +16,6 @@
 
 package com.android.internal.accessibility.util;
 
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
 import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE;
 import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
@@ -33,7 +30,6 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
 
 import java.util.Collections;
 import java.util.List;
@@ -144,7 +140,7 @@
      * @param componentId The component id that need to be checked.
      * @return {@code true} if a component id is contained.
      */
-    public static boolean isShortcutContained(Context context, @ShortcutType int shortcutType,
+    public static boolean isShortcutContained(Context context, @UserShortcutType int shortcutType,
             @NonNull String componentId) {
         final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
@@ -166,6 +162,8 @@
                 return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
             case UserShortcutType.TRIPLETAP:
                 return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
+            case UserShortcutType.TWO_FINGERS_TRIPLE_TAP:
+                return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED;
             default:
                 throw new IllegalArgumentException(
                         "Unsupported user shortcut type: " + type);
@@ -173,24 +171,6 @@
     }
 
     /**
-     * Converts {@link ShortcutType} to {@link UserShortcutType}.
-     *
-     * @param type The shortcut type.
-     * @return Mapping type from {@link UserShortcutType}.
-     */
-    public static @UserShortcutType int convertToUserType(@ShortcutType int type) {
-        switch (type) {
-            case ACCESSIBILITY_BUTTON:
-                return UserShortcutType.SOFTWARE;
-            case ACCESSIBILITY_SHORTCUT_KEY:
-                return UserShortcutType.HARDWARE;
-            default:
-                throw new IllegalArgumentException(
-                        "Unsupported shortcut type:" + type);
-        }
-    }
-
-    /**
      * Updates an accessibility state if the accessibility service is a Always-On a11y service,
      * a.k.a. AccessibilityServices that has FLAG_REQUEST_ACCESSIBILITY_BUTTON
      * <p>
@@ -255,12 +235,13 @@
     public static Set<String> getShortcutTargetsFromSettings(
             Context context, @UserShortcutType int shortcutType, int userId) {
         final String targetKey = convertToKey(shortcutType);
-        if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)) {
+        if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)
+                || Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED
+                .equals(targetKey)) {
             boolean magnificationEnabled = Settings.Secure.getIntForUser(
                     context.getContentResolver(), targetKey, /* def= */ 0, userId) == 1;
             return magnificationEnabled ? Set.of(MAGNIFICATION_CONTROLLER_NAME)
                     : Collections.emptySet();
-
         } else {
             final String targetString = Settings.Secure.getStringForUser(
                     context.getContentResolver(), targetKey, userId);
diff --git a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
index 0a28997..b4e8749 100644
--- a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
+++ b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
@@ -116,6 +116,14 @@
         if (cantCreateUser) {
             setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED);
             return null;
+        } else if (!(isUserPropertyWithinLimit(mUserName, UserManager.MAX_USER_NAME_LENGTH)
+                && isUserPropertyWithinLimit(mAccountName, UserManager.MAX_ACCOUNT_STRING_LENGTH)
+                && isUserPropertyWithinLimit(mAccountType, UserManager.MAX_ACCOUNT_STRING_LENGTH))
+                || (mAccountOptions != null && !mAccountOptions.isBundleContentsWithinLengthLimit(
+                UserManager.MAX_ACCOUNT_OPTIONS_LENGTH))) {
+            setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED);
+            Log.i(TAG, "User properties must not exceed their character limits");
+            return null;
         } else if (cantCreateAnyMoreUsers) {
             setResult(UserManager.USER_CREATION_FAILED_NO_MORE_USERS);
             return null;
@@ -144,4 +152,8 @@
         }
         finish();
     }
+
+    private boolean isUserPropertyWithinLimit(String property, int limit) {
+        return property == null || property.length() <= limit;
+    }
 }
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 96740c5..7b3565b 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -121,10 +121,11 @@
     public static final int CUJ_PREDICTIVE_BACK_CROSS_TASK = 85;
     public static final int CUJ_PREDICTIVE_BACK_HOME = 86;
     public static final int CUJ_LAUNCHER_SEARCH_QSB_OPEN = 87;
+    public static final int CUJ_BACK_PANEL_ARROW = 88;
 
     // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
     @VisibleForTesting
-    static final int LAST_CUJ = CUJ_LAUNCHER_SEARCH_QSB_OPEN;
+    static final int LAST_CUJ = CUJ_BACK_PANEL_ARROW;
 
     /** @hide */
     @IntDef({
@@ -207,6 +208,7 @@
             CUJ_PREDICTIVE_BACK_CROSS_TASK,
             CUJ_PREDICTIVE_BACK_HOME,
             CUJ_LAUNCHER_SEARCH_QSB_OPEN,
+            CUJ_BACK_PANEL_ARROW,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -298,8 +300,8 @@
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_ACTIVITY;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_TASK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_TASK;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_HOME] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_HOME;
-        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_OPEN] =
-            FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_OPEN;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_OPEN;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_BACK_PANEL_ARROW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BACK_PANEL_ARROW;
     }
 
     private Cuj() {
@@ -474,6 +476,8 @@
                 return "PREDICTIVE_BACK_HOME";
             case CUJ_LAUNCHER_SEARCH_QSB_OPEN:
                 return "LAUNCHER_SEARCH_QSB_OPEN";
+            case CUJ_BACK_PANEL_ARROW:
+                return "BACK_PANEL_ARROW";
         }
         return "UNKNOWN";
     }
diff --git a/core/java/com/android/internal/jank/InteractionMonitorDebugOverlay.java b/core/java/com/android/internal/jank/InteractionMonitorDebugOverlay.java
index f3f16a0..d9cac12 100644
--- a/core/java/com/android/internal/jank/InteractionMonitorDebugOverlay.java
+++ b/core/java/com/android/internal/jank/InteractionMonitorDebugOverlay.java
@@ -28,6 +28,7 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Trace;
+import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.WindowCallbacks;
@@ -52,6 +53,7 @@
  * @hide
  */
 class InteractionMonitorDebugOverlay implements WindowCallbacks {
+    private static final String TAG = "InteractionMonitorDebug";
     private static final int REASON_STILL_RUNNING = -1000;
     private final Object mLock;
     // Sparse array where the key in the CUJ and the value is the session status, or null if
@@ -77,7 +79,7 @@
         mDebugPaint.setAntiAlias(false);
         mDebugFontMetrics = new Paint.FontMetrics();
         final Context context = ActivityThread.currentApplication();
-        mPackageName = context.getPackageName();
+        mPackageName = context == null ? "null" : context.getPackageName();
     }
 
     @UiThread
@@ -153,8 +155,14 @@
                           SparseArray<InteractionJankMonitor.RunningTracker> runningTrackers) {
         synchronized (mLock) {
             mRunningCujs.put(removedCuj, reason);
+            boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
+            if (isLoggable) {
+                String cujName = Cuj.getNameOfCuj(removedCuj);
+                Log.d(TAG, cujName + (reason == REASON_END_NORMAL ? " ended" : " cancelled"));
+            }
             // If REASON_STILL_RUNNING is not in mRunningCujs, then all CUJs have ended
             if (mRunningCujs.indexOfValue(REASON_STILL_RUNNING) < 0) {
+                if (isLoggable) Log.d(TAG, "All CUJs ended");
                 mRunningCujs.clear();
                 dispose();
             } else {
@@ -186,6 +194,10 @@
 
     @UiThread
     void onTrackerAdded(@Cuj.CujType int addedCuj, InteractionJankMonitor.RunningTracker tracker) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            String cujName = Cuj.getNameOfCuj(addedCuj);
+            Log.d(TAG, cujName + " started");
+        }
         synchronized (mLock) {
             // Use REASON_STILL_RUNNING (not technically one of the '@Reasons') to indicate the CUJ
             // is still running
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 7a79e0f..aa60cc9 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -490,7 +490,7 @@
      * Returns true if this instance only supports reading history.
      */
     public boolean isReadOnly() {
-        return mActiveFile == null || mHistoryDir == null;
+        return !mMutable || mActiveFile == null || mHistoryDir == null;
     }
 
     /**
@@ -508,6 +508,13 @@
      * create next history file.
      */
     public void startNextFile(long elapsedRealtimeMs) {
+        synchronized (this) {
+            startNextFileLocked(elapsedRealtimeMs);
+        }
+    }
+
+    @GuardedBy("this")
+    private void startNextFileLocked(long elapsedRealtimeMs) {
         if (mMaxHistoryFiles == 0) {
             Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history");
             return;
@@ -548,10 +555,7 @@
         }
 
         mWrittenPowerStatsDescriptors.clear();
-
-        synchronized (this) {
-            cleanupLocked();
-        }
+        cleanupLocked();
     }
 
     @GuardedBy("this")
@@ -599,27 +603,31 @@
      * number 0 again.
      */
     public void reset() {
-        if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
-        for (BatteryHistoryFile file : mHistoryFiles) {
-            file.atomicFile.delete();
+        synchronized (this) {
+            if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
+            for (BatteryHistoryFile file : mHistoryFiles) {
+                file.atomicFile.delete();
+            }
+            mHistoryFiles.clear();
+
+            BatteryHistoryFile name = makeBatteryHistoryFile();
+            mHistoryFiles.add(name);
+            setActiveFile(name);
+
+            initHistoryBuffer();
         }
-        mHistoryFiles.clear();
-
-        BatteryHistoryFile name = makeBatteryHistoryFile();
-        mHistoryFiles.add(name);
-        setActiveFile(name);
-
-        initHistoryBuffer();
     }
 
     /**
      * Returns the monotonic clock time when the available battery history collection started.
      */
     public long getStartTime() {
-        if (!mHistoryFiles.isEmpty()) {
-            return mHistoryFiles.get(0).monotonicTimeMs;
-        } else {
-            return mHistoryBufferStartTime;
+        synchronized (this) {
+            if (!mHistoryFiles.isEmpty()) {
+                return mHistoryFiles.get(0).monotonicTimeMs;
+            } else {
+                return mHistoryBufferStartTime;
+            }
         }
     }
 
@@ -633,11 +641,14 @@
      */
     @NonNull
     public BatteryStatsHistoryIterator iterate(long startTimeMs, long endTimeMs) {
+        if (mMutable) {
+            return copy().iterate(startTimeMs, endTimeMs);
+        }
+
         mCurrentFileIndex = 0;
         mCurrentParcel = null;
         mCurrentParcelEnd = 0;
         mParcelIndex = 0;
-        mMutable = false;
         if (mWritableHistory != null) {
             synchronized (mWritableHistory) {
                 mWritableHistory.setCleanupEnabledLocked(false);
@@ -650,14 +661,11 @@
      * Finish iterating history files and history buffer.
      */
     void iteratorFinished() {
-        // setDataPosition so mHistoryBuffer Parcel can be written.
         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
         if (mWritableHistory != null) {
             synchronized (mWritableHistory) {
                 mWritableHistory.setCleanupEnabledLocked(true);
             }
-        } else {
-            mMutable = true;
         }
     }
 
@@ -671,6 +679,8 @@
      */
     @Nullable
     public Parcel getNextParcel(long startTimeMs, long endTimeMs) {
+        checkImmutable();
+
         // First iterate through all records in current parcel.
         if (mCurrentParcel != null) {
             if (mCurrentParcel.dataPosition() < mCurrentParcelEnd) {
@@ -754,6 +764,12 @@
         return mCurrentParcel;
     }
 
+    private void checkImmutable() {
+        if (mMutable) {
+            throw new IllegalStateException("Iterating over a mutable battery history");
+        }
+    }
+
     /**
      * Read history file into a parcel.
      *
@@ -863,8 +879,10 @@
      * @param out the output parcel
      */
     public void writeToParcel(Parcel out) {
-        writeHistoryBuffer(out);
-        writeToParcel(out, false /* useBlobs */);
+        synchronized (this) {
+            writeHistoryBuffer(out);
+            writeToParcel(out, false /* useBlobs */);
+        }
     }
 
     /**
@@ -874,8 +892,10 @@
      * @param out the output parcel
      */
     public void writeToBatteryUsageStatsParcel(Parcel out) {
-        out.writeBlob(mHistoryBuffer.marshall());
-        writeToParcel(out, true /* useBlobs */);
+        synchronized (this) {
+            out.writeBlob(mHistoryBuffer.marshall());
+            writeToParcel(out, true /* useBlobs */);
+        }
     }
 
     private void writeToParcel(Parcel out, boolean useBlobs) {
@@ -1022,14 +1042,18 @@
      * Enables/disables recording of history.  When disabled, all "record*" calls are a no-op.
      */
     public void setHistoryRecordingEnabled(boolean enabled) {
-        mRecordingHistory = enabled;
+        synchronized (this) {
+            mRecordingHistory = enabled;
+        }
     }
 
     /**
      * Returns true if history recording is enabled.
      */
     public boolean isRecordingHistory() {
-        return mRecordingHistory;
+        synchronized (this) {
+            return mRecordingHistory;
+        }
     }
 
     /**
@@ -1037,8 +1061,10 @@
      */
     @VisibleForTesting
     public void forceRecordAllHistory() {
-        mHaveBatteryLevel = true;
-        mRecordingHistory = true;
+        synchronized (this) {
+            mHaveBatteryLevel = true;
+            mRecordingHistory = true;
+        }
     }
 
     /**
@@ -1046,37 +1072,43 @@
      */
     public void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
             boolean reset) {
-        mRecordingHistory = true;
-        mHistoryCur.currentTime = mClock.currentTimeMillis();
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
-                reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME);
-        mHistoryCur.currentTime = 0;
+        synchronized (this) {
+            mRecordingHistory = true;
+            mHistoryCur.currentTime = mClock.currentTimeMillis();
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
+                    reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME);
+            mHistoryCur.currentTime = 0;
+        }
     }
 
     /**
      * Prepares to continue recording after restoring previous history from persistent storage.
      */
     public void continueRecordingHistory() {
-        if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
-            return;
-        }
+        synchronized (this) {
+            if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
+                return;
+            }
 
-        mRecordingHistory = true;
-        final long elapsedRealtimeMs = mClock.elapsedRealtime();
-        final long uptimeMs = mClock.uptimeMillis();
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START);
-        startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
+            mRecordingHistory = true;
+            final long elapsedRealtimeMs = mClock.elapsedRealtime();
+            final long uptimeMs = mClock.uptimeMillis();
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START);
+            startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
+        }
     }
 
     /**
      * Notes the current battery state to be reflected in the next written history item.
      */
     public void setBatteryState(boolean charging, int status, int level, int chargeUah) {
-        mHaveBatteryLevel = true;
-        setChargingState(charging);
-        mHistoryCur.batteryStatus = (byte) status;
-        mHistoryCur.batteryLevel = (byte) level;
-        mHistoryCur.batteryChargeUah = chargeUah;
+        synchronized (this) {
+            mHaveBatteryLevel = true;
+            setChargingState(charging);
+            mHistoryCur.batteryStatus = (byte) status;
+            mHistoryCur.batteryLevel = (byte) level;
+            mHistoryCur.batteryChargeUah = chargeUah;
+        }
     }
 
     /**
@@ -1084,24 +1116,28 @@
      */
     public void setBatteryState(int status, int level, int health, int plugType, int temperature,
             int voltageMv, int chargeUah) {
-        mHaveBatteryLevel = true;
-        mHistoryCur.batteryStatus = (byte) status;
-        mHistoryCur.batteryLevel = (byte) level;
-        mHistoryCur.batteryHealth = (byte) health;
-        mHistoryCur.batteryPlugType = (byte) plugType;
-        mHistoryCur.batteryTemperature = (short) temperature;
-        mHistoryCur.batteryVoltage = (char) voltageMv;
-        mHistoryCur.batteryChargeUah = chargeUah;
+        synchronized (this) {
+            mHaveBatteryLevel = true;
+            mHistoryCur.batteryStatus = (byte) status;
+            mHistoryCur.batteryLevel = (byte) level;
+            mHistoryCur.batteryHealth = (byte) health;
+            mHistoryCur.batteryPlugType = (byte) plugType;
+            mHistoryCur.batteryTemperature = (short) temperature;
+            mHistoryCur.batteryVoltage = (char) voltageMv;
+            mHistoryCur.batteryChargeUah = chargeUah;
+        }
     }
 
     /**
      * Notes the current power plugged-in state to be reflected in the next written history item.
      */
     public void setPluggedInState(boolean pluggedIn) {
-        if (pluggedIn) {
-            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
-        } else {
-            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+        synchronized (this) {
+            if (pluggedIn) {
+                mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+            } else {
+                mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+            }
         }
     }
 
@@ -1109,10 +1145,12 @@
      * Notes the current battery charging state to be reflected in the next written history item.
      */
     public void setChargingState(boolean charging) {
-        if (charging) {
-            mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
-        } else {
-            mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
+        synchronized (this) {
+            if (charging) {
+                mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
+            } else {
+                mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
+            }
         }
     }
 
@@ -1121,38 +1159,44 @@
      */
     public void recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name,
             int uid) {
-        mHistoryCur.eventCode = code;
-        mHistoryCur.eventTag = mHistoryCur.localEventTag;
-        mHistoryCur.eventTag.string = name;
-        mHistoryCur.eventTag.uid = uid;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.eventCode = code;
+            mHistoryCur.eventTag = mHistoryCur.localEventTag;
+            mHistoryCur.eventTag.string = name;
+            mHistoryCur.eventTag.uid = uid;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
      * Records a time change event.
      */
     public void recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
-        if (!mRecordingHistory) {
-            return;
-        }
+        synchronized (this) {
+            if (!mRecordingHistory) {
+                return;
+            }
 
-        mHistoryCur.currentTime = currentTimeMs;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
-                HistoryItem.CMD_CURRENT_TIME);
-        mHistoryCur.currentTime = 0;
+            mHistoryCur.currentTime = currentTimeMs;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
+                    HistoryItem.CMD_CURRENT_TIME);
+            mHistoryCur.currentTime = 0;
+        }
     }
 
     /**
      * Records a system shutdown event.
      */
     public void recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
-        if (!mRecordingHistory) {
-            return;
-        }
+        synchronized (this) {
+            if (!mRecordingHistory) {
+                return;
+            }
 
-        mHistoryCur.currentTime = currentTimeMs;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN);
-        mHistoryCur.currentTime = 0;
+            mHistoryCur.currentTime = currentTimeMs;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN);
+            mHistoryCur.currentTime = 0;
+        }
     }
 
     /**
@@ -1160,13 +1204,15 @@
      */
     public void recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel,
             boolean isPlugged) {
-        mHistoryCur.batteryLevel = (byte) batteryLevel;
-        setPluggedInState(isPlugged);
-        if (DEBUG) {
-            Slog.v(TAG, "Battery unplugged to: "
-                    + Integer.toHexString(mHistoryCur.states));
+        synchronized (this) {
+            mHistoryCur.batteryLevel = (byte) batteryLevel;
+            setPluggedInState(isPlugged);
+            if (DEBUG) {
+                Slog.v(TAG, "Battery unplugged to: "
+                        + Integer.toHexString(mHistoryCur.states));
+            }
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
         }
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
     }
 
     /**
@@ -1174,9 +1220,11 @@
      */
     public void recordPowerStats(long elapsedRealtimeMs, long uptimeMs,
             PowerStats powerStats) {
-        mHistoryCur.powerStats = powerStats;
-        mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.powerStats = powerStats;
+            mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1184,11 +1232,13 @@
      */
     public void recordProcessStateChange(long elapsedRealtimeMs, long uptimeMs,
             int uid, @BatteryConsumer.ProcessState int processState) {
-        mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
-        mHistoryCur.processStateChange.uid = uid;
-        mHistoryCur.processStateChange.processState = processState;
-        mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
+            mHistoryCur.processStateChange.uid = uid;
+            mHistoryCur.processStateChange.processState = processState;
+            mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1197,8 +1247,10 @@
      */
     public void recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs,
             double monitoredRailChargeMah) {
-        mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1206,10 +1258,12 @@
      */
     public void recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
             int uid) {
-        mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-        mHistoryCur.wakelockTag.string = historyName;
-        mHistoryCur.wakelockTag.uid = uid;
-        recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+        synchronized (this) {
+            mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+            mHistoryCur.wakelockTag.string = historyName;
+            mHistoryCur.wakelockTag.uid = uid;
+            recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+        }
     }
 
     /**
@@ -1217,18 +1271,20 @@
      */
     public boolean maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName,
             int uid) {
-        if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) {
-            return false;
+        synchronized (this) {
+            if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) {
+                return false;
+            }
+            if (mHistoryLastWritten.wakelockTag != null) {
+                // We'll try to update the last tag.
+                mHistoryLastWritten.wakelockTag = null;
+                mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+                mHistoryCur.wakelockTag.string = historyName;
+                mHistoryCur.wakelockTag.uid = uid;
+                writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+            }
+            return true;
         }
-        if (mHistoryLastWritten.wakelockTag != null) {
-            // We'll try to update the last tag.
-            mHistoryLastWritten.wakelockTag = null;
-            mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-            mHistoryCur.wakelockTag.string = historyName;
-            mHistoryCur.wakelockTag.uid = uid;
-            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
-        }
-        return true;
     }
 
     /**
@@ -1236,26 +1292,32 @@
      */
     public void recordWakelockStopEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
             int uid) {
-        mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-        mHistoryCur.wakelockTag.string = historyName != null ? historyName : "";
-        mHistoryCur.wakelockTag.uid = uid;
-        recordStateStopEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+        synchronized (this) {
+            mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+            mHistoryCur.wakelockTag.string = historyName != null ? historyName : "";
+            mHistoryCur.wakelockTag.uid = uid;
+            recordStateStopEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+        }
     }
 
     /**
      * Records an event when some state flag changes to true.
      */
     public void recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
-        mHistoryCur.states |= stateFlags;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states |= stateFlags;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
      * Records an event when some state flag changes to false.
      */
     public void recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
-        mHistoryCur.states &= ~stateFlags;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states &= ~stateFlags;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1263,34 +1325,42 @@
      */
     public void recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags,
             int stateStopFlags) {
-        mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
      * Records an event when some state2 flag changes to true.
      */
     public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
-        mHistoryCur.states2 |= stateFlags;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states2 |= stateFlags;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
      * Records an event when some state2 flag changes to false.
      */
     public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
-        mHistoryCur.states2 &= ~stateFlags;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states2 &= ~stateFlags;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
      * Records an wakeup event.
      */
     public void recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason) {
-        mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
-        mHistoryCur.wakeReasonTag.string = reason;
-        mHistoryCur.wakeReasonTag.uid = 0;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
+            mHistoryCur.wakeReasonTag.string = reason;
+            mHistoryCur.wakeReasonTag.uid = 0;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1298,10 +1368,12 @@
      */
     public void recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs,
             int brightnessBin) {
-        mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
-                HistoryItem.STATE_BRIGHTNESS_SHIFT,
-                HistoryItem.STATE_BRIGHTNESS_MASK);
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
+                    HistoryItem.STATE_BRIGHTNESS_SHIFT,
+                    HistoryItem.STATE_BRIGHTNESS_MASK);
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1309,20 +1381,24 @@
      */
     public void recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs,
             int signalLevel) {
-        mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
-                HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
-                HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
+                    HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
+                    HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
      * Records a device idle mode change event.
      */
     public void recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode) {
-        mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
-                HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
-                HistoryItem.STATE2_DEVICE_IDLE_MASK);
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
+                    HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
+                    HistoryItem.STATE2_DEVICE_IDLE_MASK);
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1330,20 +1406,22 @@
      */
     public void recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag,
             int removeStateFlag, int state, int signalStrength) {
-        mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
-        if (state != -1) {
-            mHistoryCur.states =
-                    setBitField(mHistoryCur.states, state,
-                            HistoryItem.STATE_PHONE_STATE_SHIFT,
-                            HistoryItem.STATE_PHONE_STATE_MASK);
+        synchronized (this) {
+            mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
+            if (state != -1) {
+                mHistoryCur.states =
+                        setBitField(mHistoryCur.states, state,
+                                HistoryItem.STATE_PHONE_STATE_SHIFT,
+                                HistoryItem.STATE_PHONE_STATE_MASK);
+            }
+            if (signalStrength != -1) {
+                mHistoryCur.states =
+                        setBitField(mHistoryCur.states, signalStrength,
+                                HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
+                                HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
+            }
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
         }
-        if (signalStrength != -1) {
-            mHistoryCur.states =
-                    setBitField(mHistoryCur.states, signalStrength,
-                            HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
-                            HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
-        }
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
     }
 
     /**
@@ -1351,10 +1429,12 @@
      */
     public void recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs,
             int dataConnectionType) {
-        mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
-                HistoryItem.STATE_DATA_CONNECTION_SHIFT,
-                HistoryItem.STATE_DATA_CONNECTION_MASK);
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
+                    HistoryItem.STATE_DATA_CONNECTION_SHIFT,
+                    HistoryItem.STATE_DATA_CONNECTION_MASK);
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1362,10 +1442,12 @@
      */
     public void recordNrStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
             int nrState) {
-        mHistoryCur.states2 = setBitField(mHistoryCur.states2, nrState,
-                HistoryItem.STATE2_NR_STATE_SHIFT,
-                HistoryItem.STATE2_NR_STATE_MASK);
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states2 = setBitField(mHistoryCur.states2, nrState,
+                    HistoryItem.STATE2_NR_STATE_SHIFT,
+                    HistoryItem.STATE2_NR_STATE_MASK);
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1373,11 +1455,13 @@
      */
     public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
             int supplState) {
-        mHistoryCur.states2 =
-                setBitField(mHistoryCur.states2, supplState,
-                        HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
-                        HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states2 =
+                    setBitField(mHistoryCur.states2, supplState,
+                            HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
+                            HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1385,11 +1469,13 @@
      */
     public void recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs,
             int strengthBin) {
-        mHistoryCur.states2 =
-                setBitField(mHistoryCur.states2, strengthBin,
-                        HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
-                        HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        synchronized (this) {
+            mHistoryCur.states2 =
+                    setBitField(mHistoryCur.states2, strengthBin,
+                            HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
+                            HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     /**
@@ -1446,25 +1532,30 @@
      * Writes the current history item to history.
      */
     public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
-        if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
-            final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
-            final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
-            if (diffUptimeMs < (diffElapsedMs - 20)) {
-                final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
-                mHistoryAddTmp.setTo(mHistoryLastWritten);
-                mHistoryAddTmp.wakelockTag = null;
-                mHistoryAddTmp.wakeReasonTag = null;
-                mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
-                mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
-                writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
+        synchronized (this) {
+            if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
+                final long diffElapsedMs =
+                        elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
+                final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
+                if (diffUptimeMs < (diffElapsedMs - 20)) {
+                    final long wakeElapsedTimeMs =
+                            elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
+                    mHistoryAddTmp.setTo(mHistoryLastWritten);
+                    mHistoryAddTmp.wakelockTag = null;
+                    mHistoryAddTmp.wakeReasonTag = null;
+                    mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
+                    mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
+                    writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
+                }
             }
+            mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
+            mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
+            mTrackRunningHistoryUptimeMs = uptimeMs;
+            writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur);
         }
-        mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
-        mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
-        mTrackRunningHistoryUptimeMs = uptimeMs;
-        writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur);
     }
 
+    @GuardedBy("this")
     private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
         if (mTracer != null && mTracer.tracingEnabled()) {
             recordTraceEvents(cur.eventCode, cur.eventTag);
@@ -1591,6 +1682,7 @@
         writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE);
     }
 
+    @GuardedBy("this")
     private void writeHistoryItem(long elapsedRealtimeMs,
             @SuppressWarnings("UnusedVariable") long uptimeMs, HistoryItem cur, byte cmd) {
         if (!mMutable) {
@@ -1701,7 +1793,8 @@
     /**
      * Writes the delta between the previous and current history items into history buffer.
      */
-    public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
+    @GuardedBy("this")
+    private void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
         if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
             dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS);
             cur.writeToParcel(dest, 0);
@@ -1921,6 +2014,7 @@
      * while writing the current history buffer, the method returns
      * <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code>
      */
+    @GuardedBy("this")
     private int writeHistoryTag(HistoryTag tag) {
         if (tag.string == null) {
             Slog.wtfStack(TAG, "writeHistoryTag called with null name");
@@ -1964,33 +2058,37 @@
      * Don't allow any more batching in to the current history event.
      */
     public void commitCurrentHistoryBatchLocked() {
-        mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+        synchronized (this) {
+            mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+        }
     }
 
     /**
      * Saves the accumulated history buffer in the active file, see {@link #getActiveFile()} .
      */
     public void writeHistory() {
-        if (isReadOnly()) {
-            Slog.w(TAG, "writeHistory: this instance instance is read-only");
-            return;
-        }
-
-        // Save the monotonic time first, so that even if the history write below fails,
-        // we still wouldn't end up with overlapping history timelines.
-        mMonotonicClock.write();
-
-        Parcel p = Parcel.obtain();
-        try {
-            final long start = SystemClock.uptimeMillis();
-            writeHistoryBuffer(p);
-            if (DEBUG) {
-                Slog.d(TAG, "writeHistoryBuffer duration ms:"
-                        + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
+        synchronized (this) {
+            if (isReadOnly()) {
+                Slog.w(TAG, "writeHistory: this instance instance is read-only");
+                return;
             }
-            writeParcelToFileLocked(p, mActiveFile);
-        } finally {
-            p.recycle();
+
+            // Save the monotonic time first, so that even if the history write below fails,
+            // we still wouldn't end up with overlapping history timelines.
+            mMonotonicClock.write();
+
+            Parcel p = Parcel.obtain();
+            try {
+                final long start = SystemClock.uptimeMillis();
+                writeHistoryBuffer(p);
+                if (DEBUG) {
+                    Slog.d(TAG, "writeHistoryBuffer duration ms:"
+                            + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
+                }
+                writeParcelToFileLocked(p, mActiveFile);
+            } finally {
+                p.recycle();
+            }
         }
     }
 
@@ -1998,35 +2096,38 @@
      * Reads history buffer from a persisted Parcel.
      */
     public void readHistoryBuffer(Parcel in) throws ParcelFormatException {
-        final int version = in.readInt();
-        if (version != BatteryStatsHistory.VERSION) {
-            Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
-                    + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats");
-            return;
-        }
-
-        mHistoryBufferStartTime = in.readLong();
-        mHistoryBuffer.setDataSize(0);
-        mHistoryBuffer.setDataPosition(0);
-
-        int bufSize = in.readInt();
-        int curPos = in.dataPosition();
-        if (bufSize >= (mMaxHistoryBufferSize * 100)) {
-            throw new ParcelFormatException(
-                    "File corrupt: history data buffer too large " + bufSize);
-        } else if ((bufSize & ~3) != bufSize) {
-            throw new ParcelFormatException(
-                    "File corrupt: history data buffer not aligned " + bufSize);
-        } else {
-            if (DEBUG) {
-                Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
-                        + " bytes at " + curPos);
+        synchronized (this) {
+            final int version = in.readInt();
+            if (version != BatteryStatsHistory.VERSION) {
+                Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
+                        + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats");
+                return;
             }
-            mHistoryBuffer.appendFrom(in, curPos, bufSize);
-            in.setDataPosition(curPos + bufSize);
+
+            mHistoryBufferStartTime = in.readLong();
+            mHistoryBuffer.setDataSize(0);
+            mHistoryBuffer.setDataPosition(0);
+
+            int bufSize = in.readInt();
+            int curPos = in.dataPosition();
+            if (bufSize >= (mMaxHistoryBufferSize * 100)) {
+                throw new ParcelFormatException(
+                        "File corrupt: history data buffer too large " + bufSize);
+            } else if ((bufSize & ~3) != bufSize) {
+                throw new ParcelFormatException(
+                        "File corrupt: history data buffer not aligned " + bufSize);
+            } else {
+                if (DEBUG) {
+                    Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
+                            + " bytes at " + curPos);
+                }
+                mHistoryBuffer.appendFrom(in, curPos, bufSize);
+                in.setDataPosition(curPos + bufSize);
+            }
         }
     }
 
+    @GuardedBy("this")
     private void writeHistoryBuffer(Parcel out) {
         out.writeInt(BatteryStatsHistory.VERSION);
         out.writeLong(mHistoryBufferStartTime);
@@ -2038,6 +2139,7 @@
         out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
     }
 
+    @GuardedBy("this")
     private void writeParcelToFileLocked(Parcel p, AtomicFile file) {
         FileOutputStream fos = null;
         mWriteLock.lock();
@@ -2066,34 +2168,43 @@
      * Returns the total number of history tags in the tag pool.
      */
     public int getHistoryStringPoolSize() {
-        return mHistoryTagPool.size();
+        synchronized (this) {
+            return mHistoryTagPool.size();
+        }
     }
 
     /**
      * Returns the total number of bytes occupied by the history tag pool.
      */
     public int getHistoryStringPoolBytes() {
-        return mNumHistoryTagChars;
+        synchronized (this) {
+            return mNumHistoryTagChars;
+        }
     }
 
     /**
      * Returns the string held by the requested history tag.
      */
     public String getHistoryTagPoolString(int index) {
-        ensureHistoryTagArray();
-        HistoryTag historyTag = mHistoryTags.get(index);
-        return historyTag != null ? historyTag.string : null;
+        synchronized (this) {
+            ensureHistoryTagArray();
+            HistoryTag historyTag = mHistoryTags.get(index);
+            return historyTag != null ? historyTag.string : null;
+        }
     }
 
     /**
      * Returns the UID held by the requested history tag.
      */
     public int getHistoryTagPoolUid(int index) {
-        ensureHistoryTagArray();
-        HistoryTag historyTag = mHistoryTags.get(index);
-        return historyTag != null ? historyTag.uid : Process.INVALID_UID;
+        synchronized (this) {
+            ensureHistoryTagArray();
+            HistoryTag historyTag = mHistoryTags.get(index);
+            return historyTag != null ? historyTag.uid : Process.INVALID_UID;
+        }
     }
 
+    @GuardedBy("this")
     private void ensureHistoryTagArray() {
         if (mHistoryTags != null) {
             return;
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
index c6683cf..05728ee 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
@@ -18,9 +18,13 @@
 
 import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.UriRelativeFilter;
+import android.content.UriRelativeFilterGroup;
+import android.content.pm.Flags;
 import android.content.pm.parsing.result.ParseInput;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.res.Resources;
@@ -132,6 +136,11 @@
                 case "data":
                     result = parseData(intentInfo, res, parser, allowGlobs, input);
                     break;
+                case "uri-relative-filter-group":
+                    if (Flags.relativeReferenceIntentFilters()) {
+                        result = parseRelRefGroup(intentInfo, pkg, res, parser, allowGlobs, input);
+                        break;
+                    }
                 default:
                     result = ParsingUtils.unknownTag("<intent-filter>", pkg, parser, input);
                     break;
@@ -163,6 +172,197 @@
     }
 
     @NonNull
+    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+    private static ParseResult<ParsedIntentInfo> parseRelRefGroup(ParsedIntentInfo intentInfo,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, boolean allowGlobs,
+            ParseInput input) throws XmlPullParserException, IOException {
+        IntentFilter intentFilter = intentInfo.getIntentFilter();
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestUriRelativeFilterGroup);
+        UriRelativeFilterGroup group;
+        try {
+            int action = UriRelativeFilterGroup.ACTION_ALLOW;
+            if (!sa.getBoolean(R.styleable.AndroidManifestUriRelativeFilterGroup_allow, true)) {
+                action = UriRelativeFilterGroup.ACTION_BLOCK;
+            }
+            group = new UriRelativeFilterGroup(action);
+        } finally {
+            sa.recycle();
+        }
+        final int depth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > depth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final ParseResult result;
+            String nodeName = parser.getName();
+            switch (nodeName) {
+                case "data":
+                    result = parseRelRefGroupData(group, res, parser, allowGlobs, input);
+                    break;
+                default:
+                    result = ParsingUtils.unknownTag("<uri-relative-filter-group>",
+                            pkg, parser, input);
+                    break;
+            }
+
+            if (result.isError()) {
+                return input.error(result);
+            }
+        }
+
+        if (group.getUriRelativeFilters().size() > 0) {
+            intentFilter.addUriRelativeFilterGroup(group);
+        }
+        return input.success(null);
+    }
+
+    @NonNull
+    @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+    private static ParseResult<ParsedIntentInfo> parseRelRefGroupData(UriRelativeFilterGroup group,
+            Resources res, XmlResourceParser parser, boolean allowGlobs, ParseInput input) {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestData);
+        try {
+            String str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_path, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+                        PatternMatcher.PATTERN_LITERAL, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_pathPrefix, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+                        PatternMatcher.PATTERN_PREFIX, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_pathPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "pathPattern not allowed here; path must be literal");
+                }
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+                        PatternMatcher.PATTERN_SIMPLE_GLOB, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "pathAdvancedPattern not allowed here; path must be literal");
+                }
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+                        PatternMatcher.PATTERN_ADVANCED_GLOB, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_pathSuffix, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+                        PatternMatcher.PATTERN_SUFFIX, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_fragment, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+                        PatternMatcher.PATTERN_LITERAL, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_fragmentPrefix, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+                        PatternMatcher.PATTERN_PREFIX, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_fragmentPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "fragmentPattern not allowed here; fragment must be literal");
+                }
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+                        PatternMatcher.PATTERN_SIMPLE_GLOB, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_fragmentAdvancedPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "fragmentAdvancedPattern not allowed here; fragment must be literal");
+                }
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+                        PatternMatcher.PATTERN_ADVANCED_GLOB, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_fragmentSuffix, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+                        PatternMatcher.PATTERN_SUFFIX, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_query, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+                        PatternMatcher.PATTERN_LITERAL, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_queryPrefix, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+                        PatternMatcher.PATTERN_PREFIX, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_queryPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "queryPattern not allowed here; query must be literal");
+                }
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+                        PatternMatcher.PATTERN_SIMPLE_GLOB, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_queryAdvancedPattern, 0);
+            if (str != null) {
+                if (!allowGlobs) {
+                    return input.error(
+                            "queryAdvancedPattern not allowed here; query must be literal");
+                }
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+                        PatternMatcher.PATTERN_ADVANCED_GLOB, str));
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestData_querySuffix, 0);
+            if (str != null) {
+                group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+                        PatternMatcher.PATTERN_SUFFIX, str));
+            }
+
+            return input.success(null);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    @NonNull
     private static ParseResult<ParsedIntentInfo> parseData(ParsedIntentInfo intentInfo,
             Resources resources, XmlResourceParser parser, boolean allowGlobs, ParseInput input) {
         IntentFilter intentFilter = intentInfo.getIntentFilter();
diff --git a/core/java/com/android/internal/policy/SystemBarUtils.java b/core/java/com/android/internal/policy/SystemBarUtils.java
index 7a1ac07..efa3697 100644
--- a/core/java/com/android/internal/policy/SystemBarUtils.java
+++ b/core/java/com/android/internal/policy/SystemBarUtils.java
@@ -19,8 +19,9 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Insets;
-import android.util.RotationUtils;
+import android.view.Display;
 import android.view.DisplayCutout;
+import android.view.DisplayInfo;
 import android.view.Surface;
 
 import com.android.internal.R;
@@ -56,21 +57,21 @@
      */
     public static int getStatusBarHeightForRotation(
             Context context, @Surface.Rotation int targetRot) {
-        final int rotation = context.getDisplay().getRotation();
-        final DisplayCutout cutout = context.getDisplay().getCutout();
-
-        Insets insets = cutout == null ? Insets.NONE : Insets.of(cutout.getSafeInsets());
-        Insets waterfallInsets = cutout == null ? Insets.NONE : cutout.getWaterfallInsets();
-        // rotate insets to target rotation if needed.
-        if (rotation != targetRot) {
-            if (!insets.equals(Insets.NONE)) {
-                insets = RotationUtils.rotateInsets(
-                        insets, RotationUtils.deltaRotation(rotation, targetRot));
-            }
-            if (!waterfallInsets.equals(Insets.NONE)) {
-                waterfallInsets = RotationUtils.rotateInsets(
-                        waterfallInsets, RotationUtils.deltaRotation(rotation, targetRot));
-            }
+        final Display display = context.getDisplay();
+        final int rotation = display.getRotation();
+        final DisplayCutout cutout = display.getCutout();
+        DisplayInfo info = new DisplayInfo();
+        display.getDisplayInfo(info);
+        Insets insets;
+        Insets waterfallInsets;
+        if (cutout == null) {
+            insets = Insets.NONE;
+            waterfallInsets = Insets.NONE;
+        } else {
+            DisplayCutout rotated =
+                    cutout.getRotated(info.logicalWidth, info.logicalHeight, rotation, targetRot);
+            insets = Insets.of(rotated.getSafeInsets());
+            waterfallInsets = rotated.getWaterfallInsets();
         }
         final int defaultSize =
                 context.getResources().getDimensionPixelSize(R.dimen.status_bar_height_default);
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 42be784..a8d0d37 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -105,6 +105,9 @@
     private int mConversationIconTopPaddingExpandedGroup;
     private int mConversationIconTopPadding;
     private int mExpandedGroupMessagePadding;
+    // TODO (b/217799515) Currently, mConversationText shows the conversation title, the actual
+    //  conversation text is inside of mMessagingLinearLayout, which is misleading, we should rename
+    //  this to mConversationTitleView
     private TextView mConversationText;
     private View mConversationIconBadge;
     private CachingIconView mConversationIconBadgeBg;
@@ -125,6 +128,11 @@
     private int mNotificationBackgroundColor;
     private CharSequence mFallbackChatName;
     private CharSequence mFallbackGroupChatName;
+    //TODO (b/217799515) Currently, Notification.MessagingStyle, ConversationLayout, and
+    // HybridConversationNotificationView, each has their own definition of "ConversationTitle".
+    // What make things worse is that the term of "ConversationTitle" often confuses with
+    // "ConversationText".
+    // We need to unify them or differentiate the namings.
     private CharSequence mConversationTitle;
     private int mMessageSpacingStandard;
     private int mMessageSpacingGroup;
@@ -160,12 +168,12 @@
     }
 
     public ConversationLayout(@NonNull Context context, @Nullable AttributeSet attrs,
-            @AttrRes int defStyleAttr) {
+                              @AttrRes int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }
 
     public ConversationLayout(@NonNull Context context, @Nullable AttributeSet attrs,
-            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+                              @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
@@ -297,13 +305,17 @@
         mNameReplacement = nameReplacement;
     }
 
-    /** Sets this conversation as "important", adding some additional UI treatment. */
+    /**
+     * Sets this conversation as "important", adding some additional UI treatment.
+     */
     @RemotableViewMethod
     public void setIsImportantConversation(boolean isImportantConversation) {
         setIsImportantConversation(isImportantConversation, false);
     }
 
-    /** @hide **/
+    /**
+     * @hide
+     **/
     public void setIsImportantConversation(boolean isImportantConversation, boolean animate) {
         mImportantConversation = isImportantConversation;
         mImportanceRingView.setVisibility(isImportantConversation && mIcon.getVisibility() != GONE
@@ -386,6 +398,7 @@
 
     /**
      * Set conversation data
+     *
      * @param extras Bundle contains conversation data
      */
     @RemotableViewMethod(asyncImpl = "setDataAsync")
@@ -427,6 +440,7 @@
      * RemotableViewMethod's asyncImpl of {@link #setData(Bundle)}.
      * This should be called on a background thread, and returns a Runnable which is then must be
      * called on the main thread to complete the operation and set text.
+     *
      * @param extras Bundle contains conversation data
      * @hide
      */
@@ -449,6 +463,7 @@
 
     /**
      * enable/disable precomputed text usage
+     *
      * @hide
      */
     public void setPrecomputedTextEnabled(boolean precomputedTextEnabled) {
@@ -466,7 +481,9 @@
         mImageResolver = resolver;
     }
 
-    /** @hide */
+    /**
+     * @hide
+     */
     public void setUnreadCount(int unreadCount) {
         mExpandButton.setNumber(unreadCount);
     }
@@ -795,6 +812,10 @@
         mConversationTitle = conversationTitle != null ? conversationTitle.toString() : null;
     }
 
+    // TODO (b/217799515) getConversationTitle is not consistent with setConversationTitle
+    //  if you call getConversationTitle() immediately after setConversationTitle(), the result
+    //  will not correctly reflect the new change without calling updateConversationLayout, for
+    //  example.
     public CharSequence getConversationTitle() {
         return mConversationText.getText();
     }
@@ -914,7 +935,7 @@
     }
 
     private void createGroupViews(List<List<MessagingMessage>> groups,
-            List<Person> senders, boolean showSpinner) {
+                                  List<Person> senders, boolean showSpinner) {
         mGroups.clear();
         for (int groupIndex = 0; groupIndex < groups.size(); groupIndex++) {
             List<MessagingMessage> group = groups.get(groupIndex);
@@ -963,8 +984,8 @@
     }
 
     private void findGroups(List<MessagingMessage> historicMessages,
-            List<MessagingMessage> messages, List<List<MessagingMessage>> groups,
-            List<Person> senders) {
+                            List<MessagingMessage> messages, List<List<MessagingMessage>> groups,
+                            List<Person> senders) {
         CharSequence currentSenderKey = null;
         List<MessagingMessage> currentGroup = null;
         int histSize = historicMessages.size();
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 0704cb8..5da6435 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -18,9 +18,11 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.os.Build;
 import android.os.Trace;
 import android.text.BoringLayout;
 import android.text.Layout;
+import android.text.PrecomputedText;
 import android.text.StaticLayout;
 import android.text.TextUtils;
 import android.text.method.TransformationMethod;
@@ -48,6 +50,10 @@
     private int mLayoutMaxLines = -1;
     private int mImageEndMargin;
 
+    private int mStaticLayoutCreationCountInOnMeasure = 0;
+
+    private static final boolean TRACE_ONMEASURE = Build.isDebuggable();
+
     public ImageFloatingTextView(Context context) {
         this(context, null);
     }
@@ -71,7 +77,10 @@
     protected Layout makeSingleLayout(int wantWidth, BoringLayout.Metrics boring, int ellipsisWidth,
             Layout.Alignment alignment, boolean shouldEllipsize,
             TextUtils.TruncateAt effectiveEllipsize, boolean useSaved) {
-        Trace.beginSection("ImageFloatingTextView#makeSingleLayout");
+        if (TRACE_ONMEASURE) {
+            Trace.beginSection("ImageFloatingTextView#makeSingleLayout");
+            mStaticLayoutCreationCountInOnMeasure++;
+        }
         TransformationMethod transformationMethod = getTransformationMethod();
         CharSequence text = getText();
         if (transformationMethod != null) {
@@ -79,7 +88,7 @@
         }
         text = text == null ? "" : text;
         StaticLayout.Builder builder = StaticLayout.Builder.obtain(text, 0, text.length(),
-                getPaint(), wantWidth)
+                        getPaint(), wantWidth)
                 .setAlignment(alignment)
                 .setTextDirection(getTextDirectionHeuristic())
                 .setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
@@ -115,7 +124,10 @@
         }
 
         final StaticLayout result = builder.build();
-        Trace.endSection();
+        if (TRACE_ONMEASURE) {
+            trackMaxLines();
+            Trace.endSection();
+        }
         return result;
     }
 
@@ -141,7 +153,10 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        Trace.beginSection("ImageFloatingTextView#onMeasure");
+        if (TRACE_ONMEASURE) {
+            Trace.beginSection("ImageFloatingTextView#onMeasure");
+        }
+        mStaticLayoutCreationCountInOnMeasure = 0;
         int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mPaddingTop - mPaddingBottom;
         if (getLayout() != null && getLayout().getHeight() != availableHeight) {
             // We've been measured before and the new size is different than before, lets make sure
@@ -168,7 +183,12 @@
                 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
             }
         }
-        Trace.endSection();
+
+
+        if (TRACE_ONMEASURE) {
+            trackParameters();
+            Trace.endSection();
+        }
     }
 
     @Override
@@ -216,4 +236,37 @@
             requestLayout();
         }
     }
+
+    private void trackParameters() {
+        if (!TRACE_ONMEASURE) {
+            return;
+        }
+        Trace.setCounter("ImageFloatingView#staticLayoutCreationCount",
+                mStaticLayoutCreationCountInOnMeasure);
+        Trace.setCounter("ImageFloatingView#isPrecomputedText",
+                isTextAPrecomputedText());
+    }
+    /**
+     * @return 1 if {@link TextView#getText()} is PrecomputedText, else 0
+     */
+    private int isTextAPrecomputedText() {
+        final CharSequence text = getText();
+        if (text == null) {
+            return 0;
+        }
+
+        if (text instanceof PrecomputedText) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    private void trackMaxLines() {
+        if (!TRACE_ONMEASURE) {
+            return;
+        }
+
+        Trace.setCounter("ImageFloatingView#layoutMaxLines", mLayoutMaxLines);
+    }
 }
diff --git a/core/java/com/android/internal/widget/PeopleHelper.java b/core/java/com/android/internal/widget/PeopleHelper.java
index 85cedc3..3f5b4a0 100644
--- a/core/java/com/android/internal/widget/PeopleHelper.java
+++ b/core/java/com/android/internal/widget/PeopleHelper.java
@@ -22,6 +22,8 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.Person;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -222,6 +224,72 @@
     }
 
     /**
+     * A class that represents a map from unique sender names in the groups to the string 1- or
+     * 2-character prefix strings for the names. This class uses the String value of the
+     * CharSequence Names as the key.
+     */
+    public class NameToPrefixMap {
+        Map<String, String> mMap;
+        NameToPrefixMap(Map<String, String> map) {
+            this.mMap = map;
+        }
+
+        /**
+         * @param name the name
+         * @return the prefix of the given name
+         */
+        public String getPrefix(CharSequence name) {
+            return mMap.get(name.toString());
+        }
+    }
+
+    /**
+     * Same functionality as mapUniqueNamesToPrefix, but takes list-represented message groups as
+     * the input. This method is better when inflating MessagingGroup from the UI thread is not
+     * an option.
+     * @param groups message groups represented by lists. A message group is some consecutive
+     *               messages (>=3) from the same sender in a conversation.
+     */
+    public NameToPrefixMap mapUniqueNamesToPrefixWithGroupList(
+            List<List<Notification.MessagingStyle.Message>> groups) {
+        // Map of unique names to their prefix
+        ArrayMap<String, String> uniqueNames = new ArrayMap<>();
+        // Map of single-character string prefix to the only name which uses it, or null if multiple
+        ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>();
+        for (int i = 0; i < groups.size(); i++) {
+            List<Notification.MessagingStyle.Message> group = groups.get(i);
+            if (group.isEmpty()) continue;
+            Person sender = group.get(0).getSenderPerson();
+            if (sender == null) continue;
+            CharSequence senderName = sender.getName();
+            if (sender.getIcon() != null || TextUtils.isEmpty(senderName)) {
+                continue;
+            }
+            String senderNameString = senderName.toString();
+            if (!uniqueNames.containsKey(senderNameString)) {
+                String charPrefix = findNamePrefix(senderName, null);
+                if (charPrefix == null) {
+                    continue;
+                }
+                if (uniqueCharacters.containsKey(charPrefix)) {
+                    // this character was already used, lets make it more unique. We first need to
+                    // resolve the existing character if it exists
+                    CharSequence existingName = uniqueCharacters.get(charPrefix);
+                    if (existingName != null) {
+                        uniqueNames.put(existingName.toString(), findNameSplit(existingName));
+                        uniqueCharacters.put(charPrefix, null);
+                    }
+                    uniqueNames.put(senderNameString, findNameSplit(senderName));
+                } else {
+                    uniqueNames.put(senderNameString, charPrefix);
+                    uniqueCharacters.put(charPrefix, senderName);
+                }
+            }
+        }
+        return new NameToPrefixMap(uniqueNames);
+    }
+
+    /**
      * Update whether the groups can hide the sender if they are first
      * (happens only for 1:1 conversations where the given title matches the sender's name)
      */
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 6a640a5..d2e58bb 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -1165,12 +1165,11 @@
 
 static jlongArray android_os_Process_getRss(JNIEnv* env, jobject clazz, jint pid)
 {
-    // total, file, anon, swap
-    jlong rss[4] = {0, 0, 0, 0};
+    // total, file, anon, swap, shmem
+    jlong rss[5] = {0, 0, 0, 0, 0};
     std::string status_path =
             android::base::StringPrintf("/proc/%d/status", pid);
     UniqueFile file = MakeUniqueFile(status_path.c_str(), "re");
-
     char line[256];
     while (file != nullptr && fgets(line, sizeof(line), file.get())) {
         jlong v;
@@ -1182,17 +1181,18 @@
             rss[2] = v;
         } else if ( sscanf(line, "VmSwap: %" SCNd64 " kB", &v) == 1) {
             rss[3] = v;
+        } else if ( sscanf(line, "RssShmem: %" SCNd64 " kB", &v) == 1) {
+            rss[4] = v;
         }
     }
 
-    jlongArray rssArray = env->NewLongArray(4);
+    jlongArray rssArray = env->NewLongArray(5);
     if (rssArray == NULL) {
         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
         return NULL;
     }
 
-    env->SetLongArrayRegion(rssArray, 0, 4, rss);
-
+    env->SetLongArrayRegion(rssArray, 0, 5, rss);
     return rssArray;
 }
 
diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp
index 6e903b3..1031542 100644
--- a/core/jni/android_window_ScreenCapture.cpp
+++ b/core/jni/android_window_ScreenCapture.cpp
@@ -211,7 +211,7 @@
 }
 
 static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject,
-                                jlong screenCaptureListenerObject) {
+                                jlong screenCaptureListenerObject, jboolean sync) {
     LayerCaptureArgs captureArgs;
     getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
 
@@ -227,7 +227,7 @@
 
     sp<gui::IScreenCaptureListener> captureListener =
             reinterpret_cast<gui::IScreenCaptureListener*>(screenCaptureListenerObject);
-    return ScreenshotClient::captureLayers(captureArgs, captureListener);
+    return ScreenshotClient::captureLayers(captureArgs, captureListener, sync);
 }
 
 static jlong nativeCreateScreenCaptureListener(JNIEnv* env, jclass clazz, jobject consumerObj) {
@@ -281,7 +281,7 @@
         // clang-format off
     {"nativeCaptureDisplay", "(Landroid/window/ScreenCapture$DisplayCaptureArgs;J)I",
             (void*)nativeCaptureDisplay },
-    {"nativeCaptureLayers",  "(Landroid/window/ScreenCapture$LayerCaptureArgs;J)I",
+    {"nativeCaptureLayers",  "(Landroid/window/ScreenCapture$LayerCaptureArgs;JZ)I",
             (void*)nativeCaptureLayers },
     {"nativeCreateScreenCaptureListener", "(Ljava/util/function/ObjIntConsumer;)J",
             (void*)nativeCreateScreenCaptureListener },
diff --git a/core/proto/android/content/intent.proto b/core/proto/android/content/intent.proto
index 75e2908..1d1f88b 100644
--- a/core/proto/android/content/intent.proto
+++ b/core/proto/android/content/intent.proto
@@ -66,7 +66,7 @@
     optional string identifier = 13 [ (.android.privacy).dest = DEST_EXPLICIT ];
 }
 
-// Next Tag: 12
+// Next Tag: 14
 message IntentFilterProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -89,6 +89,7 @@
     optional bool get_auto_verify = 10;
     repeated string mime_groups = 11;
     optional android.os.PersistableBundleProto extras = 12;
+    repeated UriRelativeFilterGroupProto uri_relative_filter_groups = 13;
 }
 
 message AuthorityEntryProto {
@@ -98,3 +99,23 @@
     optional bool wild = 2;
     optional int32 port = 3;
 }
+
+message UriRelativeFilterGroupProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    enum Action {
+        ACTION_ALLOW = 0;
+        ACTION_BLOCK = 1;
+    }
+
+    optional Action action = 1;
+    repeated UriRelativeFilterProto uri_relative_filters = 2;
+}
+
+message UriRelativeFilterProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    required int32 uri_part = 1;
+    required int32 pattern_type = 2;
+    required string filter = 3;
+}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index b63021d..c92435f 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -464,6 +464,7 @@
     repeated .android.graphics.RectProto keep_clear_areas = 45;
     repeated .android.graphics.RectProto unrestricted_keep_clear_areas = 46;
     repeated .android.view.InsetsSourceProto mergedLocalInsetsSources = 47;
+    optional int32 requested_visible_types = 48;
 }
 
 message IdentifierProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 070e2cb..0171f58 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3751,6 +3751,13 @@
     <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS"
                 android:protectionLevel="internal|role" />
 
+    <!-- Allows an application to manage policy related to content protection.
+        <p>Protection level: internal|role
+        @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled")
+    -->
+    <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION"
+                android:protectionLevel="internal|role" />
+
     <!-- Allows an application to set device policies outside the current user
         that are critical for securing data within the current user.
         <p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
@@ -3828,6 +3835,18 @@
     <permission android:name="android.permission.ACTIVITY_EMBEDDING"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to embed any other apps in untrusted embedding mode without the need
+         for the embedded app to consent.
+         <p>For now, this permission is only granted to the Assistant application selected by
+         the user.
+         {@see https://developer.android.com/guide/topics/large-screens/activity-embedding#trust_model}
+         @SystemApi
+         @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission")
+         @hide
+        -->
+    <permission android:name="android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE"
+                android:protectionLevel="internal|role" />
+
     <!-- Allows an application to start any activity, regardless of permission
          protection or exported state.
          @hide -->
@@ -6654,7 +6673,14 @@
 
     <!-- Allows the system to control the BiometricDialog (SystemUI). Reserved for the system. @hide -->
     <permission android:name="android.permission.MANAGE_BIOMETRIC_DIALOG"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
+
+    <!-- Allows an application to set the BiometricDialog (SystemUI) logo .
+         <p>Not for use by third-party applications.
+         @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")
+    -->
+    <permission android:name="android.permission.SET_BIOMETRIC_DIALOG_LOGO"
+                android:protectionLevel="signature" />
 
     <!-- Allows an application to control keyguard.  Only allowed for system processes.
         @hide -->
@@ -7801,6 +7827,16 @@
     <permission android:name="android.permission.RUN_USER_INITIATED_JOBS"
                 android:protectionLevel="normal"/>
 
+    <!-- @FlaggedApi("android.app.job.backup_jobs_exemption")
+         Gives applications whose <b>primary use case</b> is to backup or sync content increased
+         job execution allowance in order to complete the related work. The jobs must have a valid
+         content URI trigger and network constraint set.
+         <p>This is a special access permission that can be revoked by the system or the user.
+         <p>Protection level: signature|privileged|appop
+     -->
+    <permission android:name="android.permission.RUN_BACKUP_JOBS"
+                android:protectionLevel="signature|privileged|appop"/>
+
     <!-- Allows an app access to the installer provided app metadata.
         @SystemApi
         @hide
@@ -7968,6 +8004,16 @@
     <permission android:name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER"
                 android:protectionLevel="signature|privileged"/>
 
+    <!-- @SystemApi
+        @FlaggedApi("android.content.pm.emergency_install_permission")
+        Allows each app store in the system image to designate another app in the system image to
+        update the app store
+        <p>Protection level: signature|privileged
+        @hide
+    -->
+    <permission android:name="android.permission.EMERGENCY_INSTALL_PACKAGES"
+                android:protectionLevel="signature|privileged"/>
+
     <!-- Attribution for Geofencing service. -->
     <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
     <!-- Attribution for Country Detector. -->
@@ -8374,6 +8420,16 @@
             </intent-filter>
         </receiver>
 
+        <!-- Broadcast Receiver listens to sufficient verifier broadcast from Package Manager
+            when installing new SDK. Verification of SDK code during installation time is run
+            to determine compatibility with privacy sandbox restrictions. -->
+        <receiver android:name="com.android.server.sdksandbox.SdkSandboxVerifierReceiver"
+                 android:exported="false">
+            <intent-filter>
+                <action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/>
+            </intent-filter>
+        </receiver>
+
         <service android:name="android.hardware.location.GeofenceHardwareService"
             android:permission="android.permission.LOCATION_HARDWARE"
             android:exported="false" />
@@ -8415,6 +8471,10 @@
                  android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
+        <service android:name="com.android.server.selinux.SelinuxAuditLogsService"
+                 android:permission="android.permission.BIND_JOB_SERVICE">
+        </service>
+
         <service android:name="com.android.server.compos.IsolatedCompilationJobService"
                  android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
diff --git a/core/res/res/color-night/notification_expand_button_state_tint.xml b/core/res/res/color-night/notification_expand_button_state_tint.xml
deleted file mode 100644
index a794d53..0000000
--- a/core/res/res/color-night/notification_expand_button_state_tint.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:color="@android:color/system_on_surface_dark" android:alpha="0.06"/>
-    <item android:state_hovered="true" android:color="@android:color/system_on_surface_dark" android:alpha="0.03"/>
-    <item android:color="@android:color/system_on_surface_dark" android:alpha="0.00"/>
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/notification_expand_button_state_tint.xml b/core/res/res/color/notification_expand_button_state_tint.xml
index 67b2c25..5a8594f 100644
--- a/core/res/res/color/notification_expand_button_state_tint.xml
+++ b/core/res/res/color/notification_expand_button_state_tint.xml
@@ -14,8 +14,11 @@
   ~ limitations under the License.
   -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:color="@android:color/system_on_surface_light" android:alpha="0.12"/>
-    <item android:state_hovered="true" android:color="@android:color/system_on_surface_light" android:alpha="0.08"/>
-    <item android:color="@android:color/system_on_surface_light" android:alpha="0.00"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <item android:state_pressed="true" android:color="?androidprv:attr/materialColorOnPrimaryFixed"
+          android:alpha="0.15"/>
+    <item android:state_hovered="true" android:color="?androidprv:attr/materialColorOnPrimaryFixed"
+          android:alpha="0.11"/>
+    <item android:color="@color/transparent" />
 </selector>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 38d2a25..e864872 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Laat die program toe om die seluitsendingmodule te bind om seluitsendingboodskappe aan te stuur wanneer hulle ontvang word. Seluitsendingwaarskuwings word in sommige liggings gelewer om jou oor noodsituasies te waarsku. Kwaadwillige programme kan met die werkverrigting of werking van jou toestel inmeng wanneer \'n noodseluitsending ontvang word."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Bestuur voortgaande oproepe"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Stel \'n program in staat om besonderhede oor voortgaande oproepe op jou toestel te sien, en hierdie oproepe te beheer."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lees seluitsending-boodskappe"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Laat die program toe om seluitsending-boodskappe te lees wat deur jou toestel ontvang word. Seluitsending-waarskuwings word in sommige plekke afgelewer om jou van noodsituasies te waarsku. Kwaadwillige programme mag inmeng met die prestasie of die werking van jou toestel wanneer \'n noodgeval se seluitsending ontvang word."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lees ingetekende nuus"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 47d2da0..e91fe9d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"የሕዋስ ስርጭት መልዕክቶች እንደመጡ ለማስተላለፍ መተግበሪያው ከሕዋስ ስርጭት ሞዱሉ ጋር እንዲተሳሰር ያስችለዋል። የሕዋስ ስርጭት ማንቂያዎች አስቸኳይ ሁኔታዎች ሲያጋጥሙ አንዳንድ አካባቢዎች ላይ የሚላኩ ናቸው። የሕዋስ ስርጭት ሲደርስ ተንኮል-አዘል መተግበሪያዎች በመሣሪያዎ አፈጻጸም ወይም አሰራር ላይ ጣልቃ ሊገቡ ይችላሉ።"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"በመካሄድ ላይ ያሉ ጥሪዎችን አስተዳድር"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"አንድ መተግበሪያ በመካሄድ ላይ ስላሉ ጥሪዎች ዝርዝሮችን እንዲመለከት ያስችለዋል።"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"የህዋስ ስርጭት መልዕክቶችን አንብብ"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"መሣሪያህ የህዋስ ስርጭት መልዕክቶች ሲቀበል መተግበሪያው እንዲያነበው ይፈቅድለታል። የህዋስ ስርጭት ማንቂያዎች አስቸኳይ ሁኔታዎች ሲያጋጥሙ አንዳንድ አካባቢዎች ላይ የሚላኩ ናቸው። የህዋስ ስርጭት ሲደርስ ተንኮል አዘል መተግበሪያዎች በመሣሪያህ አፈጻጸም ወይም አሰራር ላይ ጣልቃ ሊገቡ ይችላሉ።"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"የምዝገባ መግቦች አንበብ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4d6b92f..ae1f2aa 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -374,6 +374,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"يسمح للتطبيق بالارتباط بوحدة البث الخلوي لإعادة توجيه رسائل البث الخلوي بينما يتم استقبالها. ويتم تسليم تنبيهات البث الخلوي في بعض المواقع لتحذيرك في حالات الطوارئ. ويمكن أن تؤثر التطبيقات الضارة على أداء الجهاز أو تشغيله عندما يتم تلقي بث خلوي في حالات الطوارئ."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"إدارة المكالمات الجارية"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"يسمح هذا الإذن للتطبيق بمعرفة تفاصيل المكالمات الجارية على جهازك والتحكّم فيها."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"قراءة رسائل بث الخلية"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"السماح للتطبيق بقراءة رسائل بث الخلية التي يتلقاها هذا الجهاز. يتم تسليم اشعارات بث الخلية في بعض المواقع لتحذيرك من حالات طارئة. يمكن أن تتداخل التطبيقات الضارة مع أداء أو تشغيل الجهاز عندما يتم تلقي بث خلية طارئ."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"قراءة الخلاصات المشتركة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 94d355f..fd8082a 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"চেল সম্প্ৰচাৰ বাৰ্তাসমূহ লাভ কৰিলে সেইবোৰ ফৰৱাৰ্ড কৰিবলৈ এপ্‌টোক চেল সম্প্ৰচাৰ মডিউলটোৰ সৈতে সংযুক্ত হ\'বলৈ অনুমতি দিয়ে। আপোনাক জৰুৰীকালীন পৰিস্থিতিসমূহৰ বিষয়ে সতৰ্ক কৰিবলৈ কিছুমান অৱস্থানত চেল সম্প্ৰচাৰ সতৰ্কবাৰ্তাসমূহ ডেলিভাৰ কৰা হয়। কোনো জৰুৰীকালীন চেল সম্প্ৰচাৰ লাভ কৰিলে ক্ষতিকাৰক এপ্‌সমূহে আপোনাৰ ডিভাইচটোৰ কাৰ্যক্ষমতা অথবা কাৰ্যপ্ৰণালীত হস্তক্ষেপ কৰিব পাৰে।"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"চলি থকা কলসমূহ পৰিচালনা কৰক"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"এটা এপক আপোনাৰ ডিভাইচত চলি থকা কলৰ সবিশেষ চাবলৈ আৰু এই কলসমূহ নিয়ন্ত্ৰণ কৰিবলৈ অনুমতি দিয়ে।"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"চেল সম্প্ৰচাৰৰ বার্তাবোৰ পঢ়ক"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"আপোনাৰ ডিভাইচে লাভ কৰা চেল সম্প্ৰচাৰৰ বার্তাবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। আপোনাক জৰুৰীকালীন পৰিস্থিতিবোৰত সর্তক কৰিবলৈ চেল সম্প্ৰচাৰৰ বার্তাবোৰ প্ৰেৰণ কৰা হয়। জৰুৰীকালীন চেল সম্প্ৰচাৰ লাভ কৰাৰ সময়ত আপোনাৰ ডিভাইচৰ কাৰ্যদক্ষতা বা কাৰ্যপ্ৰণালীত ক্ষতিকাৰক এপবোৰে হস্তক্ষেপ কৰিব পাৰে।"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"আপুনি সদস্যভুক্ত হোৱা ফীডসমূহ পঢ়ক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 633f6de..a14725b 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tətbiqə şəbəkə yayım mesajlarını əldə edildiyi anda yönləndirmək üçün şəbəkə yayımı moduluna bağlanmaq icazəsi verir. Şəbəkə yayımı bəzi məkanlarda olan fövqəladə hadisələrlə bağlı Sizi xəbərdar etmək üçün qəbul edilir. Zərərli tətbiqlər fövqəladə şəbəkə yayımı əldə edildiyi zaman cihazın performansına və əməliyyatına müdaxilə edə bilər."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Davam edən zəngləri idarə edin"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Tətbiqə cihazınızda davam edən zənglər haqqında məlumatları görmək və bu zəngləri idarə etmək imkanı verir."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"mobil yayım mesajlarını oxuyur"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Tətbiqə telefonunuz tərəfindən alınmış yayım mesajlarını oxuma icazəsi verir. Telefon yayımı bəzi məkanlarda olan fövqəladə hadisələrlə bağlı sizi xəbərdar etmək üçün qəbul edilir. Zərərli tətbiqlər təcili mobil yayım qəbul edildiyi zaman telefonunun performansına və əməliyyatına müdaxilə edə bilər."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"abunə olunmuş xəbərləri oxuyur"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 8387984..91b5b045 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Dozvoljava aplikaciji da se vezuje za modul poruka za mobilne uređaje na lokalitetu da bi prosleđivala poruke za mobilne uređaje na lokalitetu onako kako su primljene. Obaveštenja poruka za mobilne uređaje na lokalitetu se na nekim lokacijama primaju kao upozorenja na hitne slučajeve. Zlonamerne aplikacije mogu da utiču na performanse ili ometaju rad uređaja kada se primi poruka o hitnom slučaju za mobilne uređaje na lokalitetu."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Upravljanje odlaznim pozivima"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Omogućava aplikaciji da vidi detalje o odlaznim pozivima na uređaju i da kontroliše te pozive."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čitanje poruka info servisa"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Omogućava aplikaciji da čita poruke info servisa koje uređaj prima. Upozorenja info servisa se na nekim lokacijama primaju kao upozorenja na hitne slučajeve. Zlonamerne aplikacije mogu da utiču na performanse ili ometaju funkcionisanje uređaja kada se primi poruka info servisa o hitnom slučaju."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čitanje prijavljenih fidova"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 42c5010..68b89f0 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -372,6 +372,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Дазваляе праграме звязвацца з модулем сотавай трансляцыі, каб пераадрасоўваць атрыманыя там паведамленні. Абвесткі сотавай трансляцыі дасылаюцца ў некаторыя месцы, каб папярэджваць вас пра надзвычайныя сітуацыі. Шкодныя праграмы могуць негатыўна ўплываць на прадукцыйнасць або працу прылады падчас атрымання паведамленняў сотавай трансляцыі пра надзвычайныя сітуацыі."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Кіраваць уваходнымі выклікамі"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Дазваляе праграме праглядаць на прыладзе падрабязныя звесткі пра ўваходныя выклікі і кіраваць імі."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"чытаць паведамленні базавай станцыі"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Дазваляе прыкладанню чытаць паведамленні базавай станцыі, атрыманыя прыладай. Папярэджанні базавай станцыі дасылаюцца ў некаторыя месцы, каб папярэдзіць вас аб надзвычайных сітуацыях. Шкоднасныя прыкладанні могуць уплываць на прадукцыйнасць ці працу прылады пры атрыманні паведамлення базавай станцыі аб надзвычайнай сітуацыі."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"чытаць падпісаныя каналы"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 181746e..e369102 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Разрешава на приложението да се обвърже с модула за клетъчно излъчване, за да препраща получените съобщения с клетъчно излъчване. Сигналите с клетъчно излъчване се получават на някои местоположения, за да ви предупредят за спешни случаи. Злонамерените приложения могат да възпрепятстват изпълнението или работата на устройството ви при получаване на такова спешно излъчване."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Управление на текущите обаждания"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Разрешава на приложението да вижда подробности за текущите обаждания на устройството ви и да ги управлява."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"четене на съобщения с клетъчно излъчване"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Разрешава на приложението да чете съобщения с клетъчно излъчване, получени от устройството ви. Сигналите с клетъчно излъчване се получават на някои местоположения, за да ви предупредят за спешни ситуации. Злонамерените приложения могат да възпрепятстват изпълнението или работата на устройството ви при получаване на такова спешно излъчване."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"четене на емисиите с абонамент"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 236fff5..ecbc6d5 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"সেল ব্রডকাস্ট মেসেজ পেলে এটি সেল ব্রডকাস্ট মডিউলের সাথে তা যুক্ত করে যাতে সেই মেসেজ ফরওয়ার্ড করা যায়। আপনাকে জরুরি অবস্থা সম্পর্কে সাবধান করতে কিছু লোকেশনে সেল ব্রডকাস্ট অ্যালার্ট মেসেজ ডেলিভার করা হয়। জরুরি সেল ব্রডকাস্ট পাওয়া গেলে ক্ষতিকারক অ্যাপ আপনার ডিভাইসের পারফর্ম্যান্স ও অপারেশনে বাধা সৃষ্টি করতে পারে।"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"অনগোয়িং কল ম্যানেজ করুন"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"আপনার ডিভাইসে অনগোয়িং কলের বিষয়ে বিবরণ দেখতে এবং এই কলগুলি কন্ট্রোল করার জন্য অ্যাপকে অনুমতি দেয়।"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"সেল সম্প্রচার মেসেজ পড়ুন"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"আপনার ডিভাইস দ্বারা প্রাপ্ত সেল সম্প্রচার পড়তে অ্যাপ্লিকেশানটিকে অনুমতি দেয়৷ কয়েকটি স্থানে আপনাকে জরুরি অবস্থার জন্য সতর্ক করতে জরুরি সতর্কতাগুলি বিতরণ করা হয়৷ যখন একটি জরুরি সেল সম্প্রচার প্রাপ্ত হয় তখন ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার ডিভাইসের কার্য সম্পাদনা বা কার্যকলাপে প্রতিবন্ধকতার সৃষ্টি করতে পারে৷"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"গ্রাহক হিসেবে নেওয়া ফিডগুলি পড়ে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 1da2604..5088911 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Dopušta aplikaciji da se veže za modul info servisa kako bi prosljeđivala poruke info servisa. Upozorenja koja emitira info servis se isporučuju na nekim lokacijama kako bi vas upozorila na vanredne situacije. Zlonamjerne aplikacije mogu ometati performanse ili rad vašeg uređaja kada primite informacije o vanrednoj situaciji od info servisa."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Upravljanje pozivima u toku"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Omogućava aplikaciji da vidi detalje o pozivima u toku na vašem uređaju i da ih kontrolira."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čitanje poruka info servisa"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Omogućava aplikaciji čitanje poruka info servisa koje je primio vaš uređaj. Upozorenja koja emitira info servis se isporučuju na nekim lokacijama kako bi vas upozorila na vanredne situacije. Zlonamjerne aplikacije mogu ometati performanse ili rad vašeg uređaja kada primite informaciju o vanrednoj situaciji od info servisa."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čitanje sadržaja na koje ste pretplaćeni"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 867a34d..1719d53 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permet que l\'aplicació es vinculi al mòdul de difusió mòbil per poder reenviar els missatges de difusió mòbil a mesura que es reben. Les alertes de difusió mòbil s\'entreguen en algunes ubicacions per alertar de situacions d\'emergència. És possible que les aplicacions malicioses interfereixin en el rendiment o en el funcionament del dispositiu quan es rebi una difusió mòbil d\'emergència."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gestiona les trucades en curs"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permet que una aplicació vegi els detalls sobre les trucades en curs al dispositiu i que controli aquestes trucades."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"llegir missatges de difusió mòbil"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permet que l\'aplicació llegeixi missatges de difusió mòbil rebuts pel dispositiu. Les alertes de difusió mòbil s\'entreguen en algunes ubicacions per alertar de situacions d\'emergència. És possible que les aplicacions malicioses interfereixin en el rendiment o en el funcionament del dispositiu quan es rep una difusió mòbil d\'emergència."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"llegir els feeds als quals esteu subscrit"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2c17373..d50f4f8 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -372,6 +372,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Umožňuje aplikaci vytvořit vazbu s modulem informačních služeb za účelem přesměrovávání přijatých zpráv informačních služeb. Výstražná upozornění informačních služeb jsou v některých oblastech odesílána za účelem varování před výjimečnými událostmi. Škodlivé aplikace mohou narušit výkon či provoz vašeho zařízení během přijímání zpráv informačních služeb."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Správa probíhajících hovorů"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Umožňuje aplikaci zobrazit podrobnosti o probíhajících hovorech v zařízení a tyto hovory ovládat."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čtení zpráv informačních služeb"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Umožňuje aplikaci číst zprávy informačních služeb přijaté ve vašem zařízení. Výstražná upozornění informačních služeb jsou v některých oblastech odesílána za účelem varování před výjimečnými událostmi. Škodlivé aplikace mohou narušit výkon či provoz vašeho zařízení během přijímání zpráv informačních služeb."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čtení zdrojů přihlášených k odběru"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index f04fd75..e0fc3ca 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tillader, at appen bindes til Cell Broadcast-modulet, så Cell Broadcast-meddelelser kan videresendes, når de modtages. I regioner sendes der Cell Broadcast-underretninger for at advare dig om nødsituationer. Ondsindede apps kan forstyrre effektiviteten eller driften af din enhed, når den modtager en Cell Broadcast-meddelelse om en nødsituation."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Administrere igangværende opkald"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Giver appen tilladelse til at se oplysninger om igangværende opkald på din enhed og styre disse opkald."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"læse Cell Broadcast-meddelelser"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Tillader, at appen læser Cell Broadcast-underretninger, der modtages af din enhed. I regioner sendes der Cell Broadcast-underretninger for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af ​din ​enhed, når der modtages en Cell Broadcast-meddelelse om en nødsituation."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"læse feeds, jeg abonnerer på"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d55ba9f..7f0dd1e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Ermöglicht der App, sich mit dem Cell-Broadcast-Modul zu verbinden, um empfangene Cell-Broadcast-Nachrichten weiterzuleiten. Cell-Broadcast-Benachrichtigungen können in einigen Ländern oder Regionen gesendet werden, um dich bei Notfallsituationen zu warnen. Schädliche Apps können die Leistung oder den Betrieb deines Geräts beeinträchtigen, wenn eine Cell-Broadcast-Notfallbenachrichtigung eingeht."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Aktuelle Anrufe verwalten"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Ermöglicht einer App, Details zu aktuellen Anrufen auf deinem Gerät zu sehen und diese Anrufe zu verwalten."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"Cell Broadcast-Nachrichten lesen"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Ermöglicht der App, von deinem Gerät empfangene Cell Broadcast-Nachrichten zu lesen. Cell Broadcast-Benachrichtigungen werden an einigen Standorten gesendet, um dich über Notfallsituationen zu informieren. Schädliche Apps können die Leistung oder den Betrieb deines Geräts beeinträchtigen, wenn eine Cell Broadcast-Notfallbenachrichtigung eingeht."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"Abonnierte Feeds lesen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 1346faf..366533c 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Επιτρέπει στην εφαρμογή να συνδέεται στη λειτουργική μονάδα εκπομπής κινητής τηλεφωνίας, προκειμένου να προωθεί τα μηνύματα εκπομπής κινητής τηλεφωνίας κατά τη λήψη τους. Οι ειδοποιήσεις εκπομπής κινητής τηλεφωνίας προβάλλονται σε ορισμένες τοποθεσίες, για να σας προειδοποιήσουν σχετικά με καταστάσεις έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές μπορεί να επηρεάσουν την απόδοση ή τη λειτουργία της συσκευής σας κατά τη λήψη μιας εκπομπής κινητής τηλεφωνίας έκτακτης ανάγκης."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Διαχείριση κλήσεων σε εξέλιξη"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Επιτρέπει σε μια εφαρμογή να βλέπει λεπτομέρειες σχετικά με τις κλήσεις σε εξέλιξη στη συσκευή σας και να τις ελέγχει."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"διαβάζει μηνύματα που έχουν μεταδοθεί μέσω κινητού τηλεφώνου"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Επιτρέπει στην εφαρμογή την ανάγνωση μηνυμάτων που έχουν μεταδοθεί μέσω κινητού τηλεφώνου και έχουν ληφθεί από τη συσκευή σας. Ειδοποιήσεις που μεταδίδονται μέσω κινητού παραδίδονται σε ορισμένες τοποθεσίες για να σας προειδοποιήσουν για καταστάσεις έκτακτης ανάγκης. Κακόβουλες εφαρμογές ενδέχεται να παρεμποδίσουν την απόδοση ή τη λειτουργία της συσκευής σας κατά τη λήψη μετάδοσης μέσω κινητού σχετικά με μια επείγουσα κατάσταση."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"διαβάζει ροές δεδομένων στις οποίες έχετε εγγραφεί"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 8f6bb19..4e54710 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read mobile broadcast messages"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read mobile broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency mobile broadcast is received."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9129b82..4f3b52a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -370,6 +370,8 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+    <string name="permlab_accessLastKnownCellId" msgid="7638226620825665130">"Access last known cell identity."</string>
+    <string name="permdesc_accessLastKnownCellId" msgid="6664621339249308857">"Allows an app to access to the last known cell identity provided by telephony."</string>
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read cell broadcast messages"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read cell broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index dd7f4a7..240421b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read mobile broadcast messages"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read mobile broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency mobile broadcast is received."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index b652512..4b427bc 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read mobile broadcast messages"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read mobile broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency mobile broadcast is received."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 5ed9d11..66c24b4 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -370,6 +370,8 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received.‎‏‎‎‏‎"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‎‎Manage ongoing calls‎‏‎‎‏‎"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‎‏‎Allows an app to see details about ongoing calls on your device and to control these calls.‎‏‎‎‏‎"</string>
+    <string name="permlab_accessLastKnownCellId" msgid="7638226620825665130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎Access last known cell identity.‎‏‎‎‏‎"</string>
+    <string name="permdesc_accessLastKnownCellId" msgid="6664621339249308857">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎Allows an app to access to the last known cell identity provided by telephony.‎‏‎‎‏‎"</string>
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‎read cell broadcast messages‎‏‎‎‏‎"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎Allows the app to read cell broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received.‎‏‎‎‏‎"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎read subscribed feeds‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index bc94eed..0d57e4b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que la app se vincule al módulo de emisión móvil para reenviar los mensajes de este tipo a medida que se reciben. En algunas ubicaciones, se envían alertas de emisión móvil para advertirte en situaciones de emergencia. Es posible que las apps maliciosas interfieran con el rendimiento o el funcionamiento de tu dispositivo cuando recibes una emisión móvil de emergencia."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Administrar llamadas en curso"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que una app vea detalles sobre las llamadas en curso del dispositivo y las controle."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"Leer mensajes de difusión móvil"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite a la aplicación leer los mensajes de difusión móvil que recibe tu dispositivo. En algunas ubicaciones, las alertas de difusión móvil se envían para informar situaciones de emergencia. Las aplicaciones maliciosas pueden afectar el rendimiento o funcionamiento de tu dispositivo cuando se recibe un un mensaje de difusión móvil de emergencia."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"leer canales suscritos"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c65e670..79be741 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que la aplicación se vincule con el módulo de difusión móvil para reenviar los mensajes de ese tipo en cuanto se reciben. En ciertas ubicaciones se envían alertas de difusión móvil para avisar de situaciones de emergencia. Cuando se recibe una alerta de difusión móvil de emergencia, ciertas aplicaciones malintencionadas podrían interferir en el rendimiento o en el funcionamiento del dispositivo."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gestionar llamadas en curso"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que una aplicación consulte datos de llamadas que estén en curso en tu dispositivo y controle esas llamadas."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"leer mensajes de difusión móvil"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que la aplicación lea mensajes de difusión móvil que haya recibido el dispositivo. Las alertas de difusión móvil se envían en algunas ubicaciones para avisar de situaciones de emergencia. Es posible que las aplicaciones malintencionadas interfieran en el rendimiento o en el funcionamiento del dispositivo si se recibe una alerta de difusión móvil de emergencia."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"leer feeds a los que está suscrito el usuario"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 9c7cc1b..a07c4cd 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Võimaldab rakendusel luua ühenduse kärjeteadete mooduliga, et saabunud kärjeteateid edasi saata. Kärjeteateid edastatakse mõnes asukohas eriolukorrast teavitamiseks. Pahatahtlikud rakendused võivad seadme toimivust või tööd eriolukorra kärjeteate vastuvõtmisel segada."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Käimasolevate kõnede haldamine"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Võimaldab rakendusel näha teie seadmes käimasolevate kõnede üksikasju ja neid kõnesid hallata."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"mobiilsidesõnumite lugemine"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Võimaldab rakendusel lugeda seadme vastu võetud mobiilsidesõnumeid. Mobiilsidemärguandeid edastatakse mõnes asukohas eriolukorrast teavitamiseks. Pahatahtlikud rakendused võivad segada seadme toimivust või tööd eriolukorra sõnumi vastuvõtmisel."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"loe tellitud kanaleid"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 847fe56..b3f2ce2 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Sare mugikor bidezko iragarpen-modulura lotzeko baimena ematen dio aplikazioari, sare mugikor bidezko iragarpen-mezuak jaso ahala desbideratu ahal izateko. Sare mugikor bidezko iragarpen-alertak kokapen batzuetan entregatzen dira larrialdi-egoeren berri emateko. Sare mugikor bidezko larrialdi-iragarpenak jasotzean, asmo txarreko aplikazioek gailuaren errendimenduari edota funtzionamenduari eragin diezaiokete."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Kudeatu abian dauden deiak"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Gailuak jasotzen dituen deiei buruzko xehetasunak ikusteko eta dei horiek kontrolatzeko baimena ematen die aplikazioei."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"irakurri sare mugikor bidezko igorpen-mezuak"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Gailuak jasotako sare mugikor bidezko igorpen-mezuak irakurtzeko baimena ematen dio aplikazioari. Sare mugikor bidezko igorpen-alertak kokapen batzuetan ematen dira larrialdi-egoeren berri emateko. Asmo txarreko aplikazioek gailuaren errendimendua edo funtzionamendua oztopa dezakete larrialdi-igorpen horietako bat jasotzen denean."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"irakurri harpidetutako jarioak"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6cdaf78a..7738e1c 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"به برنامه امکان می‌دهد به مدول پخش سلولی متصل شود تا پیام‌های پخش سلولی را به محض دریافت بازارسال کند. هشدارهای پخش سلولی در برخی از موقعیت‌های مکانی ارسال می‌شوند تا موقعیت‌های اضطراری را به شما اعلام کنند. وقتی پخش سلولی دریافت می‌شود، ممکن است برنامه‌های مخرب در عملکرد یا کارکرد دستگاه شما اختلال ایجاد کنند."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"مدیریت تماس‌های درحال انجام"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"به برنامه اجازه می‌دهد جزئیات تماس‌های درحال انجام در دستگاه را ببیند و این تماس‌ها را کنترل کند."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"خواندن پیام‌های پخش سلولی"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"‏به برنامه اجازه می‎دهد پیام‌های پخش سلولی دستگاه شما را بخواند. هشدارهای پخش سلولی در برخی از موقعیت‌های مکانی تحویل داده می‎شوند تا موقعیت‌های اضطراری را به شما اعلام کنند. وقتی پخش سلولی دریافت می‎شود، ممکن است برنامه‌های مخرب در عملکرد یا کارکرد دستگاه شما اختلال ایجاد کنند."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"خواندن فیدهای مشترک"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e0dd50d..96e0ad4 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Sallii sovelluksen sitoutua solulähetysmoduuliin lähettääkseen solulähetysviestejä edelleen sitä mukaa kun ne saapuvat. Solulähetysilmoitusten avulla ilmoitetaan hätätilanteista joissakin paikoissa. Haitalliset sovellukset voivat häiritä laitteen toimintaa laitteen vastaanottaessa hätätilanteeseen liittyvän solulähetysviestin."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Ylläpidä käynnissä olevia puheluita"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Sovellus voi nähdä tietoja laitteella käynnissä olevista puheluista ja ohjata näitä puheluita."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lue tiedotteita"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Antaa sovelluksen lukea laitteesi vastaanottamia tiedotteita. Tiedotteiden avulla ilmoitetaan hätätilanteista joissakin paikoissa. Haitalliset sovellukset voivat häiritä laitteen toimintaa laitteen vastaanottaessa hätätiedotteen."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lukea tilattuja syötteitä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 0bb9ee5..379dce09 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permet à l\'application d\'établir un lien avec le module de diffusion cellulaire afin de transférer les messages de diffusion cellulaire à mesure de leur réception. Dans certaines régions, des alertes de diffusion cellulaire sont envoyées afin de vous avertir de situations d\'urgence. Des applications malveillantes peuvent interférer avec les performances ou le fonctionnement de votre appareil lors de la réception d\'une alerte d\'urgence par diffusion cellulaire."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gérer les appels en cours"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Autorise une application à afficher les renseignements concernant les appels en cours sur votre appareil et à les gérer."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lire les messages de diffusion cellulaire"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permet à l\'application de lire les messages de diffusion cellulaire que votre appareil reçoit. Dans certaines zones géographiques, des alertes vous sont envoyées afin de vous prévenir en cas de situation d\'urgence. Des applications malveillantes peuvent venir perturber les performances ou le fonctionnement de votre appareil lors de la réception d\'un message de diffusion cellulaire."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lire les flux auxquels vous êtes abonné"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 8956904..455b2da 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Autorise l\'application à établir une connexion avec le module de diffusion cellulaire afin de transférer les messages reçus via un canal de diffusion cellulaire. Des alertes de diffusion cellulaire sont générées dans certaines régions afin de vous avertir de situations d\'urgence. Des applications malveillantes peuvent interférer avec les performances ou le fonctionnement de votre appareil lors de la réception d\'une alerte d\'urgence par diffusion cellulaire."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gérer les appels en cours"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Autorise une application à afficher les détails concernant les appels en cours sur votre appareil et à contrôler ces appels."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lire les messages reçus via un canal de diffusion cellulaire"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permet à l\'application de lire les messages que votre appareil reçoit via un canal de diffusion cellulaire. Dans certaines zones géographiques, des alertes vous sont envoyées afin de vous prévenir en cas de situation d\'urgence. Les applications malveillantes peuvent venir perturber les performances ou le fonctionnement de votre appareil lorsqu\'un message est reçu via un canal de diffusion cellulaire."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lire les flux auxquels vous êtes abonné"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index b1598b3..df08dd3 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que a aplicación se vincule ao módulo de difusión móbil para reenviar as mensaxes deste tipo segundo se reciban. As alertas de difusión móbil envíanse nalgunhas localizacións para avisar de situacións de emerxencia. As aplicacións maliciosas poden interferir no rendemento ou funcionamento do teu dispositivo cando se reciba unha difusión móbil de emerxencia."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Xestionar as chamadas saíntes"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que unha aplicación controle as chamadas saíntes do teu dispositivo e consulte os detalles sobre elas."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensaxes de difusión móbil"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite á aplicación ler mensaxes de difusión móbil recibidas polo teu dispositivo. As alertas de difusión móbil envíanse nalgunhas localizacións para avisar de situacións de emerxencia. É posible que aplicacións maliciosas afecten ao rendemento ou funcionamento do teu dispositivo cando se recibe unha difusión móbil de emerxencia."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds subscritos"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 023269f..574c510 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"સેલ બ્રોડકાસ્ટ સંદેશા પ્રાપ્ત થાય કે તરત ફૉરવર્ડ કરવા માટે સેલ બ્રોડકાસ્ટ મૉડ્યૂલ સાથે પ્રતિબદ્ધ થવા બાબતે ઍપને મંજૂરી આપે છે. તમને કટોકટીની પરિસ્થિતિની ચેતવણી આપવા માટે સેલ બ્રોડકાસ્ટ અલર્ટ અમુક સ્થાનોમાં ડિલિવર કરવામાં આવે છે. કટોકટી અંગેનો સેલ બ્રોડકાસ્ટ પ્રાપ્ત થાય, ત્યારે દુર્ભાવનાપૂર્ણ ઍપ તમારા ડિવાઇસના કાર્યપ્રદર્શન અથવા ઑપરેશનમાં વિક્ષેપ પાડે તેમ બની શકે છે."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ચાલી રહેલા કૉલ મેનેજ કરો"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ઍપને તમારા ડિવાઇસ પર ચાલુ કૉલ વિશેની વિગતો જોવાની અને આ કૉલને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"સેલ બ્રોડકાસ્ટ સંદેશા વાંચો"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ઍપ તમારા ડિવાઇસ દ્વારા પ્રાપ્ત થયેલ સેલ બ્રોડકાસ્ટ સંદેશાને વાંચવાની મંજૂરી આપે છે. સેલ બ્રોડકાસ્ટ ચેતવણીઓ તમને ઇમર્જન્સીની સ્થિતિઓ અંગે ચેતવવા માટે કેટલાક સ્થાનોમાં વિતરિત થાય છે. જ્યારે ઇમર્જન્સીનો સેલ બ્રોડકાસ્ટ પ્રાપ્ત થાય ત્યારે દુર્ભાવનાપૂર્ણ ઍપ તમારા ડિવાઇસના કાર્યપ્રદર્શન અથવા ઓપરેશનમાં હસ્તક્ષેપ કરી શકે છે."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"સબ્સ્ક્રાઇબ કરેલ ફીડ્સ વાંચો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a9221d8..2f08e2a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"सेल ब्रॉडकास्ट (CBC) मैसेज आते ही उसे दूसरे नंबर पर भेजने के लिए, ऐप्लिकेशन को सेल ब्रॉडकास्ट (CBC) मॉड्यूल पर बाइंड करने की अनुमति देता है. कुछ जगहों में सेल ब्रॉडकास्ट (CBC) अलर्ट आपातकालीन स्थितियों के बारे में चेतावनी देने के लिए भेजा जाता है. नुकसान पहुंचाने वाले ऐप्लिकेशन, आपातकाल में सेल ब्रॉडकास्ट (CBC) मैसेज मिलने पर आपके डिवाइस के काम करते समय या इसके परफ़ॉर्मेंस में रुकावट पैदा कर सकते हैं."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"चल रहे कॉल प्रबंधित करें"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"इससे, ऐप्लिकेशन को आपके डिवाइस पर चल रहे कॉल की जानकारी देखने और उन्हें कंट्रोल करने की अनुमति मिलती है."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल ब्रॉडकास्ट (CBC) मैसेज पढ़ें"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ऐप को, वो सेल ब्रॉडकास्ट (CBC) मैसेज पढ़ने देता है जो आपके डिवाइस को मिले हैं. सेल ब्रॉडकास्ट (CBC) अलर्ट कुछ स्थानों (लोकेशन) पर आपको आपातकालीन स्‍थितियों की चेतावनी देने के लिए दिए जाते हैं. आपातकालीन सेल ब्रॉडकास्ट (CBC) मिलने पर, धोखा देने वाले ऐप आपके डिवाइस के परफ़ॉर्मेंस या कार्यवाही में दखल दे सकते हैं."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"सदस्यता वाली फ़ीड पढ़ें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 43433a3..af3bd29 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Omogućuje aplikaciji da se poveže s modulom za emitiranje na mobitele kako bi prosljeđivala poruke koje se emitiraju na mobitele po njihovom primitku. Upozorenja značajke emitiranja na mobitele dostavljaju se na nekim lokacijama kako bi upozorila korisnike na hitne situacije. Zlonamjerne aplikacije mogu ometati izvršavanje ili rad vašeg uređaja kada stigne hitno emitiranje na mobitele."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Upravljanje tekućim pozivima"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Omogućuje aplikaciji pregled pojedinosti o tekućim pozivima na uređaju i upravljanje tim pozivima."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čitaj poruke koje se emitiraju unutar mobilne mreže"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Omogućuje aplikaciji čitanje poruka emitiranih unutar mobilne mreže koje prima vaš uređaj. Upozorenja koja se emitiraju na području mobilne mreže dostavljaju se na nekim lokacijama kako bi upozorila korisnike na hitne situacije. Zlonamjerne aplikacije mogu ometati izvršavanje ili rad vašeg uređaja kada stigne hitno upozorenje koje se emitira unutar mobilne mreže."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čitanje pretplaćenih feedova"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 64dee26..882156c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Az alkalmazás összekapcsolódhat a cellán belüli üzenetszórás moduljával, hogy az érkezésükkor továbbítani tudja a cellán belüli üzeneteket. Bizonyos helyeken figyelmeztető üzeneteket kaphat a cellán belül a vészhelyzetekről. A rosszindulatú alkalmazások vészhelyzeti cellaüzenet érkezésekor befolyásolhatják az eszköz teljesítményét és működését."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Folyamatban lévő hívások kezelése"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Engedélyezi az alkalmazásnak, hogy az eszközén folyamatban lévő hívások részleteihez hozzáférjen, és vezérelje ezeket a hívásokat."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"cellán belüli üzenetek olvasása"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Lehetővé teszi az alkalmazás számára az eszközre érkező cellán belüli üzenetek olvasását. Bizonyos helyeken figyelmeztető üzeneteket kaphat a cellán belül a vészhelyzetekről. A rosszindulatú alkalmazások befolyásolhatják az eszköz  teljesítményét vagy működését vészhelyzeti cellaüzenet érkezésekor."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"feliratkozott hírcsatornák olvasása"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 8a6d802..c85aeb8 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Թույլ է տալիս հավելվածին կապ հաստատել բջջային հեռարձակման մոդուլի հետ՝ բնակչությանը ծանուցող հաղորդագրությունները վերահասցեավորելու համար։ Որոշ երկրներում այս հաղորդագրություններն օգտագործվում են բնակչությանը արտակարգ իրավիճակների մասին զգուշացնելու համար: Վնասարար հավելվածները կարող են խանգարել ձեր սարքի աշխատանքին, որին ուղարկվում են այս հաղորդագրությունները:"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Ընթացիկ զանգերի կառավարում"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Թույլ է տալիս հավելվածին ձեր սարքում տեսնել ընթացիկ զանգերի մասին տեղեկությունները և կառավարել այդ զանգերը։"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"կարդալ բջջային զեկուցվող հաղորդագրությունները"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Թույլ է տալիս հավելվածին կարդալ ձեր սարքի կողմից ստացված բջջային հեռարձակվող հաղորդագրությունները: Բջջային հեռարձակվող զգուշացումները ուղարկվում են որոշ վայրերում` արտակարգ իրավիճակների մասին ձեզ զգուշացնելու համար: Վնասարար հավելվածները կարող են խանգարել ձեր սարքի արդյունավետությանը կամ շահագործմանը, երբ ստացվում է արտակարգ իրավիճակի մասին բջջային հաղորդում:"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"կարդալ բաժանորդագրված հոսքերը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 991d69f..2b76815 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Mengizinkan aplikasi mem-binding ke modul cell broadcast untuk meneruskan pesan cell broadcast saat pesan tersebut diterima. Notifikasi cell broadcast dikirim di beberapa lokasi untuk memperingatkan Anda tentang situasi darurat. Aplikasi berbahaya dapat mengganggu performa atau operasi perangkat saat cell broadcast darurat diterima."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Mengelola panggilan yang sedang berlangsung"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Mengizinkan aplikasi untuk melihat detail panggilan yang sedang berlangsung di perangkat dan mengontrolnya."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"membaca pesan siaran seluler"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Mengizinkan aplikasi membaca pesan siaran seluler yang diterima perangkat Anda. Notifikasi siaran seluler dikirimkan di beberapa lokasi untuk memperingatkan Anda tentang situasi darurat. Aplikasi berbahaya dapat mengganggu kinerja atau operasi perangkat Anda saat siaran seluler darurat diterima."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"baca feed langganan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 8bab2d7..f8b4197 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Heimilar forritinu að bindast endurvarpseiningunni til að framsenda skilaboð frá endurvarpa þegar þau berast. Viðvaranir frá endurvarpa berast á tilteknum stöðum til að vara þig við neyðarástandi. Spilliforrit geta truflað afköst eða virkni tækisins þegar neyðarboð berast frá endurvarpa."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Stjórna símtölum sem eru í gangi"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Leyfir forriti að sjá upplýsingar um og stjórna símtölum sem eru í gangi í tækinu þínu."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lesa skilaboð frá endurvarpa"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Leyfir forriti að lesa skilaboð frá endurvarpa sem tækið móttekur. Viðvaranir frá endurvarpa berast á tilteknum stöðum til að vara þig við neyðarástandi. Spilliforrit geta truflað afköst eða virkni tækisins þegar neyðarboð berast frá endurvarpa."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lesa strauma í áskrift"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b2180ab..5a67476 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Consente all\'app di essere associata al modulo di cell broadcast al fine di inoltrare i messaggi di cell broadcast man mano che arrivano. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di situazioni di emergenza. Le app dannose potrebbero interferire con le prestazioni o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gestione delle chiamate in corso"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Consente a un\'app di accedere a dettagli relativi alle chiamate in corso sul tuo dispositivo e di controllare tali chiamate."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lettura di messaggi cell broadcast"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Consente all\'applicazione di leggere i messaggi cell broadcast ricevuti dal dispositivo. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di eventuali situazioni di emergenza. Le app dannose potrebbero interferire con le prestazioni o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lettura feed sottoscritti"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 593668a..270568d 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"מאפשרת לאפליקציה להתחייב למודול של השידור הסלולרי כדי להעביר הודעות של שידור סלולרי כשהן מתקבלות. התראות שידור סלולרי נשלחות במקומות מסוימים כדי להזהיר אותך מפני מצבי חירום. אפליקציות זדוניות עשויות להפריע לביצועים או לפעולה של המכשיר כאשר מתקבל שידור חירום סלולרי."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ניהול שיחות שנערכות"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"לאפליקציה תהיה אפשרות לראות פרטים על שיחות שנערכות במכשיר ולשלוט בשיחות האלה."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"קריאת הודעות שידור סלולרי"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"מאפשרת לאפליקציה לקרוא הודעות שידור סלולרי שהתקבלו במכשיר שלך. התראות שידור סלולרי נשלחות במקומות מסוימים כדי להזהיר אותך מפני מצבי חירום. אפליקציות זדוניות עשויות להפריע לביצועים או לפעולה של המכשיר שלך כאשר מתקבל שידור חירום סלולרי."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"קריאת עדכוני מינויים"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 3a904b6..98e2324 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"受信した緊急速報メールを転送するために、緊急速報メール モジュールにバインドすることをこのアプリに許可します。緊急速報メールは、緊急事態を警告する目的で一部の地域に配信されます。緊急速報メールの受信時に、悪意のあるアプリによってデバイスの動作や処理が妨害される恐れがあります。"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"通話の管理"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"デバイスでの通話に関する詳細の参照と、通話の操作をアプリに許可します。"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"緊急速報メール SMS の読み取り"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"デバイスで受信した緊急速報メール SMS の読み取りをアプリに許可します。緊急速報メールは、緊急事態を警告する目的で一部の地域に配信されます。緊急速報メールの受信時に、悪意のあるアプリによってデバイスの動作や処理が妨害される恐れがあります。"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"登録したフィードの読み取り"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index e77068d..f7ce159 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"საშუალებას აძლევს აპს, დაუკავშირდეს cell broadcast მოდულს იმისთვის, რომ გადაამისამართოს cell broadcast შეტყობინებები მათი მიღებისთანავე. Cell broadcast გაფრთხილებები მიეწოდება ზოგიერთ მდებარეობაზე საგანგებო სიტუაციების შესახებ გაფრთხილების მიზნით. საგანგებო cell broadcast-ის მიღების დროს, მავნე აპებმა შეიძლება ხელი შეუშალონ თქვენი მოწყობილობის ფუნქციონირებას ან ოპერაციებს."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"მიმდინარე ზარების მართვა"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"საშუალებას აძლევს აპს, ნახოს თქვენს მოწყობილობაზე მიმდინარე ზარების დეტალები და აკონტროლოს ეს ზარები."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"მასიური დაგზავნის შეტყობინებების წაკითხვა"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"აპს შეეძლება, წაიკითხოს თქვენს მოწყობილობაზე გამოგზავნილი ქსელის სამაუწყებლო შეტყობინებები. სამაუწყებლო გაფრთხილებები მოგეწოდებათ ზოგიერთ ადგილზე ექსტრემალური სიტუაციების შესახებ გასაფრთხილებლად. ქსელის გადაუდებელი შეტყონიბენის მიღების დროს მავნე აპებმა შეიძლება ხელი შეუშალონ თქვენი მოწყობილობის ფუნქციონირებას ან ოპერაციებს."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"გამოწერილი არხების წაკითხვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index e6af912..c459954 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Ұялы таратылым хабарлары алынғаннан кейін, олардың бағытын өзгерту үшін қолданбаға ұялы таратылым модулімен байланыстыруға мүмкіндік береді. Ұялы таратылым ескертулері кей аймақтарда төтенше жағдайлар туралы хабарлау үшін беріледі. Төтенше жағдай туралы ұялы таратылым хабары алынғаннан кейін, зиянды қолданбалар құрылғы жұмысына кедергі келтіруі мүмкін."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Қазіргі қоңырауларды басқару"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Қолданбаға құрылғыдағы қазіргі қоңыраулар туралы мәліметтерді көруге және басқаруға мүмкіндік береді."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ұялы хабар тарату хабарларын оқу"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Қолданбаға ұялы таратылым хабарларын оқу мүмкіндігін береді. Ұялы таратылым дабылдары кейбір аймақтарда төтенше жағдай туралы ескерту үшін қолданылады. Төтенше ұялы хабарлар келгенде залалды қолданбалар құрылғының жұмысына кедергі жасауы мүмкін."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"жазылған ағындарды оқу"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 7133527..364db0c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"អនុញ្ញាតឱ្យ​កម្មវិធី​ភ្ជាប់ទៅ​ម៉ូឌុល​ការផ្សាយចល័ត ដើម្បីបញ្ជូន​សារផ្សាយ​ចល័តបន្ត នៅពេល​ទទួលបាន​សារទាំងនោះ។ ការជូនដំណឹងអំពី​ការផ្សាយចល័ត​ត្រូវបានបញ្ជូនទៅ​ទីតាំងមួយចំនួន ដើម្បីព្រមាន​អ្នក​អំពីស្ថានភាព​អាសន្ន។ កម្មវិធី​គ្រោះថ្នាក់​អាច​រំខាន​ដល់ដំណើរការ ឬប្រតិបត្តិការ​ឧបករណ៍​របស់អ្នក នៅពេល​ទទួលបានការផ្សាយ​ចល័តពេលមានអាសន្ន​។"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"គ្រប់គ្រង​ការហៅទូរសព្ទដែល​កំពុងដំណើរការ"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"អនុញ្ញាតឱ្យ​កម្មវិធីមើលព័ត៌មានលម្អិត​អំពីការហៅទូរសព្ទ​ដែលកំពុងដំណើរការ​នៅលើឧបករណ៍​របស់អ្នក និងគ្រប់គ្រង​ការហៅទូរសព្ទទាំងនេះ។"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"អាន​សារ​ប្រកាស​ចល័ត"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ឲ្យ​កម្មវិធី​អាន​សារ​ប្រកាស​ការ​ហៅ​ដែល​ឧបករណ៍​របស់​​អ្នក​បាន​ទទួល។ ការ​ជូន​ដំណឹង​ប្រកាស​ចល័ត​ត្រូវ​បាន​បញ្ជូន​ទៅ​ទីតាំង​មួយ​ចំនួន ដើម្បី​ព្រមាន​អ្នក​អំពី​ស្ថានភាព​អាសន្ន។ កម្មវិធី​ព្យាបាទ​អាច​ជ្រៀតជ្រែក​ការ​អនុវត្ត ឬ​ប្រតិបត្តិការ​ឧបករណ៍​របស់​អ្នក​​ពេល​ទទួល​ការ​ប្រកាស​ចល័ត​ពេល​អាសន្ន។"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"អាន​អត្ថបទ​ព័ត៌មាន​បាន​ជាវ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 1e9414a..89e2361 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ಸೆಲ್ ಪ್ರಸಾರವು ಸಂದೇಶಗಳನ್ನು ಸ್ವೀಕರಿಸಿದ ರೀತಿಯಲ್ಲಿಯೇ ಫಾರ್ವರ್ಡ್ ಮಾಡಲು, ಸೆಲ್ ಪ್ರಸಾರ ಮಾಡ್ಯುಲ್‌ ಅನ್ನು ಪ್ರತಿಬಂಧಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಕೆಲವು ಸ್ಥಳಗಳಲ್ಲಿ ತುರ್ತು ಸ್ಥಿತಿಗಳ ಕುರಿತು ನಿಮಗೆ ಎಚ್ಚರಿಸಲು ಸೆಲ್ ಪ್ರಸಾರದ ಎಚ್ಚರಿಕೆಗಳನ್ನು ಕಳುಹಿಸಲಾಗುತ್ತದೆ. ತುರ್ತು ಸೆಲ್‌ ಪ್ರಸಾರವನ್ನು ಸ್ವೀಕರಿಸಿದಾಗ ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಾಚರಣೆ ಅಥವಾ ಕಾರ್ಯಕ್ಷಮತೆಗೆ ದುರುದ್ದೇಶಪೂರಿತ ಆ್ಯಪ್‌ಗಳು ಹಸ್ತಕ್ಷೇಪ ಮಾಡಬಹುದು."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಕರೆಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಕರೆಗಳ ಕುರಿತಾದ ವಿವರಗಳನ್ನು ನೋಡಲು ಮತ್ತು ಆ ಕರೆಗಳನ್ನು ನಿಯಂತ್ರಿಸಲು ಆ್ಯಪ್ ಒಂದಕ್ಕೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ಸೆಲ್ ಪ್ರಸಾರದ ಸಂದೇಶಗಳನ್ನು ಓದಿರಿ"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ನಿಮ್ಮ ಸಾಧನದಿಂದ ಸ್ವೀಕರಿಸಿದ ಸೆಲ್ ಪ್ರಸಾರ ಸಂದೇಶಗಳನ್ನು ರೀಡ್ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಸೆಲ್ ಪ್ರಸಾರ ಎಚ್ಚರಿಕೆಗಳನ್ನು ತುರ್ತು ಸಂದರ್ಭಗಳಲ್ಲಿ ನಿಮಗೆ ಎಚ್ಚರಿಸುವ ಸಲುವಾಗಿ ಕೆಲವು ಸ್ಥಳಗಳಲ್ಲಿ ವಿತರಿಸಲಾಗುತ್ತದೆ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‌‌‌ಗಳು ತುರ್ತು ಸೆಲ್ ಪ್ರಸಾರವನ್ನು ಸ್ವೀಕರಿಸುವಾಗ, ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಕ್ಷಮತೆ ಇಲ್ಲವೇ ಕಾರ್ಯಾಚರಣೆಯಲ್ಲಿ ಹಸ್ತಕ್ಷೇಪ ಮಾಡಬಹುದು."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ಚಂದಾದಾರ ಫೀಡ್‌ಗಳನ್ನು ಓದಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f78d0af..a129c9bb 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"셀 브로드캐스트 메시지를 수신하자마자 전달하기 위해 앱이 셀 브로드캐스트 모듈에 연결하도록 허용합니다. 비상 상황임을 알리기 위해 일부 지역에서 셀 브로드캐스트 경고가 전달됩니다. 비상 셀 브로드캐스트를 수신할 때 악성 앱이 기기의 성능이나 작동을 방해할 수 있습니다."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"진행 중인 전화 관리"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"앱에서 기기의 진행 중인 전화에 관한 세부정보를 확인하고 전화를 제어하도록 허용합니다."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"셀 브로드캐스트 메시지 읽기"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"앱이 기기가 수신한 셀 브로드캐스트 메시지를 읽을 수 있도록 합니다. 비상 상황임을 알리기 위해 일부 지역에서 셀 브로드캐스트 경고가 전달됩니다. 비상 셀 브로드캐스트를 수신할 때 악성 앱이 기기의 성능이나 작동을 방해할 수 있습니다."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"가입된 피드 읽기"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e7ee2e8..b84dcf5 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Уюк жөнөтүүлөрүнүн билдирүүлөрү келген сайын башка номерге багыттап туруу үчүн колдонмого уюк жөнөтүүлөрүнүн модулу менен байланышууга уруксат берет. Шашылыш уюк жөнөтүүлөрү кээ бир жерлердеги өзгөчө кырдаалдар тууралуу сизге эскертүү үчүн жөнөтүлөт. Зыянкеч колдонмолор шашылыш уюк жөнөтүүлөрү кабыл алынганда түзмөктүн майнаптуулугуна же иштешине жолтоо болушу мүмкүн."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Учурдагы чалууларды башкаруу"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Колдонмого телефонуңузда аткарылып жаткан чалууларды көрүп, аларды көзөмөлдөөгө уруксат берет."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"уюктук берүү билдирүүлөрүн окуу"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Колдонмого түзмөгүңүз кабыл алган уюк берүүнүн билдирүүлөрүн окууга жол берет. Шашылыш эскертүү билдирүүлөрү кээ бир жерлердеги өзгөчө кырдаалдар тууралу сизди эскертүү үчүн жөнөтүлөт. Зыяндуу колдономолор шашылыш эскертүүлөр берилип жатканда, сиздин түзмөктүн иштешине жолтоо болушу мүмкүн."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"жазылган түрмөктөрдү окуу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 84fea73..267f60d 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ອະນຸຍາດໃຫ້ແອັບຜູກມັດກັບໂມດູນການກະຈາຍສັນຍານໂທລະສັບເພື່ອສົ່ງຕໍ່ຂໍ້ຄວາມການກະຈາຍສັນຍານໂທລະສັບເມື່ອໄດ້ຮັບມາ. ການເຕືອນການກະຈາຍສັນຍານໂທລະສັບແມ່ນຖືກຈັດສົ່ງໃນບາງສະຖານທີ່ເພື່ອເຕືອນທ່ານໃນກໍລະນີມີເຫດການສຸກເສີນເກີດຂຶ້ນ. ແອັບທີ່ເປັນອັນຕະລາຍອາດລົບກວນປະສິດທິພາບ ຫຼື ການເຮັດວຽກຂອງອຸປະກອນທ່ານເມື່ອໄດ້ຮັບການກະຈາຍສັນຍານໂທລະສັບສຸກເສີນ."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ຈັດການສາຍໂທອອກ"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ອະນຸຍາດໃຫ້ແອັບໃດໜຶ່ງເບິ່ງເຫັນລາຍລະອຽດກ່ຽວກັບສາຍໂທອອກຢູ່ອຸປະກອນຂອງທ່ານ ແລະ ເພື່ອຄວບຄຸມການໂທເຫຼົ່ານີ້."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ອ່ານຂໍ້ຄວາມກະຈາຍສັນຍານຂອງເສົາສັນຍານ"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ອະນຸຍາດໃຫ້ແອັບຯ ສາມາດອ່ານຂໍ້ຄວາມແຈ້ງເຕືອນເຫດສຸກເສີນ ທີ່ໄດ້ຮັບໂດຍອຸປະກອນຂອງທ່ານ. ການແຈ້ງເຕືອນສຸກເສີນທີ່ມີໃຫ້ບໍລິການໃນບາງພື້ນທີ່ ເພື່ອແຈ້ງເຕືອນໃຫ້ທ່ານຮູ້ເຖິງສະຖານະການສຸກເສີນ. ແອັບພລິເຄຊັນທີ່ເປັນອັນຕະລາຍອາດລົບກວນປະສິດທິພາບ ຫຼືການດຳເນີນງານຂອງອຸປະກອນຂອງທ່ານ ເມື່ອໄດ້ການຮັບແຈ້ງເຕືອນສຸກເສີນຈາກສະຖານີມືຖື."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ອ່ານຂໍ້ມູນຟີດທີ່ສະໝັກໄວ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0991daa..4696722 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -372,6 +372,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Programai leidžiama susaistyti transliacijos mobiliuoju modulį, kad būtų galima persiųsti mobiliuoju transliuojamus pranešimus, kai jie gaunami. Transliacijos mobiliuoju įspėjimai pristatomi kai kuriose vietovėse, kad būtų galima įspėti apie kritines situacijas. Kai gaunamas mobiliuoju transliuojamas pranešimas apie kritinę situaciją, kenkėjiškos programos gali trukdyti įrenginiui veikti ar jį naudoti."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Tvarkyti vykstančius skambučius"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Programai leidžiama peržiūrėti išsamią informaciją apie vykstančius skambučius įrenginyje ir valdyti šiuos skambučius."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"skaityti mobiliuoju transliuojamus pranešimus"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Programai leidžiama skaityti mobiliuoju transliuojamus pranešimus, gaunamus jūsų įrenginyje. Mobiliuoju transliuojami įspėjimai pristatomi kai kuriose vietose, kad įspėtų apie kritines situacijas. Kai gaunamas  mobiliuoju transliuojamas pranešimas apie kritinę situaciją, kenkėjiškos programos gali trukdyti įrenginiui veikti ar jį naudoti."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"skaityti prenumeruojamus tiekimus"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 68f496a..79e82cc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Ļauj piesaistīt lietotni šūnu apraides modulim, lai pārsūtītu šūnu apraides ziņojumus, tiklīdz tie tiek saņemti. Šūnu apraides brīdinājumi tiek piegādāti noteiktās atrašanās vietās, lai brīdinātu jūs par ārkārtas situācijām. Ļaunprātīgas lietotnes var traucēt ierīces veiktspēju vai darbības, kad ir saņemts ārkārtas šūnas apraides ziņojums."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Aktīvo zvanu pārvaldība"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Ļauj lietotnei skatīt detalizētu informāciju par aktīvajiem zvaniem jūsu ierīcē, kā arī kontrolēt šos zvanus."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"šūnu apraides ziņojumu lasīšana"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Ļauj lietotnei lasīt ierīcē saņemtos šūnu apraides ziņojumus. Šūnu apraides brīdinājumi tiek piegādāti dažās atrašanās vietās, lai brīdinātu jūs par ārkārtas situācijām. Ļaunprātīgas lietotnes var traucēt ierīces veiktspēju vai darbības, kad ir saņemts ārkārtas šūnas apraides ziņojums."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lasīt abonētās plūsmas"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 8828ab4..82cb889d 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Дозволува апликацијата да се врзе со модулот за мобилен пренос за да проследува пораки за мобилен пренос штом ќе се примат. Предупредувањата за мобилно емитување се доставуваат на некои локации за да ве предупредат на итни ситуации. Злонамерните апликации може да пречат во ефикасноста или работењето на вашиот уред кога се прима емитување за итен случај."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Управување со тековни повици"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Дозволува апликацијата да гледа детали за тековните повици на уредот и да ги контролира овие повици."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"прочитај пораки за мобилно емитување"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Овозможува апликациите да ги читаат пораките за мобилно емитување што ги прима вашиот уред. Предупредувањата за мобилно емитување се доставуваат на некои локации, за да ве предупредат на итни ситуации. Злонамерните апликации може да пречат во ефикасноста или работењето на вашиот уред кога се прима емитување за итен случај."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"читај претплатени навестувања на содржина"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index cb0cb33..2bea784 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"സ്വീകരിക്കുന്ന മുറയ്ക്ക് ബ്രോഡ്‌കാസ്‌റ്റ് സന്ദേശങ്ങൾ കൈമാറുന്നതിന് സെൽ ബ്രോഡ്‌കാസ്‌റ്റ് മോഡ്യൂളിലേക്ക് ബൈൻഡ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു. അടിയന്തര സാഹചര്യങ്ങളെ കുറിച്ച് നിങ്ങൾക്ക് മുന്നറിയിപ്പ് നൽകുന്നതിന് ചില ലൊക്കേഷനുകളിൽ സെൽ ബ്രോഡ്‌കാസ്‌റ്റ് അലേർട്ടുകൾ ഡെലിവറി ചെയ്യപ്പെടുന്നു. ഒരു അടിയന്തര സെൽ ബ്രോഡ്‌കാസ്റ്റ് ലഭിക്കുമ്പോൾ ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനത്തെയോ പ്രവർത്തനത്തെയോ തടസപ്പെടുത്താനിടയുണ്ട്."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"നടന്നുകൊണ്ടിരിക്കുന്ന കോളുകൾ മാനേജ് ചെയ്യുക"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"നിങ്ങളുടെ ഉപകരണത്തിൽ നടന്നുകൊണ്ടിരിക്കുന്ന കോളുകളുടെ വിശദാംശങ്ങൾ കാണാനും ഈ കോളുകൾ നിയന്ത്രിക്കാനും ആപ്പിനെ അനുവദിക്കുന്നു."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"സെൽ പ്രക്ഷേപണ സന്ദേശങ്ങൾ റീഡുചെയ്യുക"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"നിങ്ങളുടെ ഉപകരണത്തിൽ ലഭിച്ച സെൽ പ്രക്ഷേപണ സന്ദേശങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. അടിയന്തര സാഹചര്യങ്ങളെക്കുറിച്ച് നിങ്ങൾക്ക് മുന്നറിയിപ്പ് നൽകാനായി ചില ലൊക്കേഷനുകളിൽ നൽകപ്പെടുന്നവയാണ് സെൽ പ്രക്ഷേപണ അലേർട്ടുകൾ. ഒരു അടിയന്തര സെൽ പ്രക്ഷേപണം ലഭിക്കുമ്പോൾ, ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനമോ പ്രവർത്തനമോ തടസ്സപ്പെടുത്താനിടയുണ്ട്."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"സബ്‌സ്ക്രൈബ് ചെയ്‌ത ഫീഡുകൾ വായിക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 9bff0da..5d8f143 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Гар утсанд масс мессеж түгээх онцлогийн мессежийг хүлээн авах үед түүнийг шилжүүлэх зорилгоор аппад гар утсанд масс мессеж түгээх модультай холбогдохыг зөвшөөрөх Гар утсанд масс мессеж түгээх онцлогийн сэрэмжлүүлэг нь онцгой нөхцөл байдлын тухай танд анхааруулахын тулд зарим байршилд хүрдэг. Гар утсанд масс мессеж түгээх онцлогийн илгээх онцгой нөхцөл байдлын тухай мессежийг хүлээн авах үед хортой апп таны төхөөрөмжийн гүйцэтгэл эсвэл ажиллагаанд саад учруулж болзошгүй."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Үргэлжилж буй дуудлагыг удирдах"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Аппад таны төхөөрөмж дээрх үргэлжилж буй дуудлагын талаарх дэлгэрэнгүйг харах болон эдгээр дуудлагыг хянахыг зөвшөөрнө."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"үүрэн өргөн дамжууллын мессеж унших"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Апп нь таны төхөөрөмжийн хүлээн авсан үүрэн өргөн дамжуулах мессежийг унших боломжтой. Үүрэн өргөн дамжууллын мэдэгдэл нь яаралтай нөхцөл байдлыг анхааруулах зорилгоор зарим байршлуудад хүрдэг. Хортой апп нь яаралтай үүрэн өргөн дамжууллыг хүлээн авсан үед таны төхөөрөмжийн ажиллагаа болон чадамжид нөлөөлөх боломжтой."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"бүртгүүлсэн хангамжийг унших"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4e55d1c..6654a14 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"सेल प्रसारण मेसेज मिळाल्यानंतर ते फॉरवर्ड करण्यासाठी ॲपला सेल प्रसारण मॉड्यूलमध्ये प्रतिबद्ध करण्याची अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थीतींची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरित केल्या जातात. दुर्भावनापूर्ण अ‍ॅप्स आणीबाणी सेल प्रसारण मिळवतात तेव्हा ती तुमच्या डिव्हाइसच्या परफॉर्मन्समध्ये किंवा कामामध्ये कदाचित व्यत्यय आणू शकतात."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"सुरू असलेले कॉल व्यवस्थापित करा"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ॲपला तुमच्या डिव्हाइसवर सुरू असलेल्या कॉलचे तपशील पाहण्याची आणि या कॉलना नियंत्रित करण्याची अनुमती द्या."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल प्रसारण मेसेज वाचा"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"आपल्या डिव्हाइसद्वारे प्राप्त केलेले सेल प्रसारण मेसेज वाचण्यासाठी अ‍ॅप ला अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थितीची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरीत केल्या जातात. आणीबाणी सेल प्रसारण प्राप्त होते तेव्हा आपल्या डिव्हाइसच्या कार्यप्रदर्शनात किंवा कार्यात दुर्भावनापूर्ण अ‍ॅप्स व्यत्यय आणू शकतात."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"सदस्यत्व घेतलेली फीड वाचा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 45e3d91..d51dafe 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Membenarkan apl terikat pada modul siaran sel untuk mengirim semula mesej siaran sel apabila diterima. Makluman siaran sel dihantar di sesetengah lokasi untuk memberi amaran kepada anda tentang situasi kecemasan. Apl hasad boleh mengganggu prestasi atau operasi peranti anda apabila siaran sel kecemasan diterima."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Urus panggilan yang sedang berjalan"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Benarkan apl melihat butiran panggilan yang sedang berjalan pada peranti anda dan mengawal panggilan ini."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"baca mesej siaran sel"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Membolehkan apl membaca mesej siaran sel yang diterima oleh peranti anda. Isyarat siaran sel dihantar di beberapa lokasi untuk memberi amaran kepada anda tentang situasi kecemasan. Apl hasad boleh mengganggu prestasi atau operasi peranti anda apabila siaran sel kecemasan diterima."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"baca suapan langganan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 6aee13e..a9726a5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"စာတို ဖြန့်ဝေခြင်းစနစ် မော်ဂျူးကိုပေါင်းရန် အက်ပ်များအား ခွင့်ပြုသည်။ ၎င်းမှာ စာတို ဖြန့်ဝေခြင်းစနစ်သုံး မက်ဆေ့ဂျ်များကို လက်ခံရရှိသည့်အတိုင်း ထပ်ဆင့်ပို့ရန် ဖြစ်သည်။ အချို့တည်နေရာများတွင် သင့်အား အရေးပေါ်အခြေအနေများကို သတိပေးရန် စာတို ဖြန့်ဝေခြင်းစနစ်သုံး သတိပေးချက်များကို ပေးပို့သည်။ အရေးပေါ် စာတို ဖြန့်ဝေခြင်းကို ရရှိသည့်အခါ သံသယဖြစ်နိုင်ဖွယ်ရှိသည့် အက်ပ်များက သင့်စက်၏ စွမ်းဆောင်ရည်နှင့် အော်ပရေးရှင်းတို့ကို အနှောင့်အယှက်ပေးနိုင်သည်။"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"လက်ရှိခေါ်ဆိုမှုများကို စီမံခြင်း"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"သင့်စက်ပစ္စည်းပေါ်ရှိ လက်ရှိခေါ်ဆိုမှုများအကြောင်း အသေးစိတ်များကို ကြည့်ရှုရန်နှင့် ဤခေါ်ဆိုမှုများကို ထိန်းချုပ်ရန် အက်ပ်အား ခွင့်ပြုသည်။"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"စာတိုများ ဖြန့်ဝေခြင်းစနစ်အား ဖတ်ခြင်း"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"အပလီကေးရှင်းကို သင်၏ စက်ပစ္စည်းမှ လက်ခံရရှိသော အများလွှင့်ထုတ်ချက်များကို ဖတ်ရန် ခွင့်ပြုသည်။  အများလွှင့်ထုတ်ချက်များသည် အရေးပေါ်အခြေအနေများကို သင့်အား သတိပေးရန် အချို့ နေရာများတွင် ပို့ပေးသည်။ အရေးပေါ်သတိပေးချက် ထုတ်လွှင့်ချက်ကို လက်ခံရရှိချိန်တွင်အန္တရာယ် ဖြစ်စေနိုင်သော အပလီကေးရှင်းများသည် သင့်စက်ပစ္စည်း၏ လုပ်ငန်းလည်ပတ်မှုနှင့် စွမ်းဆောင်မှုကို ဝင်စွက်ဖက်နိုင်သည်။"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"အမည်သွင်းထားသောဖိဖ့်များကို ဖတ်ခြင်း"</string>
@@ -802,7 +806,7 @@
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"အစမြင်ကွင်း ခွင့်ပြုချက် အသုံးပြုမှု"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"အက်ပ်တစ်ခုအတွက် ခွင့်ပြုချက်စတင်အသုံးပြုမှုကို ကိုင်ဆောင်သူအား ခွင့်ပြုသည်။ ပုံမှန်အက်ပ်များအတွက် ဘယ်သောအခါမျှ မလိုအပ်ပါ။"</string>
     <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ခွင့်ပြုသည့် ဆုံးဖြတ်ချက်များကို စတင်ကြည့်ခြင်း"</string>
-    <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ခွင့်ပြုထားသည့်အက်ပ်အား ခွင့်ပြုသည့်ဆုံးဖြတ်ချက်များကို ကြည့်နိုင်ရန်အတွက် စခရင်စတင်ရန် ခွင့်ပြုနိုင်သည်။ သာမန်အက်ပ်များအတွက် မည်သည့်အခါမျှ မလိုအပ်နိုင်ပါ။"</string>
+    <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ခွင့်ပြုထားသည့်အက်ပ်အား ခွင့်ပြုသည့်ဆုံးဖြတ်ချက်များကို ကြည့်နိုင်ရန်အတွက် စခရင်စတင်ရန် ခွင့်ပြုနိုင်သည်။ သာမန်အက်ပ်များအတွက် မည်သည့်အခါမှ မလိုအပ်နိုင်ပါ။"</string>
     <string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"အက်ပ်ဝန်ဆောင်မှုများကို စတင်ကြည့်ခြင်း"</string>
     <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ဝန်ဆောင်မှုအချက်အလက်ကိုများကို ခွင့်ပြုချက်ရထားသည့် အက်ပ်အား စတင်ကြည့်နိုင်ရန် ခွင့်ပြုသည်။"</string>
     <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"နမူနာနှုန်းမြင့်သော အာရုံခံစနစ်ဒေတာကို သုံးပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 4965d90..822218d1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tillat at denne appen binder seg til modulen for kringkastede meldinger for å videresende kringkastede meldinger når de mottas. Kringkastede varsler leveres noen steder for å advare deg om nødssituasjoner. Skadelige apper kan forstyrre ytelsen eller funksjonen til enheten din når en kringkastet nødmelding mottas."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Administrer pågående anrop"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Gir en app tillatelse til å se informasjon om pågående anrop på enheten og til å kontrollere disse anropene."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lese kringkastede meldinger"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Tillater at appen kan lese kringkastede meldinger enheten din mottar. Kringkastede varsler leveres noen steder for å advare deg om nødssituasjoner. Skadelige apper kan forstyrre ytelsen eller funksjonen til enheten din når en kringkastet nødmelding mottas."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lese abonnement på nyhetskilder"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 7392276..de85e5c 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"मोबाइल प्रसारणसम्बन्धी म्यासेजहरू प्राप्त हुनासाथै तिनीहरूलाई फर्वार्ड गर्नका लागि यसले एपलाई मोबाइल प्रसारण मोड्युलमा जोडिने अनुमति दिन्छ। तपाईंलाई कतिपय स्थानमा आपत्‌कालीन अवस्थाका बारेमा जानकारी दिनका लागि मोबाइल प्रसारणसम्बन्धी अलर्टहरू पठाइन्छ। हानिकारक एपहरूले आपत्‌कालीन मोबाइल प्रसारण प्राप्त हुँदा तपाईंको यन्त्रलाई कार्य सम्पादन गर्ने वा सञ्चालित हुने क्रममा हस्तक्षेप गर्न सक्छन्।"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"जारी रहेका कलहरू व्यवस्थापन गर्न"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"तपाईं यो एपलाई अनुमति दिनुभयो यस एपले तपाईंको डिभाइसमा जारी रहेका कलसम्बन्धी विवरण हेर्न र ती कलहरू नियन्त्रण गर्न सक्छ।"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल प्रसारित म्यासेजहरू पढ्नुहोस्"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"तपाईंको उपकरणद्वारा प्राप्त सेल प्रसारण म्यासेजहरू एपलाई पढ्न अनुमति दिन्छ। सेल प्रसारण चेतावनीहरू केही स्थानहरूमा तपाईंलाई आपत्‌कालीन गतिविधिहरूको बारेमा सचेत गराउन गरिएका छन्। खराब एपहरूले एउटा आपत्‌कालीन सेल प्रसारण प्राप्त गर्दछ जब तपाईंको उपकरणको प्रदर्शन वा अपरेशनको साथ हस्तक्षेप गर्न सक्दछन्।"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"सदस्य बनाइका फिडहरू पढ्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index dd6f3a6..72a7e68 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Hiermee kan de app de module voor cell broadcasts binden om cell broadcast-berichten door te sturen als die worden ontvangen. Cell broadcast-waarschuwingen worden op bepaalde locaties verzonden om je te waarschuwen voor noodsituaties. Schadelijke apps kunnen de prestaties of verwerking van je apparaat verstoren als een bericht met een noodmelding wordt ontvangen."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Actieve gesprekken beheren"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Hiermee kan een app informatie over actieve gesprekken op je apparaat bekijken en deze gesprekken beheren."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"infodienstberichten lezen"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Toestaan dat de app infodienstberichten leest die worden ontvangen op je apparaat. Infodienstberichten worden verzonden naar bepaalde locaties om u te waarschjeen voor noodsituaties. Schadelijke apps kunnen de prestaties of verwerking van je apparaat verstoren wanneer een infodienstbericht wordt ontvangen."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"Geabonneerde feeds lezen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index bd4653b..1575fd8 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ସେଲ୍ ପ୍ରସାରଣ ମେସେଜ୍ ପ୍ରାପ୍ତ ହେବା ପରେ ସେଗୁଡ଼ିକୁ ଫର୍‍ୱାର୍ଡ କରିବା ପାଇଁ ଆପ୍‍କୁ ସେଲ୍ ପ୍ରସାରଣ ମଡ୍ୟୁଲ୍ ସହିତ ସଂଯୁକ୍ତ କରିବାକୁ ଅନୁମତି ଦିଏ। ଜରୁରୀକାଳୀନ ପରିସ୍ଥିତିରେ ଆପଣଙ୍କୁ ଚେତାବନୀ ଦେବା ପାଇଁ କିଛି ଲୋକେସନ୍‍‍ରେ ସେଲ୍ ପ୍ରସାରଣ ଆଲର୍ଟ ବିତରଣ କରାଯାଇଥାଏ। ଏକ ଜରୁରୀକାଳୀନ ସେଲ୍ ପ୍ରସାରଣ ପ୍ରାପ୍ତ ହେବା ସମୟରେ କିଛି କ୍ଷତିକାରକ ଆପ୍ସ ହୁଏତ ଆପଣଙ୍କର ଡିଭାଇସ୍‍ର କାର୍ଯ୍ୟଦକ୍ଷତା କିମ୍ବା କାର୍ଯ୍ୟ ପ୍ରକ୍ରିୟାରେ ହସ୍ତକ୍ଷେପ କରିପାରେ।"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ଚାଲୁଥିବା କଲଗୁଡ଼ିକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ଏକ ଆପକୁ ଆପଣଙ୍କ ଡିଭାଇସରେ ଚାଲୁଥିବା କଲଗୁଡ଼ିକର ବିବରଣୀ ଦେଖିବା ଓ ଏହି କଲଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ସେଲ୍‍ ବ୍ରଡ୍‍କାଷ୍ଟ ମେସେଜ୍‍ ପଢ଼ନ୍ତୁ"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ଆପଣଙ୍କ ଡିଭାଇସ୍‍ରେ ପ୍ରାପ୍ତ ହୋଇଥିବା ସେଲ୍‍ ବ୍ରଡ୍‍କାଷ୍ଟ ମେସେଜ୍‍ ପଢିବାକୁ ଆପ୍‍କୁ ଅନୁମତି ଦିଏ। ଜରୁରୀକାଳୀନ ଅବସ୍ଥା ବିଷୟରେ ଆପଣଙ୍କୁ ସତର୍କ କରାଇବାକୁ କିଛି ଲୋକେଶନ୍‍ରେ ସେଲ୍‍ ବ୍ରଡ୍‍କାଷ୍ଟ ସତର୍କ ଡେଲିଭର୍ କରାଯାଇଥାଏ। ଏକ ଜରୁରୀକାଳୀନ ସେଲ୍‍ ବ୍ରଡ୍‍କାଷ୍ଟ ପ୍ରାପ୍ତ ହେବାପରେ ହାନୀକାରକ ଆପ୍‍ ଆପଣଙ୍କ ଡିଭାଇସ୍‍ର କାର୍ଯ୍ୟକ୍ଷମତା କିମ୍ବା ସଞ୍ଚାଳନାରେ ବାଧା ପହଞ୍ଚାଇପାରନ୍ତି।"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ସବସ୍କ୍ରାଇବ୍ ହୋଇଥିବା ଫୀଡ୍‌କୁ ପଢ଼ନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index f162344..01f4fe1 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ਐਪ ਨੂੰ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹਿਆਂ ਦੇ ਪ੍ਰਾਪਤ ਹੁੰਦੇ ਹੀ ਉਨ੍ਹਾਂ ਨੂੰ ਅੱਗੇ ਭੇਜਣ ਲਈ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਮਾਡਿਊਲ ਨਾਲ ਜੋੜਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ। ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਅਲਰਟ ਤੁਹਾਨੂੰ ਐਮਰਜੈਂਸੀ ਸਥਿਤੀਆਂ ਦੀ ਚਿਤਾਵਨੀ ਦੇਣ ਲਈ ਕੁਝ ਟਿਕਾਣਿਆਂ \'ਤੇ ਪ੍ਰਦਾਨ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਭੈੜੀਆਂ ਐਪਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਜਾਂ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾ ਸਕਦੀਆਂ ਹਨ ਜਦੋਂ ਇੱਕ ਐਮਰਜੈਂਸੀ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ਜਾਰੀ ਕਾਲਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ਐਪ ਨੂੰ ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਜਾਰੀ ਕਾਲਾਂ ਬਾਰੇ ਵੇਰਵੇ ਦੇਖਣ ਅਤੇ ਇਹਨਾਂ ਕਾਲਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਦਿਓ।"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ਸੈਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹੇ ਪੜ੍ਹੋ"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਵੱਲੋਂ ਪ੍ਰਾਪਤ ਕੀਤੇ ਸੈੱਲ ਪ੍ਰਸਾਰਣ ਸੁਨੇਹੇ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਸੈੱਲ ਪ੍ਰਸਾਰਣ ਚਿਤਾਵਨੀਆਂ ਤੁਹਾਨੂੰ ਸੰਕਟਕਾਲੀਨ ਸਥਿਤੀਆਂ ਦੀ ਚਿਤਾਵਨੀ ਦੇਣ ਲਈ ਕੁਝ ਨਿਰਧਾਰਤ ਟਿਕਾਣਿਆਂ ਤੇ ਪ੍ਰਦਾਨ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਖਰਾਬ ਐਪਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਪ੍ਰਦਰਸ਼ਨ ਜਾਂ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾ ਸਕਦੀਆਂ ਹਨ ਜਦੋਂ ਇੱਕ ਸੰਕਟਕਾਲੀਨ ਸੈੱਲ ਪ੍ਰਸਾਰਣ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ਸਬਸਕ੍ਰਾਈਬ ਕੀਤੇ ਫੀਡਸ ਪੜ੍ਹੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7097503..375053e 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -372,6 +372,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Zezwala aplikacji powiązać się z modułem komunikatów z sieci komórkowej, aby przekazywać je w momencie, w którym są otrzymywane. W niektórych lokalizacjach komunikaty alarmowe z sieci komórkowej są dostarczane, aby ostrzec Cię o sytuacjach zagrożenia. Złośliwe aplikacje mogą wpływać na działanie urządzenia lub zakłócać je po nadejściu komunikatu alarmowego z sieci komórkowej."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Zarządzaj połączeniami w toku"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Zezwala aplikacji zobaczyć detale dotyczące połączeń w toku na Twoim urządzeniu i na kontrolę tych połączeń."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"odczyt komunikatów z sieci komórkowej"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Zezwala aplikacji na odczyt komunikatów z sieci komórkowej odebranych na urządzeniu. Komunikaty alarmowe z sieci komórkowej są dostarczane w niektórych lokalizacjach w celu ostrzeżenia Cię o sytuacjach zagrożenia. Złośliwe aplikacje mogą wpływać na wydajność lub zakłócać działanie urządzenia po odebraniu komunikatu alarmowego z sieci komórkowej."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"czytanie subskrybowanych źródeł"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 49b4be9..9bec567 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que o app se vincule ao módulo de transmissão celular para encaminhar mensagens de transmissão celular assim que elas forem recebidas. Alertas de transmissão celular são recebidos em alguns locais para avisar sobre situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento do dispositivo quando uma transmissão celular de emergência é recebida."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gerenciar chamadas em andamento"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que um app veja detalhes sobre chamadas em andamento no seu dispositivo e as controle."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensagens de difusão celular"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds inscritos"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f5fd19f..b1be29f 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que a app se vincule ao módulo de difusão celular para encaminhar mensagens de difusão celular à medida que são recebidas. Os alertas de difusão celular são fornecidos em algumas localizações para avisar sobre situações de emergência. As aplicações maliciosas podem interferir com o desempenho ou funcionamento do seu dispositivo quando for recebida uma difusão celular de emergência."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gerir chamadas em curso"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que uma app veja detalhes acerca das chamadas em curso no seu dispositivo e controle essas chamadas."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensagens de transmissão celular"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que a app leia mensagens de transmissão celular recebidas pelo seu dispositivo. Os alertas de transmissão celular são fornecidos em algumas localizações para avisá-lo sobre situações de emergência. As aplicações maliciosas podem interferir com o desempenho ou funcionamento do seu dispositivo quando for recebida uma transmissão celular de emergência."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds subscritos"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 49b4be9..9bec567 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que o app se vincule ao módulo de transmissão celular para encaminhar mensagens de transmissão celular assim que elas forem recebidas. Alertas de transmissão celular são recebidos em alguns locais para avisar sobre situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento do dispositivo quando uma transmissão celular de emergência é recebida."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gerenciar chamadas em andamento"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que um app veja detalhes sobre chamadas em andamento no seu dispositivo e as controle."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensagens de difusão celular"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds inscritos"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e34f989..b6029f7 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite aplicației să se conecteze la modulul de transmisie celulară pentru a redirecționa mesajele cu transmisie celulară pe măsură ce le primește. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a te avertiza cu privire la situațiile de urgență. Aplicațiile rău intenționate pot afecta performanța sau funcționarea dispozitivului când e primită o transmisie celulară de urgență."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Să gestioneze apelurile în desfășurare"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite unei aplicații să vadă detalii despre apelurile în desfășurare de pe dispozitiv și să gestioneze apelurile respective."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"citește mesajele cu transmisie celulară"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitiv. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a te avertiza cu privire la situațiile de urgență. Aplicațiile rău intenționate pot afecta performanța sau funcționarea dispozitivului când e primită o transmisie celulară de urgență."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"citire feeduri abonat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d375179..7d3b869 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -372,6 +372,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Приложение сможет выполнить привязку к модулю оповещения населения, чтобы пересылать сообщения широковещательных SMS-служб сразу после их получения. В некоторых странах эти сообщения используются для информирования об экстренных ситуациях. Вредоносное ПО может помешать работе устройства, на которое поступают такие сообщения."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Управление текущими звонками"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Приложение сможет управлять текущими звонками на вашем устройстве, а также получит доступ к сведениям о них"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"Читать сообщения массовой рассылки"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Приложение получит доступ к сообщениям широковещательных SMS-служб, которые в некоторых странах используются для информирования населения об экстренных ситуациях. Вредоносные программы могут помешать работе устройства, на которое поступают такие сообщения."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"Просмотр фидов пользователя"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index c62fe33..12cb28a 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"සෙල් විකාශන පණිවිඩ ලැබුණු විට ඒවා යොමු කිරීම සඳහා සෙල් විකාශන මොඩියුලයට බැඳීමට යෙදුමට ඉඩ දෙයි. හදිසි අවස්ථා පිළිබඳව ඔබට අනතුරු ඇඟවීම සඳහා සෙල් විකාශන ඇඟවීම් සමහර ස්ථානවල ලබා දෙනු ලැබේ. හදිසි සෙල් විකාශනයක් ලැබෙන අවස්ථාවකදී, අනිෂ්ට යෙදුම්වලින් ඔබගේ උපාංග කාර්ය සාධනයට හෝ මෙහෙයුමට බාධා සිදු විය හැකිය."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"සිදු වෙමින් පවතින ඇමතුම් කළමනාකරණය කරන්න"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ඔබගේ උපාංගයේ සිදු වෙමින් පවතින ඇමතුම් පිළිබඳ විස්තර බැලීමට සහ මෙම ඇමතුම් පාලනය කිරීමට යෙදුමකට ඉඩ දෙයි."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"සෙල් ප්‍රචාරණ පණිවිඩ කියවීම"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ඔබගේ උපාංගයට ලැබුණු සෙල් විකාශන පණිවිඩ කියවීමට යෙදුමට අවසර දෙන්න. ඔබට හදිසි අවස්ථාවන් පිළිබඳ අනතුරු ඇඟවීමට සෙල් විකාශන පණිවිඩ ඇතැම් ස්ථානවල සිට යවනු ලබයි. හදිසි සෙල් විකාශන ලැබෙන අවස්ථාවකදී, අනිෂ්ට යෙදුම් මඟින් ඔබගේ උපාංගයට කාර්ය සාධනයට හෝ ක්‍රියකරණයට බාධා සිදුවිය හැක."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"දායක වූ සංග්‍රහ කියවීම"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 61ad94d..e2161ab 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -372,6 +372,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Umožňuje aplikácii spojiť sa s modulom správ informačných služieb s cieľom preposielať prichádzajúce správy informačných služieb. Správy informačných služieb sa doručujú na určitých miestach a upozorňujú na tiesňové situácie. Škodlivé aplikácie môžu pri prijatí správy informačnej služby narušiť výkonnosť alebo prevádzku vášho zariadenia."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Správa prebiehajúcich hovorov"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Povolí aplikácii čítať podrobnosti o prebiehajúcich hovoroch v zariadení a ovládať ich."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čítať správy informačných služieb"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Umožňuje aplikácii čítať správy informačných služieb prijaté vaším zariadením. Správy informačných služieb sa doručujú na určitých miestach a upozorňujú na tiesňové situácie. Škodlivé aplikácie môžu pri prijatí správy informačnej služby narušiť výkonnosť alebo prevádzku vášho zariadenia."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čítať odoberané informačné kanály"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 79e0fa3..54cc786 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -372,6 +372,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Aplikaciji omogoča povezovanje z modulom za oddaje v celici, da posreduje sporočila oddaj v celici, takoj ko jih prejme. Na nekaterih lokacijah so opozorila oddaj v celici dostavljena, da vas opozorijo na izredne razmere. Zlonamerne aplikacije lahko vplivajo na delovanje naprave, ko prejme sporočilo oddaje v celici."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Upravljanje aktivnih klicev"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Aplikaciji dovoljuje ogled podrobnosti o aktivnih klicih v napravi in upravljanje s temi klici."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"branje sporočil oddaje v celici"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Omogoča aplikaciji branje sporočil oddaje v celici, ki jih prejme naprava. Opozorila oddaje v celici so dostavljena na nekaterih lokacijah, da vas opozorijo na izredne razmere. Zlonamerne aplikacije lahko vplivajo na delovanje naprave, ko dobi sporočilo oddaje v celici."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"branje naročenih virov"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index a160591..3bd5158 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Lejon që aplikacioni të lidhet me modulin e transmetimit celular për t\'i transferuar mesazhet e transmetimit celular menjëherë kur merren. Sinjalizimet e transmetimit celular dërgohen në disa vendndodhje për të të paralajmëruar për situata urgjente. Aplikacionet keqdashëse mund të ndërhyjnë në cilësinë e funksionimit ose në veprimin e pajisjes sate kur merret një transmetim celular urgjent."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Menaxho telefonatat në vazhdim"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Lejon që një aplikacion të shikojë detaje rreth telefonatave në vazhdim dhe t\'i kontrollojë këto telefonata."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lexo mesazhet e transmetimit të qelizës"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Lejon aplikacionin të lexojë mesazhet e transmetimit të qelizës, të marra nga pajisja jote. Alarmet e transmetimit të qelizës dërgohen në disa vendndodhje për të të paralajmëruar në situata urgjente. Aplikacionet keqdashëse mund të ndërhyjnë në veprimtarinë ose operacionin e pajisjes tënde kur merret një transmetim urgjent i qelizës."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lexo informacione të abonuara"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e1f06de..0ea7b6e 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -371,6 +371,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Дозвољава апликацији да се везује за модул порука за мобилне уређаје на локалитету да би прослеђивала поруке за мобилне уређаје на локалитету онако како су примљене. Обавештења порука за мобилне уређаје на локалитету се на неким локацијама примају као упозорења на хитне случајеве. Злонамерне апликације могу да утичу на перформансе или ометају рад уређаја када се прими порука о хитном случају за мобилне уређаје на локалитету."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Управљање одлазним позивима"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Омогућава апликацији да види детаље о одлазним позивима на уређају и да контролише те позиве."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"читање порука инфо сервиса"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Омогућава апликацији да чита поруке инфо сервиса које уређај прима. Упозорења инфо сервиса се на неким локацијама примају као упозорења на хитне случајеве. Злонамерне апликације могу да утичу на перформансе или ометају функционисање уређаја када се прими порука инфо сервиса о хитном случају."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"читање пријављених фидова"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index dc9c194..12e24b6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tillåter att appen binds till cellsändningsmodulen så att massutskick via sms kan vidarebefordras vid mottagandet. I vissa områden används massutskick via sms för att varna om nödsituationer. Skadliga appar kan påverka enhetens prestanda eller funktioner när ett massutskick via sms tas emot."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Hantera pågående samtal"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Tillåter att en app får åtkomst till information om pågående samtal på enheten och kan kontrollera dessa samtal."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"läsa SMS-meddelanden"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Appen tillåts läsa SMS som skickas till din enhet. På vissa platser skickas SMS för att varna för nödsituationer. Skadliga appar kan påverka enhetens prestanda eller funktionalitet när du får ett meddelande om en nödsituation via SMS."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"läsa flöden som du prenumererar på"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index c5979dd..4a99945 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Huruhusu programu ipachikwe katika sehemu ya matangazo ya simu ili isambaze ujumbe wa matangazo ya simu unapopokewa. Arifa za matangazo ya simu huwasilishwa katika maeneo mengine ili kukuonya juu ya hali za dharura. Huenda programu hasidi zikatatiza utendaji au shughuli ya kifaa chako matangazo ya simu ya dharura yanapopokewa."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Dhibiti simu zinazoendelea"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Huruhusu programu kuangalia maelezo kuhusu simu zinazoendelea kwenye kifaa chako na kuzidhibiti."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"soma mawasiliano ya matangazo ya simu"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Huruhusu programu kusoma mawasiliano ya matangazo ya simu yaliyoingia kwenye kifaa chako. Arifa za matangazo ya simu huwasilishwa katika maeneo mengine ili kukuonya juu ya hali za dharura. Huenda programu hasidi zikatatiza utendajikazi au shughuli ya kifaa chako wakati matangazo ya simu ya dharura yameingia."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"kusoma mipasho kutoka vyanzo unavyofuatilia"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 5017e14..20f12c4 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"செல் பிராட்காஸ்ட் மெசேஜ்களைப் பெறும்போதெல்லாம் அவற்றை முன்னனுப்பும் பொருட்டு, ஆப்ஸை செல் பிராட்காஸ்ட் மாடியூலோடு இணைக்கும். சில இடங்களில் அவசர சூழ்நிலைகளின் போது உங்களை எச்சரிக்க செல் பிராட்காஸ்ட் விழிப்பூட்டல்கள் அனுப்பப்படும். அவசரநிலை செல் பிராட்காஸ்ட்டைப் பெறும்போது, தீங்கிழைக்கும் ஆப்ஸ் உங்கள் சாதனத்தின் செயல்திறனுக்கோ செயல்பாட்டிற்கோ இடையூறு விளைவிக்கக்கூடும்."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"செயலில் உள்ள அழைப்புகளை நிர்வகித்தல்"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"உங்கள் சாதனத்தில், செயலில் உள்ள அழைப்புகள் குறித்த விவரங்களைப் பார்க்கவும் அந்த அழைப்புகளை நிர்வகிக்கவும் ஆப்ஸை அனுமதிக்கும்."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"செல் அலைபரப்புச் செய்திகளைப் படித்தல்"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"உங்கள் சாதனத்தில் பெறப்படும் செல் அலைபரப்புச் செய்திகளைப் படிப்பதற்குப் ஆப்ஸை அனுமதிக்கிறது. அவசரநிலை சூழ்நிலைகளை உங்களுக்கு எச்சரிக்கைச் செய்வதற்கு சில இடங்களில் செல் அலைபரப்பு விழிப்பூட்டல்கள் வழங்கப்படும். அவசரநிலை மொபைல் அலைபரப்புப் பெறப்படும்போது உங்கள் சாதனத்தின் செயல்திறன் அல்லது செயல்பாட்டுடன் தீங்கிழைக்கும் ஆப்ஸ் அதைத் தடுக்கலாம்."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"குழுசேர்ந்த ஊட்டங்களைப் படித்தல்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 624b2c9..ec58281 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార మెసేజ్‌లను స్వీకరించినప్పుడు, వాటిని ఫార్వర్డ్ చేయడానికి సెల్ ప్రసార మాడ్యూల్‌కు కట్టుబడి ఉండేందుకు యాప్‌ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్‌లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్‌ను స్వీకరించినప్పుడు హానికరమైన యాప్‌లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"కొనసాగుతున్న కాల్స్‌ను మేనేజ్ చేయండి"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"మీ పరికరంలో కొనసాగుతున్న కాల్స్‌ను చూడటానికి అలాగే వాటిని కంట్రోల్ చేయడానికి ఒక యాప్‌కు అనుమతిస్తోంది."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"సెల్ ప్రసార మెసేజ్‌లను చదవడం"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార మెసేజ్‌లను చదవడానికి యాప్‌ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్‌లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్‌ను స్వీకరించినప్పుడు హానికరమైన యాప్‌లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"చందా చేయబడిన ఫీడ్‌లను చదవడం"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1555984..0da6af7 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"อนุญาตให้แอปเชื่อมโยงกับโมดูลการส่งข้อมูลเตือนภัยทางมือถือ (CB) เพื่อส่งต่อข้อความจากการส่งข้อมูลเตือนภัยทางมือถือ (CB) ทันทีที่ได้รับ ระบบจะส่งการแจ้งเตือนจากการส่งข้อมูลเตือนภัยทางมือถือ (CB) ในบางตำแหน่งเพื่อแจ้งเตือนคุณเกี่ยวกับสถานการณ์ฉุกเฉิน แอปที่เป็นอันตรายอาจรบกวนประสิทธิภาพหรือการทำงานของอุปกรณ์เมื่อได้รับการส่งข้อมูลเตือนภัยทางมือถือ (CB) ในกรณีฉุกเฉิน"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"จัดการสายที่สนทนา"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"อนุญาตแอปเพื่อดูรายละเอียดเกี่ยวกับสายที่สนทนาอยู่บนโทรศัพท์และเพื่อควบคุมสายสนทนาเหล่านี้"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"อ่านข้อความที่ได้รับจากสถานีมือถือ"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"อนุญาตให้แอปอ่านข้อความจากสถานีมือถือที่อุปกรณ์ได้รับ การแจ้งเตือนทางมือถือมีให้บริการในบางพื้นที่ โดยจะแจ้งเตือนคุณเกี่ยวกับสถานการณ์ฉุกเฉิน แอปที่เป็นอันตรายอาจเข้าแทรกแซงการทำงานของอุปกรณ์เมื่อได้รับข้อความแจ้งเตือนฉุกเฉิน"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"อ่านฟีดข้อมูลที่สมัครไว้"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 25422a5..cf38312 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Nagbibigay-daan sa app na mag-bind sa module ng cell broadcast para makapagpasa ng mga mensahe ng cell broadcast pagkatanggap sa mga ito. Inihahatid ang mga alerto ng cell broadcast sa ilang lokasyon para balaan ka tungkol sa mga emergency na sitwasyon. Posibleng makasagabal ang mga nakakahamak na app sa performance o pagpapatakbo ng iyong device kapag nakatanggap ito ng emergency na cell broadcast."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Pamahalaan ang mga kasalukuyang tawag"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Pinapayagan ang app na makita ang mga detalye tungkol sa mga kasalukuyang tawag sa iyong device at kontrolin ang mga tawag na ito."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"basahin ang mga mensahe ng cell broadcast"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Binibigyang-daan ang app na magbasa ng mga mensahe ng cell broadcast na natanggap ng iyong device. Inihahatid ang mga alerto ng cell broadcast sa ilang lokasyon upang balaan ka tungkol sa mga emergency na sitwasyon. Maaaring makaabala ang nakakahamak na apps sa performance o pagpapatakbo ng iyong device kapag nakatanggap ng emergency na cell broadcast."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"magbasa ng mga na-subscribe na feed"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 64a150c..7751f62 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Uygulamanın hücre yayını mesajları geldiğinde bunları yönlendirmek için hücre yayını modülüne bağlanmasına izin verir. Hücre yayını uyarıları bazı konumlarda acil durumlar hakkında sizi uyarmak için kullanılır. Zararlı uygulamalar acil durum hücre yayını alındığında cihazınızın performansını ve çalışmasını olumsuz etkileyebilir."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Devam eden aramaları yönetme"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Uygulamanın, cihazınızda devam eden aramalarla ilgili bilgileri görüp kontrol etmesine izin verir."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"hücre yayını mesajlarını oku"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Uygulamaya, cihazınız tarafından alınan hücre yayını mesajlarını okuma izni verir. Hücre yayını uyarıları bazı yerlerde acil durumlar konusunda sizi uyarmak için gönderilir. Kötü amaçlı uygulamalar acil hücre yayını alındığında cihazınızın performansına ya da çalışmasına engel olabilir."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"abone olunan yayınları okuma"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 81fe67f..491956c 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -372,6 +372,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Дозволяє додатку зв\'язуватися з модулем Cell Broadcast, щоб переадресувати відповідні вхідні повідомлення. У деяких місцеположеннях сповіщення Cell Broadcast надсилаються для попередження про надзвичайні ситуації. Після повідомлення Cell Broadcast шкідливі додатки можуть перешкоджати роботі вашого пристрою."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Керування поточними дзвінками"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Дає змогу додатку переглядати поточні дзвінки на пристрої та керувати ними."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"читати широкомовні повідомлення мережі"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Дозволяє програмі читати широкомовні повідомлення мережі, отримані пристроєм. Широкомовні сповіщення мережі надсилаються в деяких країнах для попередження про надзвичайні ситуації. Шкідливі програми можуть втручатися у швидкодію чи роботу пристрою під час отримання широкомовного повідомлення мережі про надзвичайну ситуацію."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"читати підписані канали"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 59461b8..c9346ea 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"سیل کی نشریاتی پیغامات کے موصول ہوتے ہی فارورڈ کرنے کے لیے ایپ کو سیل کے نشریاتی ماڈیول میں پابندی لگانے کی اجازت دیں۔ سیل کی نشریاتی الرٹس آپ کو ایمرجنسی حالات سے مطلع کرنے کیلئے کچھ مقامات میں مہیا کی جاتی ہیں۔ نقصان دہ ایپس کوئی ایمرجنسی سیل براڈ کاسٹ موصول ہونے پر آپ کے آلے کی کارکردگی یا عمل میں مداخلت کر سکتی ہیں۔"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"جاری کالز کا نظم کریں"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"اس سے ایپ کو آپ کے آلے پر جاری کالز کے بارے میں تفصیلات دیکھنے اور ان کالز کو کنٹرول کرنے کی اجازت ملتی ہے۔"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"سیل کے نشریاتی پیغامات پڑھیں"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ایپ کو آپ کے آلے کو موصولہ سیل کے نشریاتی پیغامات پڑھنے کی اجازت دیتا ہے۔ سیل کی نشریاتی الرٹس آپ کو ایمرجنسی حالات سے مطلع کرنے کیلئے کچھ مقامات میں مہیا کی جاتی ہیں۔ نقصان دہ ایپس کوئی ایمرجنسی سیل کا نشریہ موصول ہونے پر آپ کے آلے کی کارکردگی یا عمل میں خلل ڈال سکتی ہیں۔"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"سبسکرائب کردہ فیڈز پڑھیں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 9388b0f..8b52c36 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Qabul qilingan aholini ogohlantirish xabarlarini shu holicha uzatish uchun ilovani aholini ogohlantirish moduliga bogʻlash imkonini beradi. Ilovaga ayrim mamlakatlarda aholini favqulodda vaziyatlarda ogohlantirish uchun yuboriladigan tarqatma xabarlarni oʻqish uchun ruxsat beradi. Zararli dasturlar bunday xabarlar kelayotgan qurilmaning ishlashiga xalaqit qilishi mumkin."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Amaldagi chaqiruvlarni boshqarish"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Ilovaga qurilmangizdagi amaldagi chaqiruv tafsilotlarini koʻrish va uni boshqarish huquqini beradi."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"uyali tarmoq operatori xabarlarini o‘qish"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Ilovaga qurilmangiz tomonidan qabul qilingan uyali tarmoq operatori xabarlarini o‘qish uchun ruxsat beradi. Uyali tarmoq operatorining ogohlantiruvchi xabarlari ba’zi manzillarga favqulodda holatlar haqida ogohlantirish uchun jo‘natiladi. Zararli ilovalar uyali tarmoq orqali favqulodda xabar qabul qilinganda qurilmangizning ish faoliyati yoki amallariga xalaqit qilishi mumkin"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"obunalarni o‘qish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b9410c1..3149c18 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Cho phép ứng dụng liên kết với mô-đun truyền phát trên di động để chuyển tiếp tin nhắn truyền phát trên di động ngay khi nhận được. Ở một số vị trí, thông báo truyền phát trên di động sẽ được gửi nhằm cảnh báo cho bạn về các tình huống khẩn cấp. Các ứng dụng độc hại có thể ảnh hưởng đến hiệu suất hoặc hoạt động của thiết bị khi nhận được tin nhắn truyền phát trên di động lúc khẩn cấp."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Quản lý cuộc gọi đang diễn ra"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Cho phép một ứng dụng xem thông tin chi tiết về các cuộc gọi đang diễn ra trên thiết bị và kiểm soát các cuộc gọi này."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"đọc tin nhắn quảng bá"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Cho phép ứng dụng đọc tin nhắn quảng bá mà thiết bị của bạn nhận được. Tin nhắn quảng bá cảnh báo được gửi ở một số địa điểm nhằm cảnh báo cho bạn về các tình huống khẩn cấp. Các ứng dụng độc hại có thể gây ảnh hưởng đến hiệu suất hoặc hoạt động của thiết bị của bạn khi nhận được tin nhắn quảng bá khẩn cấp."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"đọc nguồn cấp dữ liệu đã đăng ký"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 488dcc6..168a50e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"允许应用绑定到小区广播模块,以便及时转发收到的小区广播消息。小区广播消息是在某些地区发送的、用于发布紧急情况警告的提醒信息。恶意应用可能会在您的设备收到紧急小区广播时干扰设备的性能或操作。"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"管理正在进行的通话"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"允许应用查看有关设备上正在进行的通话的详细信息并控制这些通话。"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"读取小区广播消息"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"允许应用读取您的设备收到的小区广播消息。小区广播消息是在某些地区发送的、用于发布紧急情况警告的提醒信息。恶意应用可能会在您收到小区紧急广播时干扰您设备的性能或操作。"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"读取订阅的供稿"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index db117c52..c6c0997 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"允許應用程式繫結至區域廣播模組,以在收到區域廣播訊息時轉寄訊息。在某些地點,系統會發出區域廣播通知,提示你有緊急狀況發生。惡意應用程式可能會在裝置收到緊急區域廣播時,干擾裝置的效能或運作。"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"管理正在進行的通話"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"允許應用程式查看裝置上正在進行的通話詳情並控制通話。"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"讀取區域廣播訊息"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"允許應用程式讀取你裝置接收的區域廣播訊息。某些地點會發出區域廣播警報,警告你發生緊急狀況。惡意應用程式可能會在裝置收到緊急區域廣播時,干擾裝置的性能或運作。"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"讀取訂閱的資訊提供"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e91dc76..3aa79c4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"允許應用程式繫結至區域廣播模組,以便轉送收到的區域廣播訊息。某些地點會發出區域廣播警示,警告你有緊急狀況發生。請注意,惡意應用程式可能會在裝置收到緊急區域廣播時,干擾裝置的效能或運作。"</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"管理進行中的通話"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"允許應用程式查看裝置上進行中通話的詳細資料,並控制這些通話。"</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"讀取區域廣播訊息"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"允許應用程式讀取你裝置收到的區域廣播訊息。某些地點會發出區域廣播警示,警告你有緊急狀況發生。請注意,惡意應用程式可能會在裝置收到緊急區域廣播時,干擾裝置的效能或運作。"</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"讀取訂閱資訊提供"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 87a25ca..c18b7d4 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -370,6 +370,10 @@
     <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Ivumela uhlelo lokusebenza ukuthi luboshezelwe kumojuli yokusakaza kweselula ukuze kudluliselwe imilayezo yokusakaza yeselula njengoba itholwa. Izexwayiso zokusakaza kweselula zilethwa kwezinye izindawo ukuze zikuxwayise ngezimo zesimo esiphuthumayo. Izinhlelo zokusebenza ezinobungozi zingaphazamisa ngokusebenza noma ukusetshenziswa kwedivayisi yakho uma ukusakaza kweselula kwesimo esiphuthumayo kwamukelwa."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Phatha amakholi aqhubekayo"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Ivumela uhlelo lokusebenza ukubona imininingwane emayelana namakholi aqhubekayo kudivayisi yakho nokulawula lamakholi."</string>
+    <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+    <skip />
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"funda imilayezo yokusakaza yeselula"</string>
     <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Ivumela uhlelo lokusebenza ukufunda imilayezo yokusakaza yeselula etholwe idivayisi yakho. Izaziso zokusakaza zeselula zilethwa kwezinye izindawo ukukuxwayisa ngezimo ezisheshayo. Izinhlelo zokusebenza ezingalungile zingaphazamisana nokusebenza noma umsebenzi wedivayisi yakho uma ukusakaza kweselula kwesimo esisheshayo kutholwa."</string>
     <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"funda izifunzo ezikhokhelwayo"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 35276bf..6884fc0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -3438,6 +3438,20 @@
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>data</code> tag, a child of the
          {@link #AndroidManifestIntentFilter intent-filter} tag, describing
+         a group matching rule consisting of one or more
+         {@link #AndroidManifestData data} tags that must all match.  This
+         tag can be specified multiple times to create multiple groups that
+         will be matched in the order they are defined. -->
+    <declare-styleable name="AndroidManifestUriRelativeFilterGroup"
+        parent="AndroidManifestIntentFilter">
+        <!-- Specify if this group is allow rule or disallow rule.  If this
+             attribute is not specified then it is assumed to be true -->
+        <attr name="allow" format="boolean"/>
+    </declare-styleable>
+
+    <!-- Attributes that can be supplied in an AndroidManifest.xml
+         <code>data</code> tag, a child of the
+         {@link #AndroidManifestIntentFilter intent-filter} tag, describing
          the types of data that match.  This tag can be specified multiple
          times to supply multiple data options, as described in the
          {@link android.content.IntentFilter} class.  Note that all such
@@ -3445,7 +3459,8 @@
          <code>&lt;data android:scheme="myscheme" android:host="me.com" /&gt;</code>
          is equivalent to <code>&lt;data android:scheme="myscheme" /&gt;
          &lt;data android:host="me.com" /&gt;</code>. -->
-    <declare-styleable name="AndroidManifestData" parent="AndroidManifestIntentFilter">
+    <declare-styleable name="AndroidManifestData"
+        parent="AndroidManifestIntentFilter AndroidManifestUriRelativeFilterGroup">
         <!-- Specify a MIME type that is handled, as per
              {@link android.content.IntentFilter#addDataType
              IntentFilter.addDataType()}.
@@ -3549,6 +3564,70 @@
              IntentFilter.addDataPath()} with
              {@link android.os.PatternMatcher#PATTERN_SUFFIX}. -->
         <attr name="pathSuffix" />
+        <!-- Specify a URI query that must exactly match, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_LITERAL}. -->
+        <attr name="query" format="string" />
+        <!-- Specify a URI query that must be a prefix to match, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_PREFIX}. -->
+        <attr name="queryPrefix" format="string" />
+        <!-- Specify a URI query that matches a simple pattern, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
+             Note that because '\' is used as an escape character when
+             reading the string from XML (before it is parsed as a pattern),
+             you will need to double-escape: for example a literal "*" would
+             be written as "\\*" and a literal "\" would be written as
+             "\\\\".  This is basically the same as what you would need to
+             write if constructing the string in Java code. -->
+        <attr name="queryPattern" format="string" />
+        <!-- Specify a URI query that matches an advanced pattern, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_ADVANCED_GLOB}.
+             Note that because '\' is used as an escape character when
+             reading the string from XML (before it is parsed as a pattern),
+             you will need to double-escape: for example a literal "*" would
+             be written as "\\*" and a literal "\" would be written as
+             "\\\\".  This is basically the same as what you would need to
+             write if constructing the string in Java code. -->
+        <attr name="queryAdvancedPattern" format="string" />
+        <!-- Specify a URI query that must be a suffix to match, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_SUFFIX}. -->
+        <attr name="querySuffix" format="string" />
+        <!-- Specify a URI fragment that must exactly match, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_LITERAL}. -->
+        <attr name="fragment" format="string" />
+        <!-- Specify a URI fragment that must be a prefix to match, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_PREFIX}. -->
+        <attr name="fragmentPrefix" format="string" />
+        <!-- Specify a URI fragment that matches a simple pattern, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
+             Note that because '\' is used as an escape character when
+             reading the string from XML (before it is parsed as a pattern),
+             you will need to double-escape: for example a literal "*" would
+             be written as "\\*" and a literal "\" would be written as
+             "\\\\".  This is basically the same as what you would need to
+             write if constructing the string in Java code. -->
+        <attr name="fragmentPattern" format="string" />
+        <!-- Specify a URI fragment that matches an advanced pattern, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_ADVANCED_GLOB}.
+             Note that because '\' is used as an escape character when
+             reading the string from XML (before it is parsed as a pattern),
+             you will need to double-escape: for example a literal "*" would
+             be written as "\\*" and a literal "\" would be written as
+             "\\\\".  This is basically the same as what you would need to
+             write if constructing the string in Java code. -->
+        <attr name="fragmentAdvancedPattern" format="string" />
+        <!-- Specify a URI fragment that must be a suffix to match, as a
+             {@link android.content.UriRelativeFilter UriRelativeFilter} with
+             {@link android.os.PatternMatcher#PATTERN_SUFFIX}. -->
+        <attr name="fragmentSuffix" format="string" />
     </declare-styleable>
 
     <!-- Attributes that can be supplied in an AndroidManifest.xml
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0d1a987..ebb0d34 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6611,7 +6611,7 @@
     </string-array>
 
     <!-- Whether or not the monitoring on the apps' background battery drain is enabled -->
-    <bool name="config_bg_current_drain_monitor_enabled">true</bool>
+    <bool name="config_bg_current_drain_monitor_enabled">false</bool>
 
     <!-- The threshold of the background current drain (in percentage) to the restricted
          standby bucket.
@@ -6908,4 +6908,7 @@
 
     <!-- Defines the minimum interval (in ms) between two input-based user-activity poke events. -->
     <integer name="config_minMillisBetweenInputUserActivityEvents">100</integer>
+
+    <!-- Name of the starting activity for DisplayCompat host. specific to automotive.-->
+    <string name="config_defaultDisplayCompatHostActivity" translatable="false"></string>
 </resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index b8fc052..830e99c 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -123,6 +123,26 @@
     <public name="featureFlag"/>
     <!-- @FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers") -->
     <public name="systemUserOnly"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="allow"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="query"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="queryPrefix"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="queryPattern"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="queryAdvancedPattern"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="querySuffix"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="fragmentPrefix"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="fragmentPattern"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="fragmentAdvancedPattern"/>
+    <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+    <public name="fragmentSuffix"/>
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01bc0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bd3a5e4..558bae7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5307,6 +5307,12 @@
     <!-- Content description of the expand button icon in the notification when expanded.-->
     <string name="expand_button_content_description_expanded">Collapse</string>
 
+    <!-- A11y announcement when a view is collapsed. -->
+    <string name="content_description_collapsed">Collapsed</string>
+
+    <!-- A11y announcement when a view is expanded. -->
+    <string name="content_description_expanded">Expanded</string>
+
     <!-- Accessibility action description on the expand button. -->
     <string name="expand_action_accessibility">toggle expansion</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3c1a42f..dc2f74b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3826,6 +3826,9 @@
   <java-symbol type="string" name="expand_button_content_description_collapsed" />
   <java-symbol type="string" name="expand_button_content_description_expanded" />
 
+  <java-symbol type="string" name="content_description_collapsed" />
+  <java-symbol type="string" name="content_description_expanded" />
+
   <!-- Colon separated list of package names that should be granted Notification Listener access -->
   <java-symbol type="string" name="config_defaultListenerAccessPackages" />
 
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 3a2e50a..9bb2499 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -34,7 +34,7 @@
          http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
 
     <!-- Arab Emirates -->
-    <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214" />
+    <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214|6253" />
 
     <!-- Albania: 5 digits, known short codes listed -->
     <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
@@ -86,7 +86,7 @@
     <shortcode country="cn" premium="1066.*" free="1065.*" />
 
     <!-- Colombia: 1-6 digits (not confirmed) -->
-    <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739|85517" />
+    <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739|85517|491289" />
 
     <!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU -->
     <shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" />
@@ -104,6 +104,12 @@
     <!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
     <shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}|4665" />
 
+    <!-- Dominican Republic: 1-6 digits (standard system default, not country specific) -->
+    <shortcode country="do" pattern="\\d{1,6}" free="912892" />
+
+    <!-- Ecuador: 1-6 digits (standard system default, not country specific) -->
+    <shortcode country="ec" pattern="\\d{1,6}" free="466453" />
+
     <!-- Estonia: short codes 3-5 digits starting with 1, plus premium 7 digit numbers starting with 90, plus EU.
          http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht -->
     <shortcode country="ee" pattern="1\\d{2,4}" premium="90\\d{5}|15330|1701[0-3]" free="116\\d{3}|95034" />
@@ -154,8 +160,8 @@
          http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
     <shortcode country="ie" pattern="\\d{5}" premium="5[3-9]\\d{3}" free="50\\d{3}|116\\d{3}" standard="5[12]\\d{3}" />
 
-    <!-- Israel: 4 digits, known premium codes listed -->
-    <shortcode country="il" pattern="\\d{4}" premium="4422|4545" />
+    <!-- Israel: 1-5 digits, known premium codes listed -->
+    <shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477|6681" />
 
     <!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
          https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
@@ -193,11 +199,14 @@
     <shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
 
     <!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
-    <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453" />
+    <shortcode country="mx" pattern="\\d{4,6}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346" />
 
     <!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
     <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" />
 
+    <!-- Namibia: 1-5 digits (standard system default, not country specific) -->
+    <shortcode country="na" pattern="\\d{1,5}" free="40005" />
+
     <!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
     <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" />
 
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/DefaultRadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/DefaultRadioTunerTest.java
index 63de759..ddf3615 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/DefaultRadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/DefaultRadioTunerTest.java
@@ -20,8 +20,6 @@
 
 import static org.junit.Assert.assertThrows;
 
-import android.graphics.Bitmap;
-
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
@@ -88,12 +86,6 @@
             return 0;
         }
 
-        @Nullable
-        @Override
-        public Bitmap getMetadataImage(int id) {
-            return null;
-        }
-
         @Override
         public boolean startBackgroundScan() {
             return false;
@@ -138,6 +130,16 @@
     }
 
     @Test
+    public void getMetadataImage_forRadioTuner_throwsException() {
+        UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
+                () -> DEFAULT_RADIO_TUNER.getMetadataImage(/* id= */ 1));
+
+        assertWithMessage("Exception for getting metadata image from default radio tuner")
+                .that(thrown).hasMessageThat()
+                .contains("Getting metadata image must be implemented in child classes");
+    }
+
+    @Test
     public void getDynamicProgramList_forRadioTuner_returnsNull() {
         assertWithMessage("Dynamic program list obtained from default radio tuner")
                 .that(DEFAULT_RADIO_TUNER.getDynamicProgramList(new ProgramList.Filter())).isNull();
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
index fddfd39..b3a0aba 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
@@ -290,13 +290,29 @@
     }
 
     @Test
-    public void getBitmapId_withIllegalKey() {
+    public void getBitmapId_withIllegalKey_fails() {
         String illegalKey = RadioMetadata.METADATA_KEY_ARTIST;
         RadioMetadata metadata = mBuilder.putInt(RadioMetadata.METADATA_KEY_ART, INT_KEY_VALUE)
                 .build();
 
-        mExpect.withMessage("Bitmap id value with non-bitmap-id-type key %s", illegalKey)
-                .that(metadata.getBitmapId(illegalKey)).isEqualTo(0);
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> {
+            metadata.getBitmapId(illegalKey);
+        });
+
+        mExpect.withMessage("Exception for getting string array for non-bitmap-id type key %s",
+                illegalKey).that(thrown).hasMessageThat().contains("bitmap key");
+    }
+
+    @Test
+    public void getBitmapId_withNullKey_fails() {
+        RadioMetadata metadata = mBuilder.build();
+
+        NullPointerException thrown = assertThrows(NullPointerException.class, () -> {
+            metadata.getBitmapId(/* key= */ null);
+        });
+
+        mExpect.withMessage("Exception for getting bitmap identifier with null key")
+                .that(thrown).hasMessageThat().contains("can not be null");
     }
 
     @Test
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
index 4cda26d..5aace81 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
@@ -514,6 +514,26 @@
     }
 
     @Test
+    public void getMetadataImage_withImageIdUnavailable_fails() throws Exception {
+        int nonExistImageId = 2;
+        when(mTunerMock.getImage(nonExistImageId)).thenReturn(null);
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> mRadioTuner.getMetadataImage(nonExistImageId));
+
+        assertWithMessage("Exception for getting metadata image with non-existing id")
+                .that(thrown).hasMessageThat().contains("is not available");
+    }
+
+    @Test
+    public void getMetadataImage_withInvalidId_fails() {
+        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+                () -> mRadioTuner.getMetadataImage(/* id= */ 0));
+
+        assertWithMessage("Exception for getting metadata image for id 0").that(thrown)
+                .hasMessageThat().contains("Invalid metadata image id 0");
+    }
+
+    @Test
     public void getMetadataImage_whenServiceDied_fails() throws Exception {
         when(mTunerMock.getImage(anyInt())).thenThrow(new RemoteException());
 
diff --git a/core/tests/InputMethodCoreTests/Android.bp b/core/tests/InputMethodCoreTests/Android.bp
new file mode 100644
index 0000000..ac64625
--- /dev/null
+++ b/core/tests/InputMethodCoreTests/Android.bp
@@ -0,0 +1,66 @@
+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"],
+}
+
+android_test {
+    name: "InputMethodCoreTests",
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+        "src/**/I*.aidl",
+    ],
+
+    dxflags: ["--core-library"],
+
+    static_libs: [
+        "collector-device-lib-platform",
+        "android-common",
+        "frameworks-core-util-lib",
+        "androidx.core_core",
+        "androidx.core_core-ktx",
+        "androidx.test.ext.junit",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "flag-junit",
+        "junit-params",
+        "kotlin-test",
+        "mockito-target-minus-junit4",
+        "platform-test-annotations",
+        "platform-compat-test-rules",
+        "truth",
+        "print-test-util-lib",
+        "testng",
+        "device-time-shell-utils",
+        "testables",
+        "flag-junit",
+    ],
+
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+        "framework",
+        "ext",
+        "framework-res",
+    ],
+
+    sdk_version: "core_platform",
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
+    certificate: "platform",
+
+    resource_dirs: ["res"],
+
+    data: [
+        ":com.android.cts.helpers.aosp",
+    ],
+}
diff --git a/core/tests/InputMethodCoreTests/AndroidManifest.xml b/core/tests/InputMethodCoreTests/AndroidManifest.xml
new file mode 100644
index 0000000..8d00d0f
--- /dev/null
+++ b/core/tests/InputMethodCoreTests/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?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"
+          android:installLocation="internalOnly"
+          package="com.android.frameworks.inputmethodcoretests"
+          android:sharedUserId="com.android.uid.test">
+
+    <application
+        android:supportsRtl="true"
+        android:enableOnBackInvokedCallback="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.frameworks.inputmethodcoretests"
+            android:label="InputMethod Core Tests" />
+</manifest>
diff --git a/core/tests/InputMethodCoreTests/AndroidTest.xml b/core/tests/InputMethodCoreTests/AndroidTest.xml
new file mode 100644
index 0000000..fa585d8
--- /dev/null
+++ b/core/tests/InputMethodCoreTests/AndroidTest.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+<configuration description="Runs InputMethod Core Tests.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="InputMethodCoreTests.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <!-- TODO(b/254155965): Design a mechanism to finally remove this command. -->
+        <option name="run-command" value="settings put global device_config_sync_disabled 0" />
+    </target_preparer>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceInteractionHelperInstaller" />
+
+    <option name="test-tag" value="InputMethodCoreTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.frameworks.inputmethodcoretests" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/core/tests/InputMethodCoreTests/OWNERS b/core/tests/InputMethodCoreTests/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/core/tests/InputMethodCoreTests/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/core/tests/coretests/res/xml/ime_meta.xml b/core/tests/InputMethodCoreTests/res/xml/ime_meta.xml
similarity index 100%
rename from core/tests/coretests/res/xml/ime_meta.xml
rename to core/tests/InputMethodCoreTests/res/xml/ime_meta.xml
diff --git a/core/tests/coretests/res/xml/ime_meta_inline_suggestions.xml b/core/tests/InputMethodCoreTests/res/xml/ime_meta_inline_suggestions.xml
similarity index 100%
rename from core/tests/coretests/res/xml/ime_meta_inline_suggestions.xml
rename to core/tests/InputMethodCoreTests/res/xml/ime_meta_inline_suggestions.xml
diff --git a/core/tests/coretests/res/xml/ime_meta_inline_suggestions_with_touch_exploration.xml b/core/tests/InputMethodCoreTests/res/xml/ime_meta_inline_suggestions_with_touch_exploration.xml
similarity index 100%
rename from core/tests/coretests/res/xml/ime_meta_inline_suggestions_with_touch_exploration.xml
rename to core/tests/InputMethodCoreTests/res/xml/ime_meta_inline_suggestions_with_touch_exploration.xml
diff --git a/core/tests/coretests/res/xml/ime_meta_sw_next.xml b/core/tests/InputMethodCoreTests/res/xml/ime_meta_sw_next.xml
similarity index 100%
rename from core/tests/coretests/res/xml/ime_meta_sw_next.xml
rename to core/tests/InputMethodCoreTests/res/xml/ime_meta_sw_next.xml
diff --git a/core/tests/coretests/res/xml/ime_meta_virtual_device_only.xml b/core/tests/InputMethodCoreTests/res/xml/ime_meta_virtual_device_only.xml
similarity index 100%
rename from core/tests/coretests/res/xml/ime_meta_virtual_device_only.xml
rename to core/tests/InputMethodCoreTests/res/xml/ime_meta_virtual_device_only.xml
diff --git a/core/tests/coretests/res/xml/ime_meta_vr_only.xml b/core/tests/InputMethodCoreTests/res/xml/ime_meta_vr_only.xml
similarity index 100%
rename from core/tests/coretests/res/xml/ime_meta_vr_only.xml
rename to core/tests/InputMethodCoreTests/res/xml/ime_meta_vr_only.xml
diff --git a/core/tests/coretests/src/android/view/inputmethod/BaseInputConnectionTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/BaseInputConnectionTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/BaseInputConnectionTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/BaseInputConnectionTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/CursorAnchorInfoTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/CursorAnchorInfoTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/DeleteRangeGestureTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/DeleteRangeGestureTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/DeleteRangeGestureTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/DeleteRangeGestureTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodInfoTest.java
similarity index 98%
rename from core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodInfoTest.java
index 909af7b..a3f537e 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -32,7 +32,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.frameworks.coretests.R;
+import com.android.frameworks.inputmethodcoretests.R;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodManagerTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodManagerTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodSubtypeTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodSubtypeTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/InsertGestureTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InsertGestureTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/InsertGestureTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/InsertGestureTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InsertModeGestureTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/InsertModeGestureTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/ParcelableHandwritingGestureTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/ParcelableHandwritingGestureTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/ParcelableHandwritingGestureTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/ParcelableHandwritingGestureTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/SelectGestureTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/SelectGestureTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/SelectGestureTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/SelectGestureTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/SelectRangeGestureTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/SelectRangeGestureTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/SelectRangeGestureTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/SelectRangeGestureTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/SparseRectFArrayTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/SparseRectFArrayTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/SurroundingTextTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/SurroundingTextTest.java
diff --git a/core/tests/coretests/src/android/view/inputmethod/TextAppearanceInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/TextAppearanceInfoTest.java
similarity index 100%
rename from core/tests/coretests/src/android/view/inputmethod/TextAppearanceInfoTest.java
rename to core/tests/InputMethodCoreTests/src/android/view/inputmethod/TextAppearanceInfoTest.java
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt b/core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt
rename to core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputConnectionWrapperTest.java b/core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputConnectionWrapperTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/inputmethod/InputConnectionWrapperTest.java
rename to core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputConnectionWrapperTest.java
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java b/core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
rename to core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeHandleTest.java b/core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputMethodSubtypeHandleTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeHandleTest.java
rename to core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputMethodSubtypeHandleTest.java
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java b/core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
rename to core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
index e32a57b..a2a5433 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -145,7 +145,6 @@
     fun unnecessaryFontScalesReturnsNull() {
         assertThat(FontScaleConverterFactory.forScale(0F)).isNull()
         assertThat(FontScaleConverterFactory.forScale(1F)).isNull()
-        assertThat(FontScaleConverterFactory.forScale(1.1F)).isNull()
         assertThat(FontScaleConverterFactory.forScale(0.85F)).isNull()
     }
 
@@ -176,7 +175,7 @@
         assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(-1f)).isFalse()
         assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(0.85f)).isFalse()
         assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.02f)).isFalse()
-        assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.10f)).isFalse()
+        assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.10f)).isTrue()
         assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.15f)).isTrue()
         assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.1499999f))
                 .isTrue()
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index e7b5dff6..93c2e0e 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -20,6 +20,7 @@
 
 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;
 
@@ -121,6 +122,14 @@
     }
 
     @Test
+    public void testEmpty() throws Exception {
+        assertNotNull(Bundle.EMPTY);
+        assertEquals(0, Bundle.EMPTY.size());
+
+        new Bundle(Bundle.EMPTY);
+    }
+
+    @Test
     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
     public void testCreateFromParcel() throws Exception {
         boolean withFd;
diff --git a/core/tests/coretests/src/android/os/TestLooperManagerTest.java b/core/tests/coretests/src/android/os/TestLooperManagerTest.java
new file mode 100644
index 0000000..5959444
--- /dev/null
+++ b/core/tests/coretests/src/android/os/TestLooperManagerTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.os;
+
+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.assertTrue;
+
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class TestLooperManagerTest {
+    private static final String TAG = "TestLooperManagerTest";
+
+    @Rule
+    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+            .setProvideMainThread(true)
+            .build();
+
+    @Test
+    public void testMainThread() throws Exception {
+        doTest(Looper.getMainLooper());
+    }
+
+    @Test
+    public void testCustomThread() throws Exception {
+        final HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        doTest(thread.getLooper());
+    }
+
+    private void doTest(Looper looper) throws Exception {
+        final TestLooperManager tlm =
+                InstrumentationRegistry.getInstrumentation().acquireLooperManager(looper);
+
+        final Handler handler = new Handler(looper);
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        assertFalse(tlm.hasMessages(handler, null, 42));
+
+        handler.sendEmptyMessage(42);
+        handler.post(() -> {
+            latch.countDown();
+        });
+        assertTrue(tlm.hasMessages(handler, null, 42));
+        assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
+
+        final Message first = tlm.next();
+        assertEquals(42, first.what);
+        assertNull(first.callback);
+        tlm.execute(first);
+        assertFalse(tlm.hasMessages(handler, null, 42));
+        assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
+        tlm.recycle(first);
+
+        final Message second = tlm.next();
+        assertNotNull(second.callback);
+        tlm.execute(second);
+        assertFalse(tlm.hasMessages(handler, null, 42));
+        assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
+        tlm.recycle(second);
+
+        tlm.release();
+    }
+}
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index a709d7b..52ff0d4 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -20,6 +20,7 @@
 import static android.window.OnBackInvokedDispatcher.PRIORITY_OVERLAY;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.atLeast;
@@ -358,7 +359,7 @@
     }
 
     @Test
-    public void onDetachFromWindow_cancelCallbackAndIgnoreOnBackInvoked() throws RemoteException {
+    public void onDetachFromWindow_cancelsBackAnimation() throws RemoteException {
         mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
 
         OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo();
@@ -368,13 +369,12 @@
         waitForIdle();
         verify(mCallback1).onBackStarted(any(BackEvent.class));
 
-        // This should trigger mCallback1.onBackCancelled()
+        // This should trigger mCallback1.onBackCancelled() and unset the callback in WM
         mDispatcher.detachFromWindow();
-        // This should be ignored by mCallback1
-        callbackInfo.getCallback().onBackInvoked();
 
+        OnBackInvokedCallbackInfo callbackInfo1 = assertSetCallbackInfo();
+        assertNull(callbackInfo1);
         waitForIdle();
-        verify(mCallback1, never()).onBackInvoked();
         verify(mCallback1).onBackCancelled();
     }
 }
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 75b0d4a..145aa60d 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -21,7 +21,6 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
 import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
 
 import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
@@ -83,6 +82,7 @@
 
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.util.test.FakeSettingsProvider;
 
 import org.junit.AfterClass;
@@ -726,14 +726,14 @@
 
     private void configureNoShortcutService() throws Exception {
         when(mAccessibilityManagerService
-                .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+                .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE))
                 .thenReturn(Collections.emptyList());
         Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
     }
 
     private void configureValidShortcutService() throws Exception {
         when(mAccessibilityManagerService
-                .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+                .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE))
                 .thenReturn(Collections.singletonList(SERVICE_NAME_STRING));
         Settings.Secure.putString(
                 mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING);
@@ -744,7 +744,7 @@
                 (ComponentName) AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
                         .keySet().toArray()[0];
         when(mAccessibilityManagerService
-                .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+                .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE))
                 .thenReturn(Collections.singletonList(featureComponentName.flattenToString()));
         Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
                 featureComponentName.flattenToString());
@@ -806,7 +806,7 @@
 
     private void configureDefaultAccessibilityService() throws Exception {
         when(mAccessibilityManagerService
-                .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+                .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE))
                 .thenReturn(Collections.singletonList(SERVICE_NAME_STRING));
 
         when(mResources.getString(R.string.config_defaultAccessibilityService)).thenReturn(
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 69b6a9b7a..2ea044c 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
@@ -39,6 +39,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.accessibility.TestUtils;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.util.test.FakeSettingsProviderRule;
 
@@ -99,7 +100,7 @@
 
         mSut = new InvisibleToggleAccessibilityServiceTarget(
                 mContextSpy,
-                AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY, accessibilityServiceInfo);
+                ShortcutConstants.UserShortcutType.HARDWARE, accessibilityServiceInfo);
     }
 
     @Test
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2de305f..2873428 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -450,7 +450,7 @@
         <!-- Permissions required for CTS test - android.server.biometrics -->
         <permission name="android.permission.USE_BIOMETRIC" />
         <permission name="android.permission.TEST_BIOMETRIC" />
-        <permission name="android.permission.MANAGE_BIOMETRIC_DIALOG" />
+        <permission name="android.permission.SET_BIOMETRIC_DIALOG_LOGO" />
         <permission name="android.permission.USE_BACKGROUND_FACE_AUTHENTICATION" />
         <!-- Permissions required for CTS test - CtsContactsProviderTestCases -->
         <permission name="android.contacts.permission.MANAGE_SIM_ACCOUNTS" />
@@ -642,5 +642,6 @@
 
    <privapp-permissions package="com.android.devicediagnostics">
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+        <permission name="android.permission.BATTERY_STATS"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/fonts/font_fallback.xml b/data/fonts/font_fallback.xml
index 02e032b..1bd182f 100644
--- a/data/fonts/font_fallback.xml
+++ b/data/fonts/font_fallback.xml
@@ -730,6 +730,16 @@
               postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
         </font>
     </family>
+    <family lang="ja">
+        <font weight="400" style="normal">
+            NotoSerifHentaigana-EL.ttf
+            <axis tag="wght" stylevalue="400"/>
+        </font>
+        <font weight="700" style="normal">
+            NotoSerifHentaigana-EL.ttf
+          <axis tag="wght" stylevalue="700"/>
+        </font>
+    </family>
     <family lang="ko">
         <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
             NotoSansCJK-Regular.ttc
diff --git a/data/fonts/font_fallback_cjkvf.xml b/data/fonts/font_fallback_cjkvf.xml
index 70474ba..75bc74e 100644
--- a/data/fonts/font_fallback_cjkvf.xml
+++ b/data/fonts/font_fallback_cjkvf.xml
@@ -829,6 +829,16 @@
               postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
         </font>
     </family>
+    <family lang="ja">
+        <font weight="400" style="normal">
+            NotoSerifHentaigana-EL.ttf
+            <axis tag="wght" stylevalue="400"/>
+        </font>
+        <font weight="700" style="normal">
+            NotoSerifHentaigana-EL.ttf
+            <axis tag="wght" stylevalue="700"/>
+        </font>
+    </family>
     <family lang="ko">
         <font weight="100" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
             NotoSansCJK-Regular.ttc
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 9320c14..b23f005 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -1432,6 +1432,16 @@
               postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
         </font>
     </family>
+    <family lang="ja">
+        <font weight="400" style="normal">
+            NotoSerifHentaigana-EL.ttf
+            <axis tag="wght" stylevalue="400"/>
+        </font>
+        <font weight="700" style="normal">
+            NotoSerifHentaigana-EL.ttf
+            <axis tag="wght" stylevalue="700"/>
+        </font>
+    </family>
     <family lang="ko">
         <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
             NotoSansCJK-Regular.ttc
diff --git a/data/fonts/fonts_cjkvf.xml b/data/fonts/fonts_cjkvf.xml
index 8d91edd..1ab71ae 100644
--- a/data/fonts/fonts_cjkvf.xml
+++ b/data/fonts/fonts_cjkvf.xml
@@ -1531,6 +1531,16 @@
               postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
         </font>
     </family>
+    <family lang="ja">
+        <font weight="400" style="normal">
+            NotoSerifHentaigana-EL.ttf
+            <axis tag="wght" stylevalue="400"/>
+        </font>
+        <font weight="700" style="normal">
+            NotoSerifHentaigana-EL.ttf
+            <axis tag="wght" stylevalue="700"/>
+        </font>
+    </family>
     <family lang="ko">
         <font weight="100" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
             NotoSansCJK-Regular.ttc
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index b21bf11..7d55928 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -176,6 +176,9 @@
      * - If at least one locale in the locale list contains Japanese script, this option is
      * equivalent to {@link #LINE_BREAK_STYLE_STRICT}.
      * - Otherwise, this option is equivalent to {@link #LINE_BREAK_STYLE_NONE}.
+     *
+     * <p>
+     * Note: future versions may have special line breaking style rules for other locales.
      */
     @FlaggedApi(FLAG_WORD_STYLE_AUTO)
     public static final int LINE_BREAK_STYLE_AUTO = 5;
@@ -249,6 +252,9 @@
      * option is equivalent to {@link #LINE_BREAK_WORD_STYLE_PHRASE} if the result of its line
      * count is less than 5 lines.
      * - Otherwise, this option is equivalent to {@link #LINE_BREAK_WORD_STYLE_NONE}.
+     *
+     * <p>
+     * Note: future versions may have special line breaking word style rules for other locales.
      */
     @FlaggedApi(FLAG_WORD_STYLE_AUTO)
     public static final int LINE_BREAK_WORD_STYLE_AUTO = 2;
diff --git a/keystore/java/android/security/AndroidProtectedConfirmation.java b/keystore/java/android/security/AndroidProtectedConfirmation.java
index dfe485a..268e0a5 100644
--- a/keystore/java/android/security/AndroidProtectedConfirmation.java
+++ b/keystore/java/android/security/AndroidProtectedConfirmation.java
@@ -59,6 +59,10 @@
 
     /**
      * Requests keystore call into the confirmationui HAL to display a prompt.
+     * @deprecated Android Protected Confirmation had a low adoption rate among Android device
+     *             makers and developers alike. Given the lack of devices supporting the
+     *             feature, it is deprecated. Developers can use auth-bound Keystore keys
+     *             as a partial replacement.
      *
      * @param listener the binder to use for callbacks.
      * @param promptText the prompt to display.
@@ -68,6 +72,7 @@
      * @return one of the {@code CONFIRMATIONUI_*} constants, for
      * example {@code KeyStore.CONFIRMATIONUI_OK}.
      */
+    @Deprecated
     public int presentConfirmationPrompt(IConfirmationCallback listener, String promptText,
                                          byte[] extraData, String locale, int uiOptionsAsFlags) {
         try {
@@ -84,11 +89,16 @@
 
     /**
      * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
+     * @deprecated Android Protected Confirmation had a low adoption rate among Android device
+     *             makers and developers alike. Given the lack of devices supporting the
+     *             feature, it is deprecated. Developers can use auth-bound Keystore keys
+     *             as a partial replacement.
      *
      * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
      * @return one of the {@code CONFIRMATIONUI_*} constants, for
      * example {@code KeyStore.CONFIRMATIONUI_OK}.
      */
+    @Deprecated
     public int cancelConfirmationPrompt(IConfirmationCallback listener) {
         try {
             getService().cancelPrompt(listener);
@@ -103,9 +113,14 @@
 
     /**
      * Requests keystore to check if the confirmationui HAL is available.
+     * @deprecated Android Protected Confirmation had a low adoption rate among Android device
+     *             makers and developers alike. Given the lack of devices supporting the
+     *             feature, it is deprecated. Developers can use auth-bound Keystore keys
+     *             as a partial replacement.
      *
      * @return whether the confirmationUI HAL is available.
      */
+    @Deprecated
     public boolean isConfirmationPromptSupported() {
         try {
             return getService().isSupported();
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 9c05a3a..83ddfc5 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -109,13 +109,29 @@
         }
     }
 
+    // For curve 25519, KeyMint uses the KM_ALGORITHM_EC constant, but in the Java layer we need
+    // to distinguish between Curve 25519 and other EC algorithms, so we use a different constant
+    // with a value that is outside the range of the enum used for KeyMint algorithms.
+    private static final int ALGORITHM_XDH = KeymasterDefs.KM_ALGORITHM_EC + 1200;
+    private static final int ALGORITHM_ED25519 = ALGORITHM_XDH + 1;
+
     /**
-     * XDH represents Curve 25519 providers.
+     * XDH represents Curve 25519 agreement key provider.
      */
     public static class XDH extends AndroidKeyStoreKeyPairGeneratorSpi {
         // XDH is treated as EC.
         public XDH() {
-            super(KeymasterDefs.KM_ALGORITHM_EC);
+            super(ALGORITHM_XDH);
+        }
+    }
+
+    /**
+     * ED25519 represents Curve 25519 signing key provider.
+     */
+    public static class ED25519 extends AndroidKeyStoreKeyPairGeneratorSpi {
+        // ED25519 is treated as EC.
+        public ED25519() {
+            super(ALGORITHM_ED25519);
         }
     }
 
@@ -241,7 +257,9 @@
 
             KeyGenParameterSpec spec;
             boolean encryptionAtRestRequired = false;
-            int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
+            int keymasterAlgorithm = (mOriginalKeymasterAlgorithm == ALGORITHM_XDH
+                    || mOriginalKeymasterAlgorithm == ALGORITHM_ED25519)
+                    ? KeymasterDefs.KM_ALGORITHM_EC : mOriginalKeymasterAlgorithm;
             if (params instanceof KeyGenParameterSpec) {
                 spec = (KeyGenParameterSpec) params;
             } else if (params instanceof KeyPairGeneratorSpec) {
@@ -610,6 +628,15 @@
                 if (algSpecificSpec instanceof ECGenParameterSpec) {
                     ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
                     mEcCurveName = ecSpec.getName();
+                    if (mOriginalKeymasterAlgorithm == ALGORITHM_XDH
+                            && !mEcCurveName.equalsIgnoreCase("x25519")) {
+                        throw new InvalidAlgorithmParameterException("XDH algorithm only supports"
+                                + " x25519 curve.");
+                    } else if (mOriginalKeymasterAlgorithm == ALGORITHM_ED25519
+                            && !mEcCurveName.equalsIgnoreCase("ed25519")) {
+                        throw new InvalidAlgorithmParameterException("Ed25519 algorithm only"
+                                + " supports ed25519 curve.");
+                    }
                     final Integer ecSpecKeySizeBits = SUPPORTED_EC_CURVE_NAME_TO_SIZE.get(
                             mEcCurveName.toLowerCase(Locale.US));
                     if (ecSpecKeySizeBits == null) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 11278e8..d204f13 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -86,11 +86,14 @@
         put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
         put("KeyPairGenerator.RSA", PACKAGE_NAME +  ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
         put("KeyPairGenerator.XDH", PACKAGE_NAME +  ".AndroidKeyStoreKeyPairGeneratorSpi$XDH");
+        put("KeyPairGenerator.ED25519", PACKAGE_NAME
+                +  ".AndroidKeyStoreKeyPairGeneratorSpi$ED25519");
 
         // java.security.KeyFactory
         putKeyFactoryImpl("EC");
         putKeyFactoryImpl("RSA");
         putKeyFactoryImpl("XDH");
+        putKeyFactoryImpl("ED25519");
 
         // javax.crypto.KeyGenerator
         put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index 9b84a48..6e704f3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -356,7 +356,7 @@
             }
             if (featureRect.left == 0
                     && featureRect.width() != windowConfiguration.getBounds().width()) {
-                Log.wtf(TAG, "Horizontal FoldingFeature must have full width."
+                Log.w(TAG, "Horizontal FoldingFeature must have full width."
                         + " BaseFeatureRect: " + baseFeature.getRect()
                         + ", FeatureRect: " + featureRect
                         + ", WindowConfiguration: " + windowConfiguration);
@@ -364,7 +364,7 @@
             }
             if (featureRect.top == 0
                     && featureRect.height() != windowConfiguration.getBounds().height()) {
-                Log.wtf(TAG, "Vertical FoldingFeature must have full height."
+                Log.w(TAG, "Vertical FoldingFeature must have full height."
                         + " BaseFeatureRect: " + baseFeature.getRect()
                         + ", FeatureRect: " + featureRect
                         + ", WindowConfiguration: " + windowConfiguration);
diff --git a/libs/WindowManager/Shell/multivalentTests/OWNERS b/libs/WindowManager/Shell/multivalentTests/OWNERS
new file mode 100644
index 0000000..24c1a3a
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/OWNERS
@@ -0,0 +1,4 @@
+atsjenk@google.com
+liranb@google.com
+madym@google.com
+
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt
index 4c76168..398fd55 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt
@@ -22,7 +22,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.wm.shell.taskview.TaskView
-import com.android.wm.shell.taskview.TaskViewTaskController
 
 import com.google.common.truth.Truth.assertThat
 import com.google.common.util.concurrent.MoreExecutors.directExecutor
@@ -30,6 +29,8 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -37,10 +38,11 @@
 
     private lateinit var bubbleTaskView: BubbleTaskView
     private val context = ApplicationProvider.getApplicationContext<Context>()
+    private lateinit var taskView: TaskView
 
     @Before
     fun setUp() {
-        val taskView = TaskView(context, mock<TaskViewTaskController>())
+        taskView = mock()
         bubbleTaskView = BubbleTaskView(taskView, directExecutor())
     }
 
@@ -72,4 +74,19 @@
         assertThat(actualTaskId).isEqualTo(123)
         assertThat(actualComponentName).isEqualTo(componentName)
     }
+
+    @Test
+    fun cleanup_invalidTaskId_doesNotRemoveTask() {
+        bubbleTaskView.cleanup()
+        verify(taskView, never()).removeTask()
+    }
+
+    @Test
+    fun cleanup_validTaskId_removesTask() {
+        val componentName = ComponentName(context, "TestClass")
+        bubbleTaskView.listener.onTaskCreated(123, componentName)
+
+        bubbleTaskView.cleanup()
+        verify(taskView).removeTask()
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 87c8f52..f32f030 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -51,6 +51,8 @@
 import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
 import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
 import com.android.wm.shell.common.bubbles.BubbleInfo;
+import com.android.wm.shell.taskview.TaskView;
+import com.android.wm.shell.taskview.TaskViewTaskController;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -105,6 +107,8 @@
     private BubbleExpandedView mExpandedView;
     @Nullable
     private BubbleBarExpandedView mBubbleBarExpandedView;
+    @Nullable
+    private BubbleTaskView mBubbleTaskView;
 
     private BubbleViewInfoTask mInflationTask;
     private boolean mInflateSynchronously;
@@ -394,6 +398,21 @@
     }
 
     /**
+     * Returns the existing {@link #mBubbleTaskView} if it's not {@code null}. Otherwise a new
+     * instance of {@link BubbleTaskView} is created.
+     */
+    public BubbleTaskView getOrCreateBubbleTaskView(Context context, BubbleController controller) {
+        if (mBubbleTaskView == null) {
+            TaskViewTaskController taskViewTaskController = new TaskViewTaskController(context,
+                    controller.getTaskOrganizer(),
+                    controller.getTaskViewTransitions(), controller.getSyncTransactionQueue());
+            TaskView taskView = new TaskView(context, taskViewTaskController);
+            mBubbleTaskView = new BubbleTaskView(taskView, controller.getMainExecutor());
+        }
+        return mBubbleTaskView;
+    }
+
+    /**
      * @return the ShortcutInfo id if it exists, or the metadata shortcut id otherwise.
      */
     String getShortcutId() {
@@ -415,6 +434,10 @@
      * the bubble.
      */
     void cleanupExpandedView() {
+        cleanupExpandedView(true);
+    }
+
+    private void cleanupExpandedView(boolean cleanupTaskView) {
         if (mExpandedView != null) {
             mExpandedView.cleanUpExpandedState();
             mExpandedView = null;
@@ -423,17 +446,37 @@
             mBubbleBarExpandedView.cleanUpExpandedState();
             mBubbleBarExpandedView = null;
         }
+        if (cleanupTaskView) {
+            cleanupTaskView();
+        }
         if (mIntent != null) {
             mIntent.unregisterCancelListener(mIntentCancelListener);
         }
         mIntentActive = false;
     }
 
+    private void cleanupTaskView() {
+        if (mBubbleTaskView != null) {
+            mBubbleTaskView.cleanup();
+            mBubbleTaskView = null;
+        }
+    }
+
     /**
      * Call when all the views should be removed/cleaned up.
      */
     void cleanupViews() {
-        cleanupExpandedView();
+        cleanupViews(true);
+    }
+
+    /**
+     * Call when all the views should be removed/cleaned up.
+     *
+     * <p>If we're switching between bar and floating modes, pass {@code false} on
+     * {@code cleanupTaskView} to avoid recreating it in the new mode.
+     */
+    void cleanupViews(boolean cleanupTaskView) {
+        cleanupExpandedView(cleanupTaskView);
         mIconView = null;
     }
 
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 a5f7880..945b8ac 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
@@ -1366,8 +1366,9 @@
             mStackView.resetOverflowView();
             mStackView.removeAllViews();
         }
-        // cleanup existing bubble views so they can be recreated later if needed.
-        mBubbleData.getBubbles().forEach(Bubble::cleanupViews);
+        // cleanup existing bubble views so they can be recreated later if needed, but retain
+        // TaskView.
+        mBubbleData.getBubbles().forEach(b -> b.cleanupViews(/* cleanupTaskView= */ false));
 
         // remove the current bubble container from window manager, null it out, and create a new
         // container based on the current mode.
@@ -1478,7 +1479,6 @@
      * <p>
      * Must be called from the main thread.
      */
-    @VisibleForTesting
     @MainThread
     public void removeBubble(String key, int reason) {
         if (mBubbleData.hasAnyBubbleWithKey(key)) {
@@ -1486,36 +1486,6 @@
         }
     }
 
-    // TODO(b/316358859): remove this method after task views are shared across modes
-    /**
-     * Removes the bubble with the given key after task removal, unless the task was removed as
-     * a result of mode switching, in which case, the bubble isn't removed because it will be
-     * re-inflated for the new mode.
-     */
-    @MainThread
-    public void removeFloatingBubbleAfterTaskRemoval(String key, int reason) {
-        // if we're floating remove the bubble. otherwise, we're here because the task was removed
-        // after switching modes. See b/316358859
-        if (!isShowingAsBubbleBar()) {
-            removeBubble(key, reason);
-        }
-    }
-
-    // TODO(b/316358859): remove this method after task views are shared across modes
-    /**
-     * Removes the bubble with the given key after task removal, unless the task was removed as
-     * a result of mode switching, in which case, the bubble isn't removed because it will be
-     * re-inflated for the new mode.
-     */
-    @MainThread
-    public void removeBarBubbleAfterTaskRemoval(String key, int reason) {
-        // if we're showing as bubble bar remove the bubble. otherwise, we're here because the task
-        // was removed after switching modes. See b/316358859
-        if (isShowingAsBubbleBar()) {
-            removeBubble(key, reason);
-        }
-    }
-
     /**
      * Removes all the bubbles.
      * <p>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 9f7d0ac..efc4d8b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -27,12 +27,10 @@
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT;
-import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
 
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -49,7 +47,6 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.ShapeDrawable;
-import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.IntProperty;
@@ -311,8 +308,7 @@
                         + " bubble=" + getBubbleKey());
             }
             if (mBubble != null) {
-                mController.removeFloatingBubbleAfterTaskRemoval(
-                        mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+                mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
             }
             if (mTaskView != null) {
                 // Release the surface
@@ -1105,32 +1101,11 @@
         return ((LinearLayout.LayoutParams) mManageButton.getLayoutParams()).getMarginStart();
     }
 
-    /**
-     * Cleans up anything related to the task. The TaskView itself is released after the task
-     * has been removed.
-     *
-     * If this view should be reused after this method is called, then
-     * {@link #initialize(BubbleController, BubbleStackView, boolean, BubbleTaskView)}
-     * must be invoked first.
-     */
+    /** Hide the task view. */
     public void cleanUpExpandedState() {
         if (DEBUG_BUBBLE_EXPANDED_VIEW) {
             Log.d(TAG, "cleanUpExpandedState: bubble=" + getBubbleKey() + " task=" + mTaskId);
         }
-        if (getTaskId() != INVALID_TASK_ID) {
-            // Ensure the task is removed from WM
-            if (ENABLE_SHELL_TRANSITIONS) {
-                if (mTaskView != null) {
-                    mTaskView.removeTask();
-                }
-            } else {
-                try {
-                    ActivityTaskManager.getService().removeTask(getTaskId());
-                } catch (RemoteException e) {
-                    Log.w(TAG, e.getMessage());
-                }
-            }
-        }
         if (mTaskView != null) {
             mTaskView.setVisibility(GONE);
         }
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 2fcd133..65f8e48 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
@@ -16,10 +16,14 @@
 
 package com.android.wm.shell.bubbles
 
+import android.app.ActivityTaskManager
 import android.app.ActivityTaskManager.INVALID_TASK_ID
 import android.content.ComponentName
+import android.os.RemoteException
+import android.util.Log
 import androidx.annotation.VisibleForTesting
 import com.android.wm.shell.taskview.TaskView
+import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS
 import java.util.concurrent.Executor
 
 /**
@@ -78,4 +82,28 @@
     init {
         taskView.setListener(executor, listener)
     }
+
+    /**
+     * Removes the [TaskView] from window manager.
+     *
+     * This should be called after all other cleanup animations have finished.
+     */
+    fun cleanup() {
+        if (taskId != INVALID_TASK_ID) {
+            // Ensure the task is removed from WM
+            if (ENABLE_SHELL_TRANSITIONS) {
+                taskView.removeTask()
+            } else {
+                try {
+                    ActivityTaskManager.getService().removeTask(taskId)
+                } catch (e: RemoteException) {
+                    Log.w(TAG, e.message ?: "")
+                }
+            }
+        }
+    }
+
+    private companion object {
+        const val TAG = "BubbleTaskView"
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index 5855a81..5fc67d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -29,7 +29,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Rect;
-import android.os.RemoteException;
 import android.util.Log;
 import android.view.View;
 
@@ -183,8 +182,11 @@
                         + " bubble=" + getBubbleKey());
             }
             if (mBubble != null) {
-                mController.removeBarBubbleAfterTaskRemoval(
-                        mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+                mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+            }
+            if (mTaskView != null) {
+                mTaskView.release();
+                mTaskView = null;
             }
         }
 
@@ -228,24 +230,6 @@
         return false;
     }
 
-    /** Cleans up anything related to the task and {@code TaskView}. */
-    public void cleanUpTaskView() {
-        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
-            Log.d(TAG, "cleanUpExpandedState: bubble=" + getBubbleKey() + " task=" + mTaskId);
-        }
-        if (mTaskId != INVALID_TASK_ID) {
-            try {
-                ActivityTaskManager.getService().removeTask(mTaskId);
-            } catch (RemoteException e) {
-                Log.w(TAG, e.getMessage());
-            }
-        }
-        if (mTaskView != null) {
-            mTaskView.release();
-            mTaskView = null;
-        }
-    }
-
     /** Returns the bubble key associated with this view. */
     @Nullable
     public String getBubbleKey() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index c3d899e..5fc10a9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -46,8 +46,6 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
 import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
-import com.android.wm.shell.taskview.TaskView;
-import com.android.wm.shell.taskview.TaskViewTaskController;
 
 import java.lang.ref.WeakReference;
 import java.util.Objects;
@@ -175,7 +173,7 @@
             BubbleViewInfo info = new BubbleViewInfo();
 
             if (!skipInflation && !b.isInflated()) {
-                BubbleTaskView bubbleTaskView = createBubbleTaskView(c, controller);
+                BubbleTaskView bubbleTaskView = b.getOrCreateBubbleTaskView(c, controller);
                 LayoutInflater inflater = LayoutInflater.from(c);
                 info.bubbleBarExpandedView = (BubbleBarExpandedView) inflater.inflate(
                         R.layout.bubble_bar_expanded_view, layerView, false /* attachToRoot */);
@@ -205,7 +203,7 @@
                         R.layout.bubble_view, stackView, false /* attachToRoot */);
                 info.imageView.initialize(controller.getPositioner());
 
-                BubbleTaskView bubbleTaskView = createBubbleTaskView(c, controller);
+                BubbleTaskView bubbleTaskView = b.getOrCreateBubbleTaskView(c, controller);
                 info.expandedView = (BubbleExpandedView) inflater.inflate(
                         R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
                 info.expandedView.initialize(
@@ -225,15 +223,6 @@
             }
             return info;
         }
-
-        private static BubbleTaskView createBubbleTaskView(
-                Context context, BubbleController controller) {
-            TaskViewTaskController taskViewTaskController = new TaskViewTaskController(context,
-                    controller.getTaskOrganizer(),
-                    controller.getTaskViewTransitions(), controller.getSyncTransactionQueue());
-            TaskView taskView = new TaskView(context, taskViewTaskController);
-            return new BubbleTaskView(taskView, controller.getMainExecutor());
-        }
     }
 
     /**
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 3cf23ac..00d683e 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
@@ -272,7 +272,6 @@
             if (mTaskView != null) {
                 removeView(mTaskView);
             }
-            mBubbleTaskViewHelper.cleanUpTaskView();
         }
         mMenuViewController.hideMenu(false /* animated */);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDoubleTapHelper.java
similarity index 92%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDoubleTapHelper.java
index 1b1ebc3..4cbb78f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDoubleTapHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 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,14 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.pip.phone;
+package com.android.wm.shell.common.pip;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.graphics.Rect;
 
-import com.android.wm.shell.common.pip.PipBoundsState;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -50,9 +48,9 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface PipSizeSpec {}
 
-    static final int SIZE_SPEC_DEFAULT = 0;
-    static final int SIZE_SPEC_MAX = 1;
-    static final int SIZE_SPEC_CUSTOM = 2;
+    public static final int SIZE_SPEC_DEFAULT = 0;
+    public static final int SIZE_SPEC_MAX = 1;
+    public static final int SIZE_SPEC_CUSTOM = 2;
 
     /**
      * Returns MAX or DEFAULT {@link PipSizeSpec} to toggle to/from.
@@ -84,7 +82,7 @@
      * @return pip screen size to switch to
      */
     @PipSizeSpec
-    static int nextSizeSpec(@NonNull PipBoundsState mPipBoundsState,
+    public static int nextSizeSpec(@NonNull PipBoundsState mPipBoundsState,
             @NonNull Rect userResizeBounds) {
         // is pip screen at its maximum
         boolean isScreenMax = mPipBoundsState.getBounds().width()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMenuController.java
similarity index 88%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMenuController.java
index 0775f52..2f1189a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMenuController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 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.wm.shell.pip;
+package com.android.wm.shell.common.pip;
 
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
@@ -33,12 +33,13 @@
 import android.view.WindowManager;
 
 import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
 
 import java.util.List;
 
 /**
- *  Interface to allow {@link com.android.wm.shell.pip.PipTaskOrganizer} to call into
- *  PiP menu when certain events happen (task appear/vanish, PiP move, etc.)
+ *  Interface to interact with PiP menu when certain events happen
+ *  (task appear/vanish, PiP move, etc.).
  */
 public interface PipMenuController {
 
@@ -52,15 +53,15 @@
     float ALPHA_NO_CHANGE = -1f;
 
     /**
-     * Called when
-     * {@link PipTaskOrganizer#onTaskAppeared(RunningTaskInfo, SurfaceControl)}
+     * Called when out implementation of
+     * {@link ShellTaskOrganizer.TaskListener#onTaskAppeared(RunningTaskInfo, SurfaceControl)}
      * is called.
      */
     void attach(SurfaceControl leash);
 
     /**
-     * Called when
-     * {@link PipTaskOrganizer#onTaskVanished(RunningTaskInfo)} is called.
+     * Called when our implementation of
+     * {@link ShellTaskOrganizer.TaskListener#onTaskVanished(RunningTaskInfo)} is called.
      */
     void detach();
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 2dd2743..dbf7186 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -80,8 +80,7 @@
             Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartButtonClicked) {
         super(context, taskInfo, syncQueue, taskListener, displayLayout);
         mCallback = callback;
-        mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat
-                && shouldShowSizeCompatRestartButton(taskInfo);
+        mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat;
         mCameraCompatControlState = taskInfo.appCompatTaskInfo.cameraCompatControlState;
         mCompatUIHintsState = compatUIHintsState;
         mCompatUIConfiguration = compatUIConfiguration;
@@ -106,7 +105,8 @@
 
     @Override
     protected boolean eligibleToShowLayout() {
-        return mHasSizeCompat || shouldShowCameraControl();
+        return (mHasSizeCompat && shouldShowSizeCompatRestartButton(getLastTaskInfo()))
+                || shouldShowCameraControl();
     }
 
     @Override
@@ -114,11 +114,6 @@
         mLayout = inflateLayout();
         mLayout.inject(this);
 
-        final TaskInfo taskInfo = getLastTaskInfo();
-        if (taskInfo != null) {
-            mHasSizeCompat = mHasSizeCompat && shouldShowSizeCompatRestartButton(taskInfo);
-        }
-
         updateVisibilityOfViews();
 
         if (mHasSizeCompat) {
@@ -139,8 +134,7 @@
             boolean canShow) {
         final boolean prevHasSizeCompat = mHasSizeCompat;
         final int prevCameraCompatControlState = mCameraCompatControlState;
-        mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat
-                && shouldShowSizeCompatRestartButton(taskInfo);
+        mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat;
         mCameraCompatControlState = taskInfo.appCompatTaskInfo.cameraCompatControlState;
 
         if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index 180498c..0564c95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -332,7 +332,7 @@
         updateSurfacePosition();
     }
 
-    @Nullable
+    @NonNull
     protected TaskInfo getLastTaskInfo() {
         return mTaskInfo;
     }
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 3b48c67..8eecf1c 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
@@ -18,18 +18,23 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.os.Handler;
 
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SystemWindows;
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.dagger.WMShellBaseModule;
 import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.pip2.phone.PhonePipMenuController;
 import com.android.wm.shell.pip2.phone.PipController;
 import com.android.wm.shell.pip2.phone.PipScheduler;
 import com.android.wm.shell.pip2.phone.PipTransition;
@@ -50,15 +55,16 @@
 public abstract class Pip2Module {
     @WMSingleton
     @Provides
-    static PipTransition providePipTransition(@NonNull ShellInit shellInit,
+    static PipTransition providePipTransition(Context context,
+            @NonNull ShellInit shellInit,
             @NonNull ShellTaskOrganizer shellTaskOrganizer,
             @NonNull Transitions transitions,
             PipBoundsState pipBoundsState,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             Optional<PipController> pipController,
             @NonNull PipScheduler pipScheduler) {
-        return new PipTransition(shellInit, shellTaskOrganizer, transitions, pipBoundsState, null,
-                pipBoundsAlgorithm, pipScheduler);
+        return new PipTransition(context, shellInit, shellTaskOrganizer, transitions,
+                pipBoundsState, null, pipBoundsAlgorithm, pipScheduler);
     }
 
     @WMSingleton
@@ -85,4 +91,16 @@
             @ShellMainThread ShellExecutor mainExecutor) {
         return new PipScheduler(context, pipBoundsState, mainExecutor);
     }
+
+    @WMSingleton
+    @Provides
+    static PhonePipMenuController providePipPhoneMenuController(Context context,
+            PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+            SystemWindows systemWindows,
+            PipUiEventLogger pipUiEventLogger,
+            @ShellMainThread ShellExecutor mainExecutor,
+            @ShellMainThread Handler mainHandler) {
+        return new PhonePipMenuController(context, pipBoundsState, pipMediaController,
+                systemWindows, pipUiEventLogger, mainExecutor, mainHandler);
+    }
 }
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 da1ca8d..6250fc5 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
@@ -17,6 +17,8 @@
 package com.android.wm.shell.desktopmode;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
 import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
 
@@ -86,7 +88,6 @@
         mTaskSurface = taskSurface;
         mRootTdaOrganizer = taskDisplayAreaOrganizer;
         mCurrentType = IndicatorType.NO_INDICATOR;
-        createView();
     }
 
     /**
@@ -127,34 +128,15 @@
         mView = new View(mContext);
         final SurfaceControl.Builder builder = new SurfaceControl.Builder();
         mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder);
-        String description;
-        switch (mCurrentType) {
-            case TO_DESKTOP_INDICATOR:
-                description = "Desktop indicator";
-                break;
-            case TO_FULLSCREEN_INDICATOR:
-                description = "Fullscreen indicator";
-                break;
-            case TO_SPLIT_LEFT_INDICATOR:
-                description = "Split Left indicator";
-                break;
-            case TO_SPLIT_RIGHT_INDICATOR:
-                description = "Split Right indicator";
-                break;
-            default:
-                description = "Invalid indicator";
-                break;
-        }
         mLeash = builder
-                .setName(description)
+                .setName("Desktop Mode Visual Indicator")
                 .setContainerLayer()
                 .build();
         t.show(mLeash);
         final WindowManager.LayoutParams lp =
-                new WindowManager.LayoutParams(screenWidth, screenHeight,
-                        WindowManager.LayoutParams.TYPE_APPLICATION,
-                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
-        lp.setTitle(description + " for Task=" + mTaskInfo.taskId);
+                new WindowManager.LayoutParams(screenWidth, screenHeight, TYPE_APPLICATION,
+                        FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
+        lp.setTitle("Desktop Mode Visual Indicator");
         lp.setTrustedOverlay();
         final WindowlessWindowManager windowManager = new WindowlessWindowManager(
                 mTaskInfo.configuration, mLeash,
@@ -201,6 +183,9 @@
      */
     private void transitionIndicator(IndicatorType newType) {
         if (mCurrentType == newType) return;
+        if (mView == null) {
+            createView();
+        }
         if (mCurrentType == IndicatorType.NO_INDICATOR) {
             fadeInIndicator(newType);
         } else if (newType == IndicatorType.NO_INDICATOR) {
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 4f5c39a..28c06a4 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
@@ -919,22 +919,27 @@
         }
         if (taskBounds.top <= transitionAreaHeight) {
             moveToFullscreenWithAnimation(taskInfo, position)
+            return
         }
         if (inputCoordinate.x <= transitionAreaWidth) {
             releaseVisualIndicator()
-            var wct = WindowContainerTransaction()
+            val wct = WindowContainerTransaction()
             addMoveToSplitChanges(wct, taskInfo)
             splitScreenController.requestEnterSplitSelect(taskInfo, wct,
                 SPLIT_POSITION_TOP_OR_LEFT, taskBounds)
+            return
         }
         if (inputCoordinate.x >= (displayController.getDisplayLayout(taskInfo.displayId)?.width()
             ?.minus(transitionAreaWidth) ?: return)) {
             releaseVisualIndicator()
-            var wct = WindowContainerTransaction()
+            val wct = WindowContainerTransaction()
             addMoveToSplitChanges(wct, taskInfo)
             splitScreenController.requestEnterSplitSelect(taskInfo, wct,
                 SPLIT_POSITION_BOTTOM_OR_RIGHT, taskBounds)
+            return
         }
+        // A freeform drag-move ended, remove the indicator immediately.
+        releaseVisualIndicator()
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index c3a82ce..731fec7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -239,7 +239,7 @@
                     show(change.leash)
                 }
             } else if (TransitionInfo.isIndependent(change, info)) {
-                // Root.
+                // Root(s).
                 when (state) {
                     is TransitionState.FromSplit -> {
                         state.splitRootChange = change
@@ -256,6 +256,9 @@
                         }
                     }
                     is TransitionState.FromFullscreen -> {
+                        // Most of the time we expect one change/task here, which should be the
+                        // same that initiated the drag and that should be layered on top of
+                        // everything.
                         if (change.taskInfo?.taskId == state.draggedTaskId) {
                             state.draggedTaskChange = change
                             val bounds = change.endAbsBounds
@@ -265,7 +268,18 @@
                                 show(change.leash)
                             }
                         } else {
-                            throw IllegalStateException("Expected root to be dragged task")
+                            // It's possible to see an additional change that isn't the dragged
+                            // task when the dragged task is translucent and so the task behind it
+                            // is included in the transition since it was visible and is now being
+                            // occluded by the Home task. Just layer it at the bottom and save it
+                            // in case we need to restore order if the drag is cancelled.
+                            state.otherRootChanges.add(change)
+                            val bounds = change.endAbsBounds
+                            startTransaction.apply {
+                                setLayer(change.leash, appLayers - i)
+                                setWindowCrop(change.leash, bounds.width(), bounds.height())
+                                show(change.leash)
+                            }
                         }
                     }
                 }
@@ -515,8 +529,18 @@
         val wct = WindowContainerTransaction()
         when (state) {
             is TransitionState.FromFullscreen -> {
+                // There may have been tasks sent behind home that are not the dragged task (like
+                // when the dragged task is translucent and that makes the task behind it visible).
+                // Restore the order of those first.
+                state.otherRootChanges.mapNotNull { it.container }.forEach { wc ->
+                    // TODO(b/322852244): investigate why even though these "other" tasks are
+                    //  reordered in front of home and behind the translucent dragged task, its
+                    //  surface is not visible on screen.
+                    wct.reorder(wc, true /* toTop */)
+                }
                 val wc = state.draggedTaskChange?.container
                         ?: error("Dragged task should be non-null before cancelling")
+                // Then the dragged task a the very top.
                 wct.reorder(wc, true /* toTop */)
             }
             is TransitionState.FromSplit -> {
@@ -574,6 +598,7 @@
                 override var draggedTaskChange: Change? = null,
                 override var cancelled: Boolean = false,
                 override var startAborted: Boolean = false,
+                var otherRootChanges: MutableList<Change> = mutableListOf()
         ) : TransitionState()
         data class FromSplit(
                 override val draggedTaskId: Int,
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 07b8f11..52a06e0 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
@@ -86,6 +86,7 @@
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.pip.phone.PipMotionHelper;
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 8e375a9..e739266 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
@@ -68,6 +68,7 @@
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
 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.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
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 04911c0..d1fd207 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
@@ -40,6 +40,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.split.SplitScreenUtils;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
@@ -47,6 +48,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Responsible supplying PiP Transitions.
@@ -116,6 +118,17 @@
     }
 
     /**
+     * Called when the Shell wants to start resizing Pip transition/animation.
+     *
+     * @param onFinishResizeCallback callback guaranteed to execute when animation ends and
+     *                               client completes any potential draws upon WM state updates.
+     */
+    public void startResizeTransition(WindowContainerTransaction wct,
+            Consumer<Rect> onFinishResizeCallback) {
+        // Default implementation does nothing.
+    }
+
+    /**
      * Called when the transition animation can't continue (eg. task is removed during
      * animation)
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 7606526..d8e8b58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -41,8 +41,8 @@
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipMediaController;
 import com.android.wm.shell.common.pip.PipMediaController.ActionListener;
+import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.pip.PipUiEventLogger;
-import com.android.wm.shell.pip.PipMenuController;
 import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 452a416..81705e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -52,6 +52,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipDoubleTapHelper;
 import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.common.pip.SizeSpecSource;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index c6803f7..843c84a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -40,7 +40,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.pip.PipMenuController;
+import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.util.List;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
index 21223c9a..cac63eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
@@ -28,10 +28,10 @@
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.pip.PipMenuController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
 import com.android.wm.shell.pip.PipTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
index 571c839..d16a692 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
@@ -25,10 +25,10 @@
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.transitTypeToString;
 
+import static com.android.wm.shell.common.pip.PipMenuController.ALPHA_NO_CHANGE;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
-import static com.android.wm.shell.pip.PipMenuController.ALPHA_NO_CHANGE;
 import static com.android.wm.shell.pip.PipTransitionState.ENTERED_PIP;
 import static com.android.wm.shell.pip.PipTransitionState.ENTERING_PIP;
 import static com.android.wm.shell.pip.PipTransitionState.EXITING_PIP;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelper.java
new file mode 100644
index 0000000..24077a3
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelper.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pip2;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.Choreographer;
+import android.view.SurfaceControl;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.transition.Transitions;
+
+/**
+ * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
+ */
+public class PipSurfaceTransactionHelper {
+    /** for {@link #scale(SurfaceControl.Transaction, SurfaceControl, Rect, Rect)} operation */
+    private final Matrix mTmpTransform = new Matrix();
+    private final float[] mTmpFloat9 = new float[9];
+    private final RectF mTmpSourceRectF = new RectF();
+    private final RectF mTmpDestinationRectF = new RectF();
+    private final Rect mTmpDestinationRect = new Rect();
+
+    private int mCornerRadius;
+    private int mShadowRadius;
+
+    public PipSurfaceTransactionHelper(Context context) {
+        onDensityOrFontScaleChanged(context);
+    }
+
+    /**
+     * Called when display size or font size of settings changed
+     *
+     * @param context the current context
+     */
+    public void onDensityOrFontScaleChanged(Context context) {
+        mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+        mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
+    }
+
+    /**
+     * Operates the alpha on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash,
+            float alpha) {
+        tx.setAlpha(leash, alpha);
+        return this;
+    }
+
+    /**
+     * Operates the crop (and position) on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,
+            Rect destinationBounds) {
+        tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
+                .setPosition(leash, destinationBounds.left, destinationBounds.top);
+        return this;
+    }
+
+    /**
+     * Operates the scale (setMatrix) on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+            Rect sourceBounds, Rect destinationBounds) {
+        mTmpDestinationRectF.set(destinationBounds);
+        return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */);
+    }
+
+    /**
+     * Operates the scale (setMatrix) on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+            Rect sourceBounds, RectF destinationBounds) {
+        return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */);
+    }
+
+    /**
+     * Operates the scale (setMatrix) on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+            Rect sourceBounds, Rect destinationBounds, float degrees) {
+        mTmpDestinationRectF.set(destinationBounds);
+        return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees);
+    }
+
+    /**
+     * Operates the scale (setMatrix) on a given transaction and leash, along with a rotation.
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+            Rect sourceBounds, RectF destinationBounds, float degrees) {
+        mTmpSourceRectF.set(sourceBounds);
+        // We want the matrix to position the surface relative to the screen coordinates so offset
+        // the source to 0,0
+        mTmpSourceRectF.offsetTo(0, 0);
+        mTmpDestinationRectF.set(destinationBounds);
+        mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
+        mTmpTransform.postRotate(degrees,
+                mTmpDestinationRectF.centerX(), mTmpDestinationRectF.centerY());
+        tx.setMatrix(leash, mTmpTransform, mTmpFloat9);
+        return this;
+    }
+
+    /**
+     * Operates the scale (setMatrix) on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx,
+            SurfaceControl leash, Rect sourceRectHint,
+            Rect sourceBounds, Rect destinationBounds, Rect insets,
+            boolean isInPipDirection, float fraction) {
+        mTmpDestinationRect.set(sourceBounds);
+        // Similar to {@link #scale}, we want to position the surface relative to the screen
+        // coordinates so offset the bounds to 0,0
+        mTmpDestinationRect.offsetTo(0, 0);
+        mTmpDestinationRect.inset(insets);
+        // Scale to the bounds no smaller than the destination and offset such that the top/left
+        // of the scaled inset source rect aligns with the top/left of the destination bounds
+        final float scale;
+        if (isInPipDirection
+                && sourceRectHint != null && sourceRectHint.width() < sourceBounds.width()) {
+            // scale by sourceRectHint if it's not edge-to-edge, for entering PiP transition only.
+            final float endScale = sourceBounds.width() <= sourceBounds.height()
+                    ? (float) destinationBounds.width() / sourceRectHint.width()
+                    : (float) destinationBounds.height() / sourceRectHint.height();
+            final float startScale = sourceBounds.width() <= sourceBounds.height()
+                    ? (float) destinationBounds.width() / sourceBounds.width()
+                    : (float) destinationBounds.height() / sourceBounds.height();
+            scale = (1 - fraction) * startScale + fraction * endScale;
+        } else {
+            scale = Math.max((float) destinationBounds.width() / sourceBounds.width(),
+                    (float) destinationBounds.height() / sourceBounds.height());
+        }
+        final float left = destinationBounds.left - insets.left * scale;
+        final float top = destinationBounds.top - insets.top * scale;
+        mTmpTransform.setScale(scale, scale);
+        tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
+                .setCrop(leash, mTmpDestinationRect)
+                .setPosition(leash, left, top);
+        return this;
+    }
+
+    /**
+     * Operates the rotation according to the given degrees and scale (setMatrix) according to the
+     * source bounds and rotated destination bounds. The crop will be the unscaled source bounds.
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper rotateAndScaleWithCrop(SurfaceControl.Transaction tx,
+            SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets,
+            float degrees, float positionX, float positionY, boolean isExpanding,
+            boolean clockwise) {
+        mTmpDestinationRect.set(sourceBounds);
+        mTmpDestinationRect.inset(insets);
+        final int srcW = mTmpDestinationRect.width();
+        final int srcH = mTmpDestinationRect.height();
+        final int destW = destinationBounds.width();
+        final int destH = destinationBounds.height();
+        // Scale by the short side so there won't be empty area if the aspect ratio of source and
+        // destination are different.
+        final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
+        final Rect crop = mTmpDestinationRect;
+        crop.set(0, 0, Transitions.SHELL_TRANSITIONS_ROTATION ? destH
+                : destW, Transitions.SHELL_TRANSITIONS_ROTATION ? destW : destH);
+        // Inverse scale for crop to fit in screen coordinates.
+        crop.scale(1 / scale);
+        crop.offset(insets.left, insets.top);
+        if (isExpanding) {
+            // Expand bounds (shrink insets) in source orientation.
+            positionX -= insets.left * scale;
+            positionY -= insets.top * scale;
+        } else {
+            // Shrink bounds (expand insets) in destination orientation.
+            if (clockwise) {
+                positionX -= insets.top * scale;
+                positionY += insets.left * scale;
+            } else {
+                positionX += insets.top * scale;
+                positionY -= insets.left * scale;
+            }
+        }
+        mTmpTransform.setScale(scale, scale);
+        mTmpTransform.postRotate(degrees);
+        mTmpTransform.postTranslate(positionX, positionY);
+        tx.setMatrix(leash, mTmpTransform, mTmpFloat9).setCrop(leash, crop);
+        return this;
+    }
+
+    /**
+     * Resets the scale (setMatrix) on a given transaction and leash if there's any
+     *
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper resetScale(SurfaceControl.Transaction tx,
+            SurfaceControl leash,
+            Rect destinationBounds) {
+        tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, mTmpFloat9)
+                .setPosition(leash, destinationBounds.left, destinationBounds.top);
+        return this;
+    }
+
+    /**
+     * Operates the round corner radius on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
+            boolean applyCornerRadius) {
+        tx.setCornerRadius(leash, applyCornerRadius ? mCornerRadius : 0);
+        return this;
+    }
+
+    /**
+     * Operates the round corner radius on a given transaction and leash, scaled by bounds
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
+            Rect fromBounds, Rect toBounds) {
+        final float scale = (float) (Math.hypot(fromBounds.width(), fromBounds.height())
+                / Math.hypot(toBounds.width(), toBounds.height()));
+        tx.setCornerRadius(leash, mCornerRadius * scale);
+        return this;
+    }
+
+    /**
+     * Operates the shadow radius on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    public PipSurfaceTransactionHelper shadow(SurfaceControl.Transaction tx, SurfaceControl leash,
+            boolean applyShadowRadius) {
+        tx.setShadowRadius(leash, applyShadowRadius ? mShadowRadius : 0);
+        return this;
+    }
+
+    /**
+     * Interface to standardize {@link SurfaceControl.Transaction} generation across PiP.
+     */
+    public interface SurfaceControlTransactionFactory {
+        /**
+         * @return a new transaction to operate on.
+         */
+        SurfaceControl.Transaction getTransaction();
+    }
+
+    /**
+     * Implementation of {@link SurfaceControlTransactionFactory} that returns
+     * {@link SurfaceControl.Transaction} with VsyncId being set.
+     */
+    public static class VsyncSurfaceControlTransactionFactory
+            implements SurfaceControlTransactionFactory {
+        @Override
+        public SurfaceControl.Transaction getTransaction() {
+            final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+            tx.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+            return tx;
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
new file mode 100644
index 0000000..2478252
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pip2.phone;
+
+import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.RemoteAction;
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Size;
+import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController.ActionListener;
+import com.android.wm.shell.common.pip.PipMenuController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
+import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the PiP menu view which can show menu options or a scrim.
+ *
+ * The current media session provides actions whenever there are no valid actions provided by the
+ * current PiP activity. Otherwise, those actions always take precedence.
+ */
+public class PhonePipMenuController implements PipMenuController {
+
+    private static final String TAG = "PhonePipMenuController";
+    private static final boolean DEBUG = false;
+
+    public static final int MENU_STATE_NONE = 0;
+    public static final int MENU_STATE_FULL = 1;
+
+    /**
+     * A listener interface to receive notification on changes in PIP.
+     */
+    public interface Listener {
+        /**
+         * Called when the PIP menu visibility change has started.
+         *
+         * @param menuState the new, about-to-change state of the menu
+         * @param resize whether or not to resize the PiP with the state change
+         */
+        void onPipMenuStateChangeStart(int menuState, boolean resize, Runnable callback);
+
+        /**
+         * Called when the PIP menu state has finished changing/animating.
+         *
+         * @param menuState the new state of the menu.
+         */
+        void onPipMenuStateChangeFinish(int menuState);
+
+        /**
+         * Called when the PIP requested to be expanded.
+         */
+        void onPipExpand();
+
+        /**
+         * Called when the PIP requested to be dismissed.
+         */
+        void onPipDismiss();
+
+        /**
+         * Called when the PIP requested to show the menu.
+         */
+        void onPipShowMenu();
+
+        /**
+         * Called when the PIP requested to enter Split.
+         */
+        void onEnterSplit();
+    }
+
+    private final Matrix mMoveTransform = new Matrix();
+    private final Rect mTmpSourceBounds = new Rect();
+    private final RectF mTmpSourceRectF = new RectF();
+    private final RectF mTmpDestinationRectF = new RectF();
+    private final Context mContext;
+    private final PipBoundsState mPipBoundsState;
+    private final PipMediaController mMediaController;
+    private final ShellExecutor mMainExecutor;
+    private final Handler mMainHandler;
+
+    private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+            mSurfaceControlTransactionFactory;
+    private final float[] mTmpTransform = new float[9];
+
+    private final ArrayList<Listener> mListeners = new ArrayList<>();
+    private final SystemWindows mSystemWindows;
+    private final PipUiEventLogger mPipUiEventLogger;
+
+    private List<RemoteAction> mAppActions;
+    private RemoteAction mCloseAction;
+    private List<RemoteAction> mMediaActions;
+
+    private int mMenuState;
+
+    private PipMenuView mPipMenuView;
+
+    private SurfaceControl mLeash;
+
+    private ActionListener mMediaActionListener = new ActionListener() {
+        @Override
+        public void onMediaActionsChanged(List<RemoteAction> mediaActions) {
+            mMediaActions = new ArrayList<>(mediaActions);
+            updateMenuActions();
+        }
+    };
+
+    public PhonePipMenuController(Context context, PipBoundsState pipBoundsState,
+            PipMediaController mediaController, SystemWindows systemWindows,
+            PipUiEventLogger pipUiEventLogger,
+            ShellExecutor mainExecutor, Handler mainHandler) {
+        mContext = context;
+        mPipBoundsState = pipBoundsState;
+        mMediaController = mediaController;
+        mSystemWindows = systemWindows;
+        mMainExecutor = mainExecutor;
+        mMainHandler = mainHandler;
+        mPipUiEventLogger = pipUiEventLogger;
+
+        mSurfaceControlTransactionFactory =
+                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
+    }
+
+    public boolean isMenuVisible() {
+        return mPipMenuView != null && mMenuState != MENU_STATE_NONE;
+    }
+
+    /**
+     * Attach the menu when the PiP task first appears.
+     */
+    @Override
+    public void attach(SurfaceControl leash) {
+        mLeash = leash;
+        attachPipMenuView();
+    }
+
+    /**
+     * Detach the menu when the PiP task is gone.
+     */
+    @Override
+    public void detach() {
+        hideMenu();
+        detachPipMenuView();
+        mLeash = null;
+    }
+
+    void attachPipMenuView() {
+        // In case detach was not called (e.g. PIP unexpectedly closed)
+        if (mPipMenuView != null) {
+            detachPipMenuView();
+        }
+        mPipMenuView = new PipMenuView(mContext, this, mMainExecutor, mMainHandler,
+                mPipUiEventLogger);
+        mPipMenuView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+            @Override
+            public void onViewAttachedToWindow(View v) {
+                v.getViewRootImpl().addSurfaceChangedCallback(
+                        new ViewRootImpl.SurfaceChangedCallback() {
+                            @Override
+                            public void surfaceCreated(SurfaceControl.Transaction t) {
+                                final SurfaceControl sc = getSurfaceControl();
+                                if (sc != null) {
+                                    t.reparent(sc, mLeash);
+                                    // make menu on top of the surface
+                                    t.setLayer(sc, Integer.MAX_VALUE);
+                                }
+                            }
+
+                            @Override
+                            public void surfaceReplaced(SurfaceControl.Transaction t) {
+                            }
+
+                            @Override
+                            public void surfaceDestroyed() {
+                            }
+                        });
+            }
+
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+            }
+        });
+
+        mSystemWindows.addView(mPipMenuView,
+                getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
+                0, SHELL_ROOT_LAYER_PIP);
+        setShellRootAccessibilityWindow();
+
+        // Make sure the initial actions are set
+        updateMenuActions();
+    }
+
+    private void detachPipMenuView() {
+        if (mPipMenuView == null) {
+            return;
+        }
+
+        mSystemWindows.removeView(mPipMenuView);
+        mPipMenuView = null;
+    }
+
+    /**
+     * Updates the layout parameters of the menu.
+     * @param destinationBounds New Menu bounds.
+     */
+    @Override
+    public void updateMenuBounds(Rect destinationBounds) {
+        mSystemWindows.updateViewLayout(mPipMenuView,
+                getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, destinationBounds.width(),
+                        destinationBounds.height()));
+        updateMenuLayout(destinationBounds);
+    }
+
+    @Override
+    public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+        if (mPipMenuView != null) {
+            mPipMenuView.onFocusTaskChanged(taskInfo);
+        }
+    }
+
+    /**
+     * Tries to grab a surface control from {@link PipMenuView}. If this isn't available for some
+     * reason (ie. the window isn't ready yet, thus {@link ViewRootImpl} is
+     * {@code null}), it will get the leash that the WindowlessWM has assigned to it.
+     */
+    public SurfaceControl getSurfaceControl() {
+        return mSystemWindows.getViewSurface(mPipMenuView);
+    }
+
+    /**
+     * Adds a new menu activity listener.
+     */
+    public void addListener(Listener listener) {
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+        }
+    }
+
+    @Nullable
+    Size getEstimatedMinMenuSize() {
+        return mPipMenuView == null ? null : mPipMenuView.getEstimatedMinMenuSize();
+    }
+
+    /**
+     * When other components requests the menu controller directly to show the menu, we must
+     * first fire off the request to the other listeners who will then propagate the call
+     * back to the controller with the right parameters.
+     */
+    @Override
+    public void showMenu() {
+        mListeners.forEach(Listener::onPipShowMenu);
+    }
+
+    /**
+     * Similar to {@link #showMenu(int, Rect, boolean, boolean, boolean)} but only show the menu
+     * upon PiP window transition is finished.
+     */
+    public void showMenuWithPossibleDelay(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+            boolean willResizeMenu, boolean showResizeHandle) {
+        if (willResizeMenu) {
+            // hide all visible controls including close button and etc. first, this is to ensure
+            // menu is totally invisible during the transition to eliminate unpleasant artifacts
+            fadeOutMenu();
+        }
+        showMenuInternal(menuState, stackBounds, allowMenuTimeout, willResizeMenu,
+                willResizeMenu /* withDelay=willResizeMenu here */, showResizeHandle);
+    }
+
+    /**
+     * Shows the menu activity immediately.
+     */
+    public void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+            boolean willResizeMenu, boolean showResizeHandle) {
+        showMenuInternal(menuState, stackBounds, allowMenuTimeout, willResizeMenu,
+                false /* withDelay */, showResizeHandle);
+    }
+
+    private void showMenuInternal(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+            boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: showMenu() state=%s"
+                            + " isMenuVisible=%s"
+                            + " allowMenuTimeout=%s"
+                            + " willResizeMenu=%s"
+                            + " withDelay=%s"
+                            + " showResizeHandle=%s"
+                            + " callers=\n%s", TAG, menuState, isMenuVisible(), allowMenuTimeout,
+                    willResizeMenu, withDelay, showResizeHandle, Debug.getCallers(5, "    "));
+        }
+
+        if (!checkPipMenuState()) {
+            return;
+        }
+
+        // Sync the menu bounds before showing it in case it is out of sync.
+        movePipMenu(null /* pipLeash */, null /* transaction */, stackBounds,
+                PipMenuController.ALPHA_NO_CHANGE);
+        updateMenuBounds(stackBounds);
+
+        mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
+                showResizeHandle);
+    }
+
+    /**
+     * Move the PiP menu, which does a translation and possibly a scale transformation.
+     */
+    @Override
+    public void movePipMenu(@Nullable SurfaceControl pipLeash,
+            @Nullable SurfaceControl.Transaction t,
+            Rect destinationBounds, float alpha) {
+        if (destinationBounds.isEmpty()) {
+            return;
+        }
+
+        if (!checkPipMenuState()) {
+            return;
+        }
+
+        // TODO(b/286307861) transaction should be applied outside of PiP menu controller
+        if (pipLeash != null && t != null) {
+            t.apply();
+        }
+    }
+
+    /**
+     * Does an immediate window crop of the PiP menu.
+     */
+    @Override
+    public void resizePipMenu(@Nullable SurfaceControl pipLeash,
+            @Nullable SurfaceControl.Transaction t,
+            Rect destinationBounds) {
+        if (destinationBounds.isEmpty()) {
+            return;
+        }
+
+        if (!checkPipMenuState()) {
+            return;
+        }
+
+        // TODO(b/286307861) transaction should be applied outside of PiP menu controller
+        if (pipLeash != null && t != null) {
+            t.apply();
+        }
+    }
+
+    private boolean checkPipMenuState() {
+        if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: Not going to move PiP, either menu or its parent is not created.", TAG);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Pokes the menu, indicating that the user is interacting with it.
+     */
+    public void pokeMenu() {
+        final boolean isMenuVisible = isMenuVisible();
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: pokeMenu() isMenuVisible=%b", TAG, isMenuVisible);
+        }
+        if (isMenuVisible) {
+            mPipMenuView.pokeMenu();
+        }
+    }
+
+    private void fadeOutMenu() {
+        final boolean isMenuVisible = isMenuVisible();
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: fadeOutMenu() isMenuVisible=%b", TAG, isMenuVisible);
+        }
+        if (isMenuVisible) {
+            mPipMenuView.fadeOutMenu();
+        }
+    }
+
+    /**
+     * Hides the menu view.
+     */
+    public void hideMenu() {
+        final boolean isMenuVisible = isMenuVisible();
+        if (isMenuVisible) {
+            mPipMenuView.hideMenu();
+        }
+    }
+
+    /**
+     * Hides the menu view.
+     *
+     * @param animationType the animation type to use upon hiding the menu
+     * @param resize whether or not to resize the PiP with the state change
+     */
+    public void hideMenu(@PipMenuView.AnimationType int animationType, boolean resize) {
+        final boolean isMenuVisible = isMenuVisible();
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: hideMenu() state=%s"
+                            + " isMenuVisible=%s"
+                            + " animationType=%s"
+                            + " resize=%s"
+                            + " callers=\n%s", TAG, mMenuState, isMenuVisible,
+                    animationType, resize,
+                    Debug.getCallers(5, "    "));
+        }
+        if (isMenuVisible) {
+            mPipMenuView.hideMenu(resize, animationType);
+        }
+    }
+
+    /**
+     * Hides the menu activity.
+     */
+    public void hideMenu(Runnable onStartCallback, Runnable onEndCallback) {
+        if (isMenuVisible()) {
+            // If the menu is visible in either the closed or full state, then hide the menu and
+            // trigger the animation trigger afterwards
+            if (onStartCallback != null) {
+                onStartCallback.run();
+            }
+            mPipMenuView.hideMenu(onEndCallback);
+        }
+    }
+
+    /**
+     * Sets the menu actions to the actions provided by the current PiP menu.
+     */
+    @Override
+    public void setAppActions(List<RemoteAction> appActions,
+            RemoteAction closeAction) {
+        mAppActions = appActions;
+        mCloseAction = closeAction;
+        updateMenuActions();
+    }
+
+    void onPipExpand() {
+        mListeners.forEach(Listener::onPipExpand);
+    }
+
+    void onPipDismiss() {
+        mListeners.forEach(Listener::onPipDismiss);
+    }
+
+    void onEnterSplit() {
+        mListeners.forEach(Listener::onEnterSplit);
+    }
+
+    /**
+     * @return the best set of actions to show in the PiP menu.
+     */
+    private List<RemoteAction> resolveMenuActions() {
+        if (isValidActions(mAppActions)) {
+            return mAppActions;
+        }
+        return mMediaActions;
+    }
+
+    /**
+     * Updates the PiP menu with the best set of actions provided.
+     */
+    private void updateMenuActions() {
+        if (mPipMenuView != null) {
+            mPipMenuView.setActions(mPipBoundsState.getBounds(),
+                    resolveMenuActions(), mCloseAction);
+        }
+    }
+
+    /**
+     * Returns whether the set of actions are valid.
+     */
+    private static boolean isValidActions(List<?> actions) {
+        return actions != null && actions.size() > 0;
+    }
+
+    /**
+     * Handles changes in menu visibility.
+     */
+    void onMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onMenuStateChangeStart() mMenuState=%s"
+                            + " menuState=%s resize=%s"
+                            + " callers=\n%s", TAG, mMenuState, menuState, resize,
+                    Debug.getCallers(5, "    "));
+        }
+
+        if (menuState != mMenuState) {
+            mListeners.forEach(l -> l.onPipMenuStateChangeStart(menuState, resize, callback));
+            if (menuState == MENU_STATE_FULL) {
+                // Once visible, start listening for media action changes. This call will trigger
+                // the menu actions to be updated again.
+                mMediaController.addActionListener(mMediaActionListener);
+            } else {
+                // Once hidden, stop listening for media action changes. This call will trigger
+                // the menu actions to be updated again.
+                mMediaController.removeActionListener(mMediaActionListener);
+            }
+
+            try {
+                WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+                        mSystemWindows.getFocusGrantToken(mPipMenuView),
+                        menuState != MENU_STATE_NONE /* grantFocus */);
+            } catch (RemoteException e) {
+                ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: Unable to update focus as menu appears/disappears, %s", TAG, e);
+            }
+        }
+    }
+
+    void onMenuStateChangeFinish(int menuState) {
+        if (menuState != mMenuState) {
+            mListeners.forEach(l -> l.onPipMenuStateChangeFinish(menuState));
+        }
+        mMenuState = menuState;
+        setShellRootAccessibilityWindow();
+    }
+
+    private void setShellRootAccessibilityWindow() {
+        switch (mMenuState) {
+            case MENU_STATE_NONE:
+                mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP, null);
+                break;
+            default:
+                mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP,
+                        mPipMenuView);
+                break;
+        }
+    }
+
+    /**
+     * Handles a pointer event sent from pip input consumer.
+     */
+    void handlePointerEvent(MotionEvent ev) {
+        if (mPipMenuView == null) {
+            return;
+        }
+
+        if (ev.isTouchEvent()) {
+            mPipMenuView.dispatchTouchEvent(ev);
+        } else {
+            mPipMenuView.dispatchGenericMotionEvent(ev);
+        }
+    }
+
+    /**
+     * Tell the PIP Menu to recalculate its layout given its current position on the display.
+     */
+    public void updateMenuLayout(Rect bounds) {
+        final boolean isMenuVisible = isMenuVisible();
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: updateMenuLayout() state=%s"
+                            + " isMenuVisible=%s"
+                            + " callers=\n%s", TAG, mMenuState, isMenuVisible,
+                    Debug.getCallers(5, "    "));
+        }
+        if (isMenuVisible) {
+            mPipMenuView.updateMenuLayout(bounds);
+        }
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        final String innerPrefix = prefix + "  ";
+        pw.println(prefix + TAG);
+        pw.println(innerPrefix + "mMenuState=" + mMenuState);
+        pw.println(innerPrefix + "mPipMenuView=" + mPipMenuView);
+        pw.println(innerPrefix + "mListeners=" + mListeners.size());
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuActionView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuActionView.java
new file mode 100644
index 0000000..7252675
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuActionView.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pip2.phone;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.wm.shell.R;
+
+/**
+ * Container layout wraps single action image view drawn in PiP menu and can restrict the size of
+ * action image view (see pip_menu_action.xml).
+ */
+public class PipMenuActionView extends FrameLayout {
+    private ImageView mImageView;
+    private View mCustomCloseBackground;
+
+    public PipMenuActionView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mImageView = findViewById(R.id.image);
+        mCustomCloseBackground = findViewById(R.id.custom_close_bg);
+    }
+
+    /** pass through to internal {@link #mImageView} */
+    public void setImageDrawable(Drawable drawable) {
+        mImageView.setImageDrawable(drawable);
+    }
+
+    /** pass through to internal {@link #mCustomCloseBackground} */
+    public void setCustomCloseBackgroundVisibility(@Visibility int visibility) {
+        mCustomCloseBackground.setVisibility(visibility);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuIconsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuIconsAlgorithm.java
new file mode 100644
index 0000000..b5e575b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuIconsAlgorithm.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pip2.phone;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+/**
+ * Helper class to calculate and place the menu icons on the PIP Menu.
+ */
+public class PipMenuIconsAlgorithm {
+
+    private static final String TAG = "PipMenuIconsAlgorithm";
+
+    protected ViewGroup mViewRoot;
+    protected ViewGroup mTopEndContainer;
+    protected View mDragHandle;
+    protected View mEnterSplitButton;
+    protected View mSettingsButton;
+    protected View mDismissButton;
+
+    protected PipMenuIconsAlgorithm(Context context) {
+    }
+
+    /**
+     * Bind the necessary views.
+     */
+    public void bindViews(ViewGroup viewRoot, ViewGroup topEndContainer, View dragHandle,
+            View enterSplitButton, View settingsButton, View dismissButton) {
+        mViewRoot = viewRoot;
+        mTopEndContainer = topEndContainer;
+        mDragHandle = dragHandle;
+        mEnterSplitButton = enterSplitButton;
+        mSettingsButton = settingsButton;
+        mDismissButton = dismissButton;
+    }
+
+    /**
+     * Updates the position of the drag handle based on where the PIP window is on the screen.
+     */
+    public void onBoundsChanged(Rect bounds) {
+        // On phones, the menu icons are always static and will never move based on the PIP window
+        // position. No need to do anything here.
+    }
+
+    /**
+     * Set the gravity on the given view.
+     */
+    protected static void setLayoutGravity(View v, int gravity) {
+        if (v.getLayoutParams() instanceof FrameLayout.LayoutParams) {
+            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) v.getLayoutParams();
+            params.gravity = gravity;
+            v.setLayoutParams(params);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
new file mode 100644
index 0000000..a5b76c7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
@@ -0,0 +1,630 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pip2.phone;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.provider.Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
+
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.Pair;
+import android.util.Size;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
+import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Translucent window that gets started on top of a task in PIP to allow the user to control it.
+ */
+public class PipMenuView extends FrameLayout {
+
+    private static final String TAG = "PipMenuView";
+
+    private static final int ANIMATION_NONE_DURATION_MS = 0;
+    private static final int ANIMATION_HIDE_DURATION_MS = 125;
+
+    /** No animation performed during menu hide. */
+    public static final int ANIM_TYPE_NONE = 0;
+    /** Fade out the menu until it's invisible. Used when the PIP window remains visible.  */
+    public static final int ANIM_TYPE_HIDE = 1;
+    /** Fade out the menu in sync with the PIP window. */
+    public static final int ANIM_TYPE_DISMISS = 2;
+
+    @IntDef(prefix = { "ANIM_TYPE_" }, value = {
+            ANIM_TYPE_NONE,
+            ANIM_TYPE_HIDE,
+            ANIM_TYPE_DISMISS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AnimationType {}
+
+    private static final int INITIAL_DISMISS_DELAY = 3500;
+    private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
+    private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30;
+
+    private static final float MENU_BACKGROUND_ALPHA = 0.54f;
+    private static final float DISABLED_ACTION_ALPHA = 0.54f;
+
+    private int mMenuState;
+    private boolean mAllowMenuTimeout = true;
+    private boolean mAllowTouches = true;
+    private int mDismissFadeOutDurationMs;
+    private final List<RemoteAction> mActions = new ArrayList<>();
+    private RemoteAction mCloseAction;
+
+    private AccessibilityManager mAccessibilityManager;
+    private Drawable mBackgroundDrawable;
+    private View mMenuContainer;
+    private LinearLayout mActionsGroup;
+    private int mBetweenActionPaddingLand;
+
+    private AnimatorSet mMenuContainerAnimator;
+    private final PhonePipMenuController mController;
+    private final PipUiEventLogger mPipUiEventLogger;
+
+    private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
+            new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    final float alpha = (float) animation.getAnimatedValue();
+                    mBackgroundDrawable.setAlpha((int) (MENU_BACKGROUND_ALPHA * alpha * 255));
+                }
+            };
+
+    private ShellExecutor mMainExecutor;
+    private Handler mMainHandler;
+
+    /**
+     * Whether the most recent showing of the menu caused a PIP resize, such as when PIP is too
+     * small and it is resized on menu show to fit the actions.
+     */
+    private boolean mDidLastShowMenuResize;
+    private final Runnable mHideMenuRunnable = this::hideMenu;
+
+    protected View mViewRoot;
+    protected View mSettingsButton;
+    protected View mDismissButton;
+    protected View mEnterSplitButton;
+    protected View mTopEndContainer;
+    protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
+
+    // How long the shell will wait for the app to close the PiP if a custom action is set.
+    private final int mPipForceCloseDelay;
+
+    public PipMenuView(Context context, PhonePipMenuController controller,
+            ShellExecutor mainExecutor, Handler mainHandler, PipUiEventLogger pipUiEventLogger) {
+        super(context, null, 0);
+        mContext = context;
+        mController = controller;
+        mMainExecutor = mainExecutor;
+        mMainHandler = mainHandler;
+        mPipUiEventLogger = pipUiEventLogger;
+
+        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+        inflate(context, R.layout.pip_menu, this);
+
+        mPipForceCloseDelay = context.getResources().getInteger(
+                R.integer.config_pipForceCloseDelay);
+
+        mBackgroundDrawable = mContext.getDrawable(R.drawable.pip_menu_background);
+        mBackgroundDrawable.setAlpha(0);
+        mViewRoot = findViewById(R.id.background);
+        mViewRoot.setBackground(mBackgroundDrawable);
+        mMenuContainer = findViewById(R.id.menu_container);
+        mMenuContainer.setAlpha(0);
+        mTopEndContainer = findViewById(R.id.top_end_container);
+        mSettingsButton = findViewById(R.id.settings);
+        mSettingsButton.setAlpha(0);
+        mSettingsButton.setOnClickListener((v) -> {
+            if (v.getAlpha() != 0) {
+                showSettings();
+            }
+        });
+        mDismissButton = findViewById(R.id.dismiss);
+        mDismissButton.setAlpha(0);
+        mDismissButton.setOnClickListener(v -> dismissPip());
+        findViewById(R.id.expand_button).setOnClickListener(v -> {
+            if (mMenuContainer.getAlpha() != 0) {
+                expandPip();
+            }
+        });
+
+        mEnterSplitButton = findViewById(R.id.enter_split);
+        mEnterSplitButton.setAlpha(0);
+        mEnterSplitButton.setOnClickListener(v -> {
+            if (mEnterSplitButton.getAlpha() != 0) {
+                enterSplit();
+            }
+        });
+
+        // this disables the ripples
+        mEnterSplitButton.setEnabled(false);
+
+        findViewById(R.id.resize_handle).setAlpha(0);
+
+        mActionsGroup = findViewById(R.id.actions_group);
+        mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
+                R.dimen.pip_between_action_padding_land);
+        mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
+        mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
+                findViewById(R.id.resize_handle), mEnterSplitButton, mSettingsButton,
+                mDismissButton);
+        mDismissFadeOutDurationMs = context.getResources()
+                .getInteger(R.integer.config_pipExitAnimationDuration);
+
+        initAccessibility();
+    }
+
+    private void initAccessibility() {
+        this.setAccessibilityDelegate(new AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                String label = getResources().getString(R.string.pip_menu_title);
+                info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, label));
+            }
+
+            @Override
+            public boolean performAccessibilityAction(View host, int action, Bundle args) {
+                if (action == ACTION_CLICK && mMenuState != MENU_STATE_FULL) {
+                    mController.showMenu();
+                }
+                return super.performAccessibilityAction(host, action, args);
+            }
+        });
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+            hideMenu();
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return true;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (!mAllowTouches) {
+            return false;
+        }
+
+        if (mAllowMenuTimeout) {
+            repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+        }
+
+        return super.dispatchTouchEvent(ev);
+    }
+
+    @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent event) {
+        if (mAllowMenuTimeout) {
+            repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+        }
+
+        return super.dispatchGenericMotionEvent(event);
+    }
+
+    void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {}
+
+    void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+            boolean resizeMenuOnShow, boolean withDelay, boolean showResizeHandle) {
+        mAllowMenuTimeout = allowMenuTimeout;
+        mDidLastShowMenuResize = resizeMenuOnShow;
+        final boolean enableEnterSplit =
+                mContext.getResources().getBoolean(R.bool.config_pipEnableEnterSplitButton);
+        if (mMenuState != menuState) {
+            // Disallow touches if the menu needs to resize while showing, and we are transitioning
+            // to/from a full menu state.
+            boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow
+                    && (mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
+            mAllowTouches = !disallowTouchesUntilAnimationEnd;
+            cancelDelayedHide();
+            if (mMenuContainerAnimator != null) {
+                mMenuContainerAnimator.cancel();
+            }
+            mMenuContainerAnimator = new AnimatorSet();
+            ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
+                    mMenuContainer.getAlpha(), 1f);
+            menuAnim.addUpdateListener(mMenuBgUpdateListener);
+            ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
+                    mSettingsButton.getAlpha(), 1f);
+            ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
+                    mDismissButton.getAlpha(), 1f);
+            if (menuState == MENU_STATE_FULL) {
+                mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim);
+            }
+            mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
+            mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
+            mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mAllowTouches = true;
+                    notifyMenuStateChangeFinish(menuState);
+                    if (allowMenuTimeout) {
+                        repostDelayedHide(INITIAL_DISMISS_DELAY);
+                    }
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    mAllowTouches = true;
+                }
+            });
+            if (withDelay) {
+                // starts the menu container animation after window expansion is completed
+                notifyMenuStateChangeStart(menuState, resizeMenuOnShow, () -> {
+                    if (mMenuContainerAnimator == null) {
+                        return;
+                    }
+                    mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
+                    setVisibility(VISIBLE);
+                    mMenuContainerAnimator.start();
+                });
+            } else {
+                notifyMenuStateChangeStart(menuState, resizeMenuOnShow, null);
+                setVisibility(VISIBLE);
+                mMenuContainerAnimator.start();
+            }
+            updateActionViews(menuState, stackBounds);
+        } else {
+            // If we are already visible, then just start the delayed dismiss and unregister any
+            // existing input consumers from the previous drag
+            if (allowMenuTimeout) {
+                repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+            }
+        }
+    }
+
+    /**
+     * Different from {@link #hideMenu()}, this function does not try to finish this menu activity
+     * and instead, it fades out the controls by setting the alpha to 0 directly without menu
+     * visibility callbacks invoked.
+     */
+    void fadeOutMenu() {
+        mMenuContainer.setAlpha(0f);
+        mSettingsButton.setAlpha(0f);
+        mDismissButton.setAlpha(0f);
+        mEnterSplitButton.setAlpha(0f);
+    }
+
+    void pokeMenu() {
+        cancelDelayedHide();
+    }
+
+    void updateMenuLayout(Rect bounds) {
+        mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
+    }
+
+    void hideMenu() {
+        hideMenu(null);
+    }
+
+    void hideMenu(Runnable animationEndCallback) {
+        hideMenu(animationEndCallback, true /* notifyMenuVisibility */, mDidLastShowMenuResize,
+                ANIM_TYPE_HIDE);
+    }
+
+    void hideMenu(boolean resize, @AnimationType int animationType) {
+        hideMenu(null /* animationFinishedRunnable */, true /* notifyMenuVisibility */, resize,
+                animationType);
+    }
+
+    void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
+            boolean resize, @AnimationType int animationType) {
+        if (mMenuState != MENU_STATE_NONE) {
+            cancelDelayedHide();
+            if (notifyMenuVisibility) {
+                notifyMenuStateChangeStart(MENU_STATE_NONE, resize, null);
+            }
+            mMenuContainerAnimator = new AnimatorSet();
+            ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
+                    mMenuContainer.getAlpha(), 0f);
+            menuAnim.addUpdateListener(mMenuBgUpdateListener);
+            ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
+                    mSettingsButton.getAlpha(), 0f);
+            ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
+                    mDismissButton.getAlpha(), 0f);
+            ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
+                    mEnterSplitButton.getAlpha(), 0f);
+            mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
+                    enterSplitAnim);
+            mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
+            mMenuContainerAnimator.setDuration(getFadeOutDuration(animationType));
+            mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    setVisibility(GONE);
+                    if (notifyMenuVisibility) {
+                        notifyMenuStateChangeFinish(MENU_STATE_NONE);
+                    }
+                    if (animationFinishedRunnable != null) {
+                        animationFinishedRunnable.run();
+                    }
+                }
+            });
+            mMenuContainerAnimator.start();
+        }
+    }
+
+    /**
+     * @return Estimated minimum {@link Size} to hold the actions.
+     * See also {@link #updateActionViews(Rect)}
+     */
+    Size getEstimatedMinMenuSize() {
+        final int pipActionSize = getResources().getDimensionPixelSize(R.dimen.pip_action_size);
+        // the minimum width would be (2 * pipActionSize) since we have settings and dismiss button
+        // on the top action container.
+        final int width = Math.max(2, mActions.size()) * pipActionSize;
+        final int height = getResources().getDimensionPixelSize(R.dimen.pip_expand_action_size)
+                + getResources().getDimensionPixelSize(R.dimen.pip_action_padding)
+                + getResources().getDimensionPixelSize(R.dimen.pip_expand_container_edge_margin);
+        return new Size(width, height);
+    }
+
+    void setActions(Rect stackBounds, @Nullable List<RemoteAction> actions,
+            @Nullable RemoteAction closeAction) {
+        mActions.clear();
+        if (actions != null && !actions.isEmpty()) {
+            mActions.addAll(actions);
+        }
+        mCloseAction = closeAction;
+        if (mMenuState == MENU_STATE_FULL) {
+            updateActionViews(mMenuState, stackBounds);
+        }
+    }
+
+    private void updateActionViews(int menuState, Rect stackBounds) {
+        ViewGroup expandContainer = findViewById(R.id.expand_container);
+        ViewGroup actionsContainer = findViewById(R.id.actions_container);
+        actionsContainer.setOnTouchListener((v, ev) -> {
+            // Do nothing, prevent click through to parent
+            return true;
+        });
+
+        // Update the expand button only if it should show with the menu
+        expandContainer.setVisibility(menuState == MENU_STATE_FULL
+                ? View.VISIBLE
+                : View.INVISIBLE);
+
+        LayoutParams expandedLp =
+                (LayoutParams) expandContainer.getLayoutParams();
+        if (mActions.isEmpty() || menuState == MENU_STATE_NONE) {
+            actionsContainer.setVisibility(View.INVISIBLE);
+
+            // Update the expand container margin to adjust the center of the expand button to
+            // account for the existence of the action container
+            expandedLp.topMargin = 0;
+            expandedLp.bottomMargin = 0;
+        } else {
+            actionsContainer.setVisibility(View.VISIBLE);
+            if (mActionsGroup != null) {
+                // Ensure we have as many buttons as actions
+                final LayoutInflater inflater = LayoutInflater.from(mContext);
+                while (mActionsGroup.getChildCount() < mActions.size()) {
+                    final PipMenuActionView actionView = (PipMenuActionView) inflater.inflate(
+                            R.layout.pip_menu_action, mActionsGroup, false);
+                    mActionsGroup.addView(actionView);
+                }
+
+                // Update the visibility of all views
+                for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
+                    mActionsGroup.getChildAt(i).setVisibility(i < mActions.size()
+                            ? View.VISIBLE
+                            : View.GONE);
+                }
+
+                // Recreate the layout
+                final boolean isLandscapePip = stackBounds != null
+                        && (stackBounds.width() > stackBounds.height());
+                for (int i = 0; i < mActions.size(); i++) {
+                    final RemoteAction action = mActions.get(i);
+                    final PipMenuActionView actionView =
+                            (PipMenuActionView) mActionsGroup.getChildAt(i);
+                    final boolean isCloseAction = mCloseAction != null && Objects.equals(
+                            mCloseAction.getActionIntent(), action.getActionIntent());
+
+                    final int iconType = action.getIcon().getType();
+                    if (iconType == Icon.TYPE_URI || iconType == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+                        // Disallow loading icon from content URI
+                        actionView.setImageDrawable(null);
+                    } else {
+                        // TODO: Check if the action drawable has changed before we reload it
+                        action.getIcon().loadDrawableAsync(mContext, d -> {
+                            if (d != null) {
+                                d.setTint(Color.WHITE);
+                                actionView.setImageDrawable(d);
+                            }
+                        }, mMainHandler);
+                    }
+                    actionView.setCustomCloseBackgroundVisibility(
+                            isCloseAction ? View.VISIBLE : View.GONE);
+                    actionView.setContentDescription(action.getContentDescription());
+                    if (action.isEnabled()) {
+                        actionView.setOnClickListener(
+                                v -> onActionViewClicked(action.getActionIntent(), isCloseAction));
+                    }
+                    actionView.setEnabled(action.isEnabled());
+                    actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA);
+
+                    // Update the margin between actions
+                    LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+                            actionView.getLayoutParams();
+                    lp.leftMargin = (isLandscapePip && i > 0) ? mBetweenActionPaddingLand : 0;
+                }
+            }
+
+            // Update the expand container margin to adjust the center of the expand button to
+            // account for the existence of the action container
+            expandedLp.topMargin = getResources().getDimensionPixelSize(
+                    R.dimen.pip_action_padding);
+            expandedLp.bottomMargin = getResources().getDimensionPixelSize(
+                    R.dimen.pip_expand_container_edge_margin);
+        }
+        expandContainer.requestLayout();
+    }
+
+    private void notifyMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
+        mController.onMenuStateChangeStart(menuState, resize, callback);
+    }
+
+    private void notifyMenuStateChangeFinish(int menuState) {
+        mMenuState = menuState;
+        mController.onMenuStateChangeFinish(menuState);
+    }
+
+    private void expandPip() {
+        // Do not notify menu visibility when hiding the menu, the controller will do this when it
+        // handles the message
+        hideMenu(mController::onPipExpand, false /* notifyMenuVisibility */, true /* resize */,
+                ANIM_TYPE_HIDE);
+        mPipUiEventLogger.log(
+                PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
+    }
+
+    private void dismissPip() {
+        if (mMenuState != MENU_STATE_NONE) {
+            // Do not call hideMenu() directly. Instead, let the menu controller handle it just as
+            // any other dismissal that will update the touch state and fade out the PIP task
+            // and the menu view at the same time.
+            mController.onPipDismiss();
+            mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_TAP_TO_REMOVE);
+        }
+    }
+
+    /**
+     * Execute the {@link PendingIntent} attached to the {@link PipMenuActionView}.
+     * If the given {@link PendingIntent} matches {@link #mCloseAction}, we need to make sure
+     * the PiP is removed after a certain timeout in case the app does not respond in a
+     * timely manner.
+     */
+    private void onActionViewClicked(@NonNull PendingIntent intent, boolean isCloseAction) {
+        try {
+            intent.send();
+        } catch (PendingIntent.CanceledException e) {
+            ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: Failed to send action, %s", TAG, e);
+        }
+        if (isCloseAction) {
+            mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_CUSTOM_CLOSE);
+            mAllowTouches = false;
+            mMainExecutor.executeDelayed(() -> {
+                hideMenu();
+                // TODO: it's unsafe to call onPipDismiss with a delay here since
+                // we may have a different PiP by the time this runnable is executed.
+                mController.onPipDismiss();
+                mAllowTouches = true;
+            }, mPipForceCloseDelay);
+        }
+    }
+
+    private void enterSplit() {
+        // Do not notify menu visibility when hiding the menu, the controller will do this when it
+        // handles the message
+        hideMenu(mController::onEnterSplit, false /* notifyMenuVisibility */, true /* resize */,
+                ANIM_TYPE_HIDE);
+    }
+
+
+    private void showSettings() {
+        final Pair<ComponentName, Integer> topPipActivityInfo =
+                PipUtils.getTopPipActivity(mContext);
+        if (topPipActivityInfo.first != null) {
+            final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
+                    Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
+            settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+            mContext.startActivityAsUser(settingsIntent, UserHandle.of(topPipActivityInfo.second));
+            mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_SHOW_SETTINGS);
+        }
+    }
+
+    private void cancelDelayedHide() {
+        mMainExecutor.removeCallbacks(mHideMenuRunnable);
+    }
+
+    private void repostDelayedHide(int delay) {
+        int recommendedTimeout = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
+                FLAG_CONTENT_ICONS | FLAG_CONTENT_CONTROLS);
+        mMainExecutor.removeCallbacks(mHideMenuRunnable);
+        mMainExecutor.executeDelayed(mHideMenuRunnable, recommendedTimeout);
+    }
+
+    private long getFadeOutDuration(@AnimationType int animationType) {
+        switch (animationType) {
+            case ANIM_TYPE_NONE:
+                return ANIMATION_NONE_DURATION_MS;
+            case ANIM_TYPE_HIDE:
+                return ANIMATION_HIDE_DURATION_MS;
+            case ANIM_TYPE_DISMISS:
+                return mDismissFadeOutDurationMs;
+            default:
+                throw new IllegalStateException("Invalid animation type " + animationType);
+        }
+    }
+}
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 0b8f60e..57b73b3 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
@@ -24,10 +24,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Rect;
 import android.view.SurfaceControl;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 import androidx.core.content.ContextCompat;
 
@@ -36,6 +38,10 @@
 import com.android.wm.shell.common.pip.PipUtils;
 import com.android.wm.shell.pip.PipTransitionController;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.function.Consumer;
+
 /**
  * Scheduler for Shell initiated PiP transitions and animations.
  */
@@ -58,13 +64,37 @@
     private SurfaceControl mPinnedTaskLeash;
 
     /**
-     * A temporary broadcast receiver to initiate exit PiP via expand.
-     * This will later be modified to be triggered by the PiP menu.
+     * Temporary PiP CUJ codes to schedule PiP related transitions directly from Shell.
+     * This is used for a broadcast receiver to resolve intents. This should be removed once
+     * there is an equivalent of PipTouchHandler and PipResizeGestureHandler for PiP2.
+     */
+    private static final int PIP_EXIT_VIA_EXPAND_CODE = 0;
+    private static final int PIP_DOUBLE_TAP = 1;
+
+    @IntDef(value = {
+            PIP_EXIT_VIA_EXPAND_CODE,
+            PIP_DOUBLE_TAP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface PipUserJourneyCode {}
+
+    /**
+     * A temporary broadcast receiver to initiate PiP CUJs.
      */
     private class PipSchedulerReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            scheduleExitPipViaExpand();
+            int userJourneyCode = intent.getIntExtra("cuj_code_extra", 0);
+            switch (userJourneyCode) {
+                case PIP_EXIT_VIA_EXPAND_CODE:
+                    scheduleExitPipViaExpand();
+                    break;
+                case PIP_DOUBLE_TAP:
+                    scheduleDoubleTapToResize();
+                    break;
+                default:
+                    throw new IllegalStateException("unexpected CUJ code=" + userJourneyCode);
+            }
         }
     }
 
@@ -121,6 +151,23 @@
         }
     }
 
+    /**
+     * Schedules resize PiP via double tap.
+     */
+    public void scheduleDoubleTapToResize() {}
+
+    /**
+     * Animates resizing of the pinned stack given the duration.
+     */
+    public void scheduleAnimateResizePip(Rect toBounds, Consumer<Rect> onFinishResizeCallback) {
+        if (mPipTaskToken == null) {
+            return;
+        }
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.setBounds(mPipTaskToken, toBounds);
+        mPipTransitionController.startResizeTransition(wct, onFinishResizeCallback);
+    }
+
     void onExitPip() {
         mPipTaskToken = null;
         mPinnedTaskLeash = null;
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 3b0e7c1..fbf4d13 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
@@ -22,10 +22,12 @@
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
 import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_RESIZE_PIP;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.PictureInPictureParams;
+import android.content.Context;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.view.SurfaceControl;
@@ -36,34 +38,39 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.pip.PipUtils;
-import com.android.wm.shell.pip.PipMenuController;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
+import java.util.function.Consumer;
+
 /**
  * Implementation of transitions for PiP on phone.
  */
 public class PipTransition extends PipTransitionController {
     private static final String TAG = PipTransition.class.getSimpleName();
 
+    private final Context mContext;
     private final PipScheduler mPipScheduler;
     @Nullable
     private WindowContainerToken mPipTaskToken;
     @Nullable
     private IBinder mEnterTransition;
     @Nullable
-    private IBinder mAutoEnterButtonNavTransition;
-    @Nullable
     private IBinder mExitViaExpandTransition;
     @Nullable
-    private IBinder mLegacyEnterTransition;
+    private IBinder mResizeTransition;
+
+    private Consumer<Rect> mFinishResizeCallback;
 
     public PipTransition(
+            Context context,
             @NonNull ShellInit shellInit,
             @NonNull ShellTaskOrganizer shellTaskOrganizer,
             @NonNull Transitions transitions,
@@ -74,6 +81,7 @@
         super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController,
                 pipBoundsAlgorithm);
 
+        mContext = context;
         mPipScheduler = pipScheduler;
         mPipScheduler.setPipTransitionController(this);
     }
@@ -87,7 +95,7 @@
 
     @Override
     public void startExitTransition(int type, WindowContainerTransaction out,
-            @android.annotation.Nullable Rect destinationBounds) {
+            @Nullable Rect destinationBounds) {
         if (out == null) {
             return;
         }
@@ -97,6 +105,16 @@
         }
     }
 
+    @Override
+    public void startResizeTransition(WindowContainerTransaction wct,
+            Consumer<Rect> onFinishResizeCallback) {
+        if (wct == null) {
+            return;
+        }
+        mResizeTransition = mTransitions.startTransition(TRANSIT_RESIZE_PIP, wct, this);
+        mFinishResizeCallback = onFinishResizeCallback;
+    }
+
     @Nullable
     @Override
     public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@@ -126,43 +144,6 @@
     public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
             @Nullable SurfaceControl.Transaction finishT) {}
 
-    private WindowContainerTransaction getEnterPipTransaction(@NonNull IBinder transition,
-            @NonNull TransitionRequestInfo request) {
-        // cache the original task token to check for multi-activity case later
-        final ActivityManager.RunningTaskInfo pipTask = request.getPipTask();
-        PictureInPictureParams pipParams = pipTask.pictureInPictureParams;
-        mPipBoundsState.setBoundsStateForEntry(pipTask.topActivity, pipTask.topActivityInfo,
-                pipParams, mPipBoundsAlgorithm);
-
-        // calculate the entry bounds and notify core to move task to pinned with final bounds
-        final Rect entryBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
-        mPipBoundsState.setBounds(entryBounds);
-
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        wct.movePipActivityToPinnedRootTask(pipTask.token, entryBounds);
-        return wct;
-    }
-
-    private boolean isAutoEnterInButtonNavigation(@NonNull TransitionRequestInfo requestInfo) {
-        final ActivityManager.RunningTaskInfo pipTask = requestInfo.getPipTask();
-        if (pipTask == null) {
-            return false;
-        }
-        if (pipTask.pictureInPictureParams == null) {
-            return false;
-        }
-
-        // Assuming auto-enter is enabled and pipTask is non-null, the TRANSIT_OPEN request type
-        // implies that we are entering PiP in button navigation mode. This is guaranteed by
-        // TaskFragment#startPausing()` in Core which wouldn't get called in gesture nav.
-        return requestInfo.getType() == TRANSIT_OPEN
-                && pipTask.pictureInPictureParams.isAutoEnterEnabled();
-    }
-
-    private boolean isEnterPictureInPictureModeRequest(@NonNull TransitionRequestInfo requestInfo) {
-        return requestInfo.getType() == TRANSIT_PIP;
-    }
-
     @Override
     public boolean startAnimation(@NonNull IBinder transition,
             @NonNull TransitionInfo info,
@@ -182,16 +163,48 @@
         } else if (transition == mExitViaExpandTransition) {
             mExitViaExpandTransition = null;
             return startExpandAnimation(info, startTransaction, finishTransaction, finishCallback);
+        } else if (transition == mResizeTransition) {
+            mResizeTransition = null;
+            return startResizeAnimation(info, startTransaction, finishTransaction, finishCallback);
         }
         return false;
     }
 
-    private boolean isLegacyEnter(@NonNull TransitionInfo info) {
+    private boolean startResizeAnimation(@NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {
         TransitionInfo.Change pipChange = getPipChange(info);
-        // If the only change in the changes list is a TO_FRONT mode PiP task,
-        // then this is legacy-enter PiP.
-        return pipChange != null && pipChange.getMode() == TRANSIT_TO_FRONT
-                && info.getChanges().size() == 1;
+        if (pipChange == null) {
+            return false;
+        }
+        SurfaceControl pipLeash = pipChange.getLeash();
+        Rect destinationBounds = pipChange.getEndAbsBounds();
+
+        // Even though the final bounds and crop are applied with finishTransaction since
+        // this is a visible change, we still need to handle the app draw coming in. Snapshot
+        // covering app draw during collection will be removed by startTransaction. So we make
+        // the crop equal to the final bounds and then scale the leash back to starting bounds.
+        startTransaction.setWindowCrop(pipLeash, pipChange.getEndAbsBounds().width(),
+                pipChange.getEndAbsBounds().height());
+        startTransaction.setScale(pipLeash,
+                (float) mPipBoundsState.getBounds().width() / destinationBounds.width(),
+                (float) mPipBoundsState.getBounds().height() / destinationBounds.height());
+        startTransaction.apply();
+
+        finishTransaction.setScale(pipLeash,
+                (float) mPipBoundsState.getBounds().width() / destinationBounds.width(),
+                (float) mPipBoundsState.getBounds().height() / destinationBounds.height());
+
+        // We are done with the transition, but will continue animating leash to final bounds.
+        finishCallback.onTransitionFinished(null);
+
+        // Animate the pip leash with the new buffer
+        final int duration = mContext.getResources().getInteger(
+                R.integer.config_pipResizeAnimationDuration);
+        // TODO: b/275910498 Couple this routine with a new implementation of the PiP animator.
+        startResizeAnimation(pipLeash, mPipBoundsState.getBounds(), destinationBounds, duration);
+        return true;
     }
 
     private boolean startBoundsTypeEnterAnimation(@NonNull TransitionInfo info,
@@ -251,6 +264,57 @@
         return null;
     }
 
+    private WindowContainerTransaction getEnterPipTransaction(@NonNull IBinder transition,
+            @NonNull TransitionRequestInfo request) {
+        // cache the original task token to check for multi-activity case later
+        final ActivityManager.RunningTaskInfo pipTask = request.getPipTask();
+        PictureInPictureParams pipParams = pipTask.pictureInPictureParams;
+        mPipBoundsState.setBoundsStateForEntry(pipTask.topActivity, pipTask.topActivityInfo,
+                pipParams, mPipBoundsAlgorithm);
+
+        // calculate the entry bounds and notify core to move task to pinned with final bounds
+        final Rect entryBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+        mPipBoundsState.setBounds(entryBounds);
+
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.movePipActivityToPinnedRootTask(pipTask.token, entryBounds);
+        return wct;
+    }
+
+    private boolean isAutoEnterInButtonNavigation(@NonNull TransitionRequestInfo requestInfo) {
+        final ActivityManager.RunningTaskInfo pipTask = requestInfo.getPipTask();
+        if (pipTask == null) {
+            return false;
+        }
+        if (pipTask.pictureInPictureParams == null) {
+            return false;
+        }
+
+        // Assuming auto-enter is enabled and pipTask is non-null, the TRANSIT_OPEN request type
+        // implies that we are entering PiP in button navigation mode. This is guaranteed by
+        // TaskFragment#startPausing()` in Core which wouldn't get called in gesture nav.
+        return requestInfo.getType() == TRANSIT_OPEN
+                && pipTask.pictureInPictureParams.isAutoEnterEnabled();
+    }
+
+    private boolean isEnterPictureInPictureModeRequest(@NonNull TransitionRequestInfo requestInfo) {
+        return requestInfo.getType() == TRANSIT_PIP;
+    }
+
+    private boolean isLegacyEnter(@NonNull TransitionInfo info) {
+        TransitionInfo.Change pipChange = getPipChange(info);
+        // If the only change in the changes list is a TO_FRONT mode PiP task,
+        // then this is legacy-enter PiP.
+        return pipChange != null && pipChange.getMode() == TRANSIT_TO_FRONT
+                && info.getChanges().size() == 1;
+    }
+
+    /**
+     * TODO: b/275910498 Use a new implementation of the PiP animator here.
+     */
+    private void startResizeAnimation(SurfaceControl leash, Rect startBounds,
+            Rect endBounds, int duration) {}
+
     private void onExitPip() {
         mPipTaskToken = null;
         mPipScheduler.onExitPip();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 253acc4..0ca244c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -158,5 +158,10 @@
      * does not expect split to currently be running.
      */
     RemoteAnimationTarget[] onStartingSplitLegacy(in RemoteAnimationTarget[] appTargets) = 14;
+
+    /**
+     * Reverse the split.
+     */
+    oneway void switchSplitPosition() = 22;
 }
-// Last id = 21
\ No newline at end of file
+// Last id = 22
\ No newline at end of file
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 2ec52bb..70cb2fc 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
@@ -1109,6 +1109,12 @@
         mStageCoordinator.onDroppedToSplit(position, dragSessionId);
     }
 
+    void switchSplitPosition(String reason) {
+        if (isSplitScreenVisible()) {
+            mStageCoordinator.switchSplitPosition(reason);
+        }
+    }
+
     /**
      * Return the {@param exitReason} as a string.
      */
@@ -1473,5 +1479,11 @@
                     true /* blocking */);
             return out[0];
         }
+
+        @Override
+        public void switchSplitPosition() {
+            executeRemoteCallWithTaskPermission(mController, "switchSplitPosition",
+                    (controller) -> controller.switchSplitPosition("remoteCall"));
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
index 7fd03a9..7f16c5e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
@@ -43,6 +43,8 @@
                 return runRemoveFromSideStage(args, pw);
             case "setSideStagePosition":
                 return runSetSideStagePosition(args, pw);
+            case "switchSplitPosition":
+                return runSwitchSplitPosition();
             default:
                 pw.println("Invalid command: " + args[0]);
                 return false;
@@ -84,6 +86,11 @@
         return true;
     }
 
+    private boolean runSwitchSplitPosition() {
+        mController.switchSplitPosition("shellCommand");
+        return true;
+    }
+
     @Override
     public void printShellCommandHelp(PrintWriter pw, String prefix) {
         pw.println(prefix + "moveToSideStage <taskId> <SideStagePosition>");
@@ -92,5 +99,7 @@
         pw.println(prefix + "  Remove a task with given id in split-screen mode.");
         pw.println(prefix + "setSideStagePosition <SideStagePosition>");
         pw.println(prefix + "  Sets the position of the side-stage.");
+        pw.println(prefix + "switchSplitPosition");
+        pw.println(prefix + "  Reverses the split.");
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 3fb0dbf..67fc7e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -175,6 +175,9 @@
     /** Transition to animate task to desktop. */
     public static final int TRANSIT_MOVE_TO_DESKTOP = WindowManager.TRANSIT_FIRST_CUSTOM + 15;
 
+    /** Transition to resize PiP task. */
+    public static final int TRANSIT_RESIZE_PIP = TRANSIT_FIRST_CUSTOM + 16;
+
     private final ShellTaskOrganizer mOrganizer;
     private final Context mContext;
     private final ShellExecutor mMainExecutor;
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 e6faa63..96eaa1e 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
@@ -287,7 +287,7 @@
     }
 
     boolean isHandlingDragResize() {
-        return mDragResizeListener.isHandlingDragResize();
+        return mDragResizeListener != null && mDragResizeListener.isHandlingDragResize();
     }
 
     private void closeDragResizeListener() {
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 554b1fb..a8b39c4 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
@@ -32,6 +32,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
@@ -60,7 +61,6 @@
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -345,7 +345,7 @@
                 mTaskOperations.injectBackKey();
             } else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
                 if (!decoration.isHandleMenuActive()) {
-                    moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
+                    moveTaskToFront(decoration.mTaskInfo);
                     decoration.createHandleMenu();
                 } else {
                     decoration.closeHandleMenu();
@@ -419,10 +419,10 @@
                     && id != R.id.maximize_window) {
                 return false;
             }
-            moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
+            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+            moveTaskToFront(decoration.mTaskInfo);
 
             if (!mHasLongClicked && id != R.id.maximize_window) {
-                final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
                 decoration.closeMaximizeMenuIfNeeded(e);
             }
 
@@ -466,7 +466,8 @@
          */
         @Override
         public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
-            final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+            final RunningTaskInfo taskInfo = decoration.mTaskInfo;
             if (DesktopModeStatus.isEnabled()
                     && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
                 return false;
@@ -492,8 +493,6 @@
                 }
                 case MotionEvent.ACTION_MOVE: {
                     mShouldClick = false;
-                    final DesktopModeWindowDecoration decoration =
-                            mWindowDecorByTaskId.get(mTaskId);
                     // If a decor's resize drag zone is active, don't also try to reposition it.
                     if (decoration.isHandlingDragResize()) break;
                     decoration.closeMaximizeMenu();
@@ -544,11 +543,22 @@
             return true;
         }
 
+        /**
+         * Perform a task size toggle on release of the double-tap, assuming no drag event
+         * was handled during the double-tap.
+         * @param e The motion event that occurred during the double-tap gesture.
+         * @return true if the event should be consumed, false if not
+         */
         @Override
-        public boolean onDoubleTap(@NonNull MotionEvent e) {
-            final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+        public boolean onDoubleTapEvent(@NonNull MotionEvent e) {
+            final int action = e.getActionMasked();
+            if (mIsDragging || (action != MotionEvent.ACTION_UP
+                    && action != MotionEvent.ACTION_CANCEL)) {
+                return false;
+            }
             mDesktopTasksController.ifPresent(c -> {
-                c.toggleDesktopTaskSize(taskInfo, mWindowDecorByTaskId.get(taskInfo.taskId));
+                final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+                c.toggleDesktopTaskSize(decoration.mTaskInfo, decoration);
             });
             return true;
         }
@@ -833,7 +843,18 @@
 
     @Nullable
     private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) {
-        if (mSplitScreenController != null && mSplitScreenController.isSplitScreenVisible()) {
+        final DesktopModeWindowDecoration focusedDecor = getFocusedDecor();
+        if (focusedDecor == null) {
+            return null;
+        }
+        final boolean splitScreenVisible = mSplitScreenController != null
+                && mSplitScreenController.isSplitScreenVisible();
+        // It's possible that split tasks are visible but neither is focused, such as when there's
+        // a fullscreen translucent window on top of them. In that case, the relevant decor should
+        // just be that translucent focused window.
+        final boolean focusedTaskInSplit = mSplitScreenController != null
+                && mSplitScreenController.isTaskInSplitScreen(focusedDecor.mTaskInfo.taskId);
+        if (splitScreenVisible && focusedTaskInSplit) {
             // We can't look at focused task here as only one task will have focus.
             DesktopModeWindowDecoration splitTaskDecor = getSplitScreenDecor(ev);
             return splitTaskDecor == null ? getFocusedDecor() : splitTaskDecor;
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 2023333..3f0a281 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
@@ -36,7 +36,6 @@
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.util.Log;
 import android.view.Choreographer;
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
@@ -388,27 +387,20 @@
     }
 
     boolean isHandlingDragResize() {
-        return mDragResizeListener.isHandlingDragResize();
+        return mDragResizeListener != null && mDragResizeListener.isHandlingDragResize();
     }
 
     private void loadAppInfo() {
-        String packageName = mTaskInfo.realActivity.getPackageName();
         PackageManager pm = mContext.getApplicationContext().getPackageManager();
-        try {
-            final IconProvider provider = new IconProvider(mContext);
-            mAppIconDrawable = provider.getIcon(pm.getActivityInfo(mTaskInfo.baseActivity,
-                    PackageManager.ComponentInfoFlags.of(0)));
-            final Resources resources = mContext.getResources();
-            final BaseIconFactory factory = new BaseIconFactory(mContext,
-                    resources.getDisplayMetrics().densityDpi,
-                    resources.getDimensionPixelSize(R.dimen.desktop_mode_caption_icon_radius));
-            mAppIconBitmap = factory.createScaledBitmap(mAppIconDrawable, MODE_DEFAULT);
-            final ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName,
-                    PackageManager.ApplicationInfoFlags.of(0));
-            mAppName = pm.getApplicationLabel(applicationInfo);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Package not found: " + packageName, e);
-        }
+        final IconProvider provider = new IconProvider(mContext);
+        mAppIconDrawable = provider.getIcon(mTaskInfo.topActivityInfo);
+        final Resources resources = mContext.getResources();
+        final BaseIconFactory factory = new BaseIconFactory(mContext,
+                resources.getDisplayMetrics().densityDpi,
+                resources.getDimensionPixelSize(R.dimen.desktop_mode_caption_icon_radius));
+        mAppIconBitmap = factory.createScaledBitmap(mAppIconDrawable, MODE_DEFAULT);
+        final ApplicationInfo applicationInfo = mTaskInfo.topActivityInfo.applicationInfo;
+        mAppName = pm.getApplicationLabel(applicationInfo);
     }
 
     private void closeDragResizeListener() {
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 8b38f99..d902621 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
@@ -353,6 +353,7 @@
         private boolean mShouldHandleEvents;
         private int mLastCursorType = PointerIcon.TYPE_DEFAULT;
         private Rect mDragStartTaskBounds;
+        private final Rect mTmpRect = new Rect();
 
         private TaskResizeInputEventReceiver(
                 InputChannel inputChannel, Handler handler, Choreographer choreographer) {
@@ -477,14 +478,15 @@
         }
 
         private void updateInputSinkRegionForDrag(Rect taskBounds) {
+            mTmpRect.set(taskBounds);
             final DisplayLayout layout = mDisplayController.getDisplayLayout(mDisplayId);
             final Region dragTouchRegion = new Region(-taskBounds.left,
                     -taskBounds.top,
                     -taskBounds.left + layout.width(),
                     -taskBounds.top + layout.height());
             // Remove the localized task bounds from the touch region.
-            taskBounds.offsetTo(0, 0);
-            dragTouchRegion.op(taskBounds, Region.Op.DIFFERENCE);
+            mTmpRect.offsetTo(0, 0);
+            dragTouchRegion.op(mTmpRect, Region.Op.DIFFERENCE);
             updateSinkInputChannel(dragTouchRegion);
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
index 368231e..b0d3b50 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
@@ -125,6 +125,7 @@
 
         relayout(taskBounds, t);
         if (fadeIn) {
+            cancelAnimation();
             mVeilAnimator = new ValueAnimator();
             mVeilAnimator.setFloatValues(0f, 1f);
             mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
@@ -210,15 +211,16 @@
      * Animate veil's alpha to 0, fading it out.
      */
     public void hideVeil() {
-        final ValueAnimator animator = new ValueAnimator();
-        animator.setFloatValues(1, 0);
-        animator.setDuration(RESIZE_ALPHA_DURATION);
-        animator.addUpdateListener(animation -> {
+        cancelAnimation();
+        mVeilAnimator = new ValueAnimator();
+        mVeilAnimator.setFloatValues(1, 0);
+        mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
+        mVeilAnimator.addUpdateListener(animation -> {
             SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
-            t.setAlpha(mVeilSurface, 1 - animator.getAnimatedFraction());
+            t.setAlpha(mVeilSurface, 1 - mVeilAnimator.getAnimatedFraction());
             t.apply();
         });
-        animator.addListener(new AnimatorListenerAdapter() {
+        mVeilAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
@@ -226,7 +228,7 @@
                 t.apply();
             }
         });
-        animator.start();
+        mVeilAnimator.start();
     }
 
     @ColorRes
@@ -240,10 +242,20 @@
         }
     }
 
+    private void cancelAnimation() {
+        if (mVeilAnimator != null) {
+            mVeilAnimator.removeAllUpdateListeners();
+            mVeilAnimator.cancel();
+        }
+    }
+
     /**
      * Dispose of veil when it is no longer needed, likely on close of its container decor.
      */
     void dispose() {
+        cancelAnimation();
+        mVeilAnimator = null;
+
         if (mViewHost != null) {
             mViewHost.release();
             mViewHost = null;
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
index e61f762..faeb342 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
@@ -30,6 +30,7 @@
         "src/**/B*.kt",
         "src/**/C*.kt",
         "src/**/D*.kt",
+        "src/**/F*.kt",
         "src/**/S*.kt",
     ],
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
similarity index 92%
rename from libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
rename to libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
index a5c2c89..2792298 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
 import android.tools.common.Rotation
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
@@ -62,7 +61,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) :
+class FromSplitScreenAutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) :
     AutoEnterPipOnGoToHomeTest(flicker) {
     private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
     /** Second app used to enter split screen mode */
@@ -120,9 +119,7 @@
     @Presubmit
     @Test
     override fun pipAppLayerAlwaysVisible() {
-        // pip layer in gesture nav will disappear during transition with alpha animation
-        Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
-        super.pipAppLayerAlwaysVisible()
+        // pip layer in should disappear during transition with alpha animation
     }
 
     @Presubmit
@@ -151,8 +148,7 @@
         @JvmStatic
         fun getParams() =
             LegacyFlickerTestFactory.nonRotationTests(
-                // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+                supportedRotations = listOf(Rotation.ROTATION_0)
             )
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
similarity index 72%
copy from libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
copy to libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index a5c2c89..4c23153 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
 import android.tools.common.Rotation
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
@@ -28,6 +27,7 @@
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -62,8 +62,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) :
-    AutoEnterPipOnGoToHomeTest(flicker) {
+class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) :
+    EnterPipTransition(flicker) {
     private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
     /** Second app used to enter split screen mode */
     private val secondAppForSplitScreen =
@@ -88,7 +88,7 @@
                     secondAppForSplitScreen,
                     flicker.scenario.startRotation
                 )
-                pipApp.enableAutoEnterForPipActivity()
+                pipApp.enableEnterPipOnUserLeaveHint()
             }
             teardown {
                 pipApp.exit(wmHelper)
@@ -120,9 +120,44 @@
     @Presubmit
     @Test
     override fun pipAppLayerAlwaysVisible() {
-        // pip layer in gesture nav will disappear during transition with alpha animation
+        // pip layer in should disappear during transition with alpha animation
+    }
+
+    @Presubmit
+    @Test
+    override fun focusChanges() {
+        // in gestural nav the focus goes to different activity on swipe up
         Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
-        super.pipAppLayerAlwaysVisible()
+        super.focusChanges()
+    }
+
+    @Presubmit
+    @Test
+    fun pipAppWindowVisibleChanges() {
+        // TODO(b/322394235) this method comes from EnterPipOnUserLeaveHintTest, but due to how
+        // it is being packaged in Android.bp we cannot inherit from it. Needs to be refactored.
+        Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
+        flicker.assertWm {
+            this.isAppWindowVisible(pipApp)
+                .then()
+                .isAppWindowInvisible(pipApp, isOptional = true)
+                .then()
+                .isAppWindowVisible(pipApp, isOptional = true)
+        }
+    }
+
+    @Presubmit
+    @Test
+    override fun pipAppWindowAlwaysVisible() {
+        // TODO(b/322394235) this method comes from EnterPipOnUserLeaveHintTest, but due to how
+        // it is being packaged in Android.bp we cannot inherit from it. Needs to be refactored.
+        // In gestural nav the pip will first move behind home and then above home. The visual
+        // appearance visible->invisible->visible is asserted by pipAppLayerAlwaysVisible().
+        // But the internal states of activity don't need to follow that, such as a temporary
+        // visibility state can be changed quickly outside a transaction so the test doesn't
+        // detect that. Hence, skip the case to avoid restricting the internal implementation.
+        Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+        super.pipAppWindowAlwaysVisible()
     }
 
     @Presubmit
@@ -149,10 +184,8 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams() =
-            LegacyFlickerTestFactory.nonRotationTests(
-                // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
-            )
+        fun getParams() = LegacyFlickerTestFactory.nonRotationTests(
+            supportedRotations = listOf(Rotation.ROTATION_0)
+        )
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
index 4ddc539..dd358e7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
@@ -30,6 +30,7 @@
 import android.app.ActivityManager;
 import android.app.AppCompatTaskInfo.CameraCompatControlState;
 import android.app.TaskInfo;
+import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
 import android.util.Pair;
 import android.view.LayoutInflater;
@@ -83,6 +84,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        doReturn(100).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance();
         mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN);
         mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue,
                 mCallback, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
@@ -127,7 +129,6 @@
     @Test
     public void testOnClickForSizeCompatHint() {
         mWindowManager.mHasSizeCompat = true;
-        doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(mTaskInfo);
         mWindowManager.createLayout(/* canShow= */ true);
         final LinearLayout sizeCompatHint = mLayout.findViewById(R.id.size_compat_hint);
         sizeCompatHint.performClick();
@@ -222,6 +223,9 @@
         taskInfo.taskId = TASK_ID;
         taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat;
         taskInfo.appCompatTaskInfo.cameraCompatControlState = cameraCompatControlState;
+        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 1000;
+        taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1000;
+        taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 2000, 2000));
         return taskInfo;
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index 2acfd83..4f261cd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -20,7 +20,6 @@
 import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
 import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
 import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 import static android.view.WindowInsets.Type.navigationBars;
 
@@ -86,6 +85,8 @@
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
 
     private static final int TASK_ID = 1;
+    private static final int TASK_WIDTH = 2000;
+    private static final int TASK_HEIGHT = 2000;
 
     @Mock private SyncTransactionQueue mSyncTransactionQueue;
     @Mock private CompatUIController.CompatUICallback mCallback;
@@ -101,6 +102,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        doReturn(100).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance();
         mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN);
         mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue,
                 mCallback, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
@@ -115,7 +117,6 @@
     public void testCreateSizeCompatButton() {
         // Doesn't create layout if show is false.
         mWindowManager.mHasSizeCompat = true;
-        doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(mTaskInfo);
         assertTrue(mWindowManager.createLayout(/* canShow= */ false));
 
         verify(mWindowManager, never()).inflateLayout();
@@ -147,6 +148,13 @@
         mWindowManager.mHasSizeCompat = false;
         assertFalse(mWindowManager.createLayout(/* canShow= */ true));
 
+        // Returns false and doesn't create layout if restart button should be hidden.
+        clearInvocations(mWindowManager);
+        mWindowManager.mHasSizeCompat = true;
+        mTaskInfo.appCompatTaskInfo.topActivityLetterboxWidth = TASK_WIDTH;
+        mTaskInfo.appCompatTaskInfo.topActivityLetterboxHeight = TASK_HEIGHT;
+        assertFalse(mWindowManager.createLayout(/* canShow= */ true));
+
         verify(mWindowManager, never()).inflateLayout();
     }
 
@@ -293,8 +301,6 @@
 
     @Test
     public void testUpdateCompatInfoLayoutNotInflatedYet() {
-        mWindowManager.mHasSizeCompat = true;
-        doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(any());
         mWindowManager.createLayout(/* canShow= */ false);
 
         verify(mWindowManager, never()).inflateLayout();
@@ -314,6 +320,15 @@
         mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
 
         verify(mWindowManager).inflateLayout();
+
+        // Change shouldShowSizeCompatRestartButton to false and pass canShow true, layout
+        // shouldn't be inflated
+        clearInvocations(mWindowManager);
+        taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = TASK_WIDTH;
+        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = TASK_HEIGHT;
+        mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
+
+        verify(mWindowManager, never()).inflateLayout();
     }
 
     @Test
@@ -364,7 +379,6 @@
         // Create button if it is not created.
         mWindowManager.mLayout = null;
         mWindowManager.mHasSizeCompat = true;
-        doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(mTaskInfo);
         mWindowManager.updateVisibility(/* canShow= */ true);
 
         verify(mWindowManager).createLayout(/* canShow= */ true);
@@ -489,7 +503,6 @@
         TaskInfo taskInfo = createTaskInfo(true, CAMERA_COMPAT_CONTROL_HIDDEN);
         taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 2000, 2000));
         taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 2000;
-        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1850;
 
         assertFalse(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));
@@ -514,6 +527,11 @@
         taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat;
         taskInfo.appCompatTaskInfo.cameraCompatControlState = cameraCompatControlState;
         taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK;
+        // Letterboxed activity that takes half the screen should show size compat restart button
+        taskInfo.configuration.windowConfiguration.setBounds(
+                new Rect(0, 0, TASK_WIDTH, TASK_HEIGHT));
+        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 1000;
+        taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1000;
         return taskInfo;
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java
index 0f8db85..b583acd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.pip.phone;
 
-import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_CUSTOM;
-import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_DEFAULT;
-import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_MAX;
-import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.nextSizeSpec;
+import static com.android.wm.shell.common.pip.PipDoubleTapHelper.SIZE_SPEC_CUSTOM;
+import static com.android.wm.shell.common.pip.PipDoubleTapHelper.SIZE_SPEC_DEFAULT;
+import static com.android.wm.shell.common.pip.PipDoubleTapHelper.SIZE_SPEC_MAX;
+import static com.android.wm.shell.common.pip.PipDoubleTapHelper.nextSizeSpec;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -30,6 +30,7 @@
 
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipDoubleTapHelper;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -38,7 +39,7 @@
 import org.mockito.Mock;
 
 /**
- * Unit test against {@link PipDoubleTapHelper}.
+ * Unit test against {@link com.android.wm.shell.common.pip.PipDoubleTapHelper}.
  */
 @RunWith(AndroidTestingRunner.class)
 public class PipDoubleTapHelperTest extends ShellTestCase {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 12a5594..7f3bfbb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -421,6 +421,15 @@
         assertEquals(false, controller.supportsMultiInstanceSplit(component));
     }
 
+    @Test
+    public void testSwitchSplitPosition_checksIsSplitScreenVisible() {
+        final String reason = "test";
+        when(mSplitScreenController.isSplitScreenVisible()).thenReturn(true, false);
+        mSplitScreenController.switchSplitPosition(reason);
+        mSplitScreenController.switchSplitPosition(reason);
+        verify(mStageCoordinator, times(1)).switchSplitPosition(reason);
+    }
+
     private Intent createStartIntent(String activityName) {
         Intent intent = new Intent();
         intent.setComponent(new ComponentName(mContext, activityName));
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 193f16d..40e61dd 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
@@ -27,6 +27,8 @@
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -202,6 +204,8 @@
                 .setTaskDescriptionBuilder(taskDescriptionBuilder)
                 .setVisible(visible)
                 .build();
+        taskInfo.topActivityInfo = new ActivityInfo();
+        taskInfo.topActivityInfo.applicationInfo = new ApplicationInfo();
         taskInfo.realActivity = new ComponentName("com.android.wm.shell.windowdecor",
                 "DesktopModeWindowDecorationTests");
         taskInfo.baseActivity = new ComponentName("com.android.wm.shell.windowdecor",
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index b40b73c..4e330da 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -229,15 +229,6 @@
     path: "apex/java",
 }
 
-java_api_contribution {
-    name: "framework-graphics-public-stubs",
-    api_surface: "public",
-    api_file: "api/current.txt",
-    visibility: [
-        "//build/orchestrator/apis",
-    ],
-}
-
 // ------------------------
 // APEX
 // ------------------------
@@ -638,14 +629,6 @@
             // Allow implicit fallthroughs in HardwareBitmapUploader.cpp until they are fixed.
             cflags: ["-Wno-implicit-fallthrough"],
         },
-        host: {
-            srcs: [
-                "utils/HostColorSpace.cpp",
-            ],
-            export_static_lib_headers: [
-                "libarect",
-            ],
-        },
     },
 }
 
diff --git a/libs/hwui/utils/HostColorSpace.cpp b/libs/hwui/utils/HostColorSpace.cpp
deleted file mode 100644
index 77a6820..0000000
--- a/libs/hwui/utils/HostColorSpace.cpp
+++ /dev/null
@@ -1,417 +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.
- */
-// This is copied from framework/native/libs/ui in order not to include libui in host build
-
-#include <ui/ColorSpace.h>
-
-using namespace std::placeholders;
-
-namespace android {
-
-static constexpr float linearResponse(float v) {
-    return v;
-}
-
-static constexpr float rcpResponse(float x, const ColorSpace::TransferParameters& p) {
-    return x >= p.d * p.c ? (std::pow(x, 1.0f / p.g) - p.b) / p.a : x / p.c;
-}
-
-static constexpr float response(float x, const ColorSpace::TransferParameters& p) {
-    return x >= p.d ? std::pow(p.a * x + p.b, p.g) : p.c * x;
-}
-
-static constexpr float rcpFullResponse(float x, const ColorSpace::TransferParameters& p) {
-    return x >= p.d * p.c ? (std::pow(x - p.e, 1.0f / p.g) - p.b) / p.a : (x - p.f) / p.c;
-}
-
-static constexpr float fullResponse(float x, const ColorSpace::TransferParameters& p) {
-    return x >= p.d ? std::pow(p.a * x + p.b, p.g) + p.e : p.c * x + p.f;
-}
-
-static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
-    float xx = std::abs(x);
-    return std::copysign(xx >= d * c ? (std::pow(xx, 1.0f / g) - b) / a : xx / c, x);
-}
-
-static float absResponse(float x, float g, float a, float b, float c, float d) {
-   float xx = std::abs(x);
-   return std::copysign(xx >= d ? std::pow(a * xx + b, g) : c * xx, x);
-}
-
-static float safePow(float x, float e) {
-    return powf(x < 0.0f ? 0.0f : x, e);
-}
-
-static ColorSpace::transfer_function toOETF(const ColorSpace::TransferParameters& parameters) {
-    if (parameters.e == 0.0f && parameters.f == 0.0f) {
-        return std::bind(rcpResponse, _1, parameters);
-    }
-    return std::bind(rcpFullResponse, _1, parameters);
-}
-
-static ColorSpace::transfer_function toEOTF( const ColorSpace::TransferParameters& parameters) {
-    if (parameters.e == 0.0f && parameters.f == 0.0f) {
-        return std::bind(response, _1, parameters);
-    }
-    return std::bind(fullResponse, _1, parameters);
-}
-
-static ColorSpace::transfer_function toOETF(float gamma) {
-    if (gamma == 1.0f) {
-        return linearResponse;
-    }
-    return std::bind(safePow, _1, 1.0f / gamma);
-}
-
-static ColorSpace::transfer_function toEOTF(float gamma) {
-    if (gamma == 1.0f) {
-        return linearResponse;
-    }
-    return std::bind(safePow, _1, gamma);
-}
-
-static constexpr std::array<float2, 3> computePrimaries(const mat3& rgbToXYZ) {
-    float3 r(rgbToXYZ * float3{1, 0, 0});
-    float3 g(rgbToXYZ * float3{0, 1, 0});
-    float3 b(rgbToXYZ * float3{0, 0, 1});
-
-    return {{r.xy / dot(r, float3{1}),
-             g.xy / dot(g, float3{1}),
-             b.xy / dot(b, float3{1})}};
-}
-
-static constexpr float2 computeWhitePoint(const mat3& rgbToXYZ) {
-    float3 w(rgbToXYZ * float3{1});
-    return w.xy / dot(w, float3{1});
-}
-
-ColorSpace::ColorSpace(
-        const std::string& name,
-        const mat3& rgbToXYZ,
-        transfer_function OETF,
-        transfer_function EOTF,
-        clamping_function clamper) noexcept
-        : mName(name)
-        , mRGBtoXYZ(rgbToXYZ)
-        , mXYZtoRGB(inverse(rgbToXYZ))
-        , mOETF(std::move(OETF))
-        , mEOTF(std::move(EOTF))
-        , mClamper(std::move(clamper))
-        , mPrimaries(computePrimaries(rgbToXYZ))
-        , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
-}
-
-ColorSpace::ColorSpace(
-        const std::string& name,
-        const mat3& rgbToXYZ,
-        const TransferParameters parameters,
-        clamping_function clamper) noexcept
-        : mName(name)
-        , mRGBtoXYZ(rgbToXYZ)
-        , mXYZtoRGB(inverse(rgbToXYZ))
-        , mParameters(parameters)
-        , mOETF(toOETF(mParameters))
-        , mEOTF(toEOTF(mParameters))
-        , mClamper(std::move(clamper))
-        , mPrimaries(computePrimaries(rgbToXYZ))
-        , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
-}
-
-ColorSpace::ColorSpace(
-        const std::string& name,
-        const mat3& rgbToXYZ,
-        float gamma,
-        clamping_function clamper) noexcept
-        : mName(name)
-        , mRGBtoXYZ(rgbToXYZ)
-        , mXYZtoRGB(inverse(rgbToXYZ))
-        , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
-        , mOETF(toOETF(gamma))
-        , mEOTF(toEOTF(gamma))
-        , mClamper(std::move(clamper))
-        , mPrimaries(computePrimaries(rgbToXYZ))
-        , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
-}
-
-ColorSpace::ColorSpace(
-        const std::string& name,
-        const std::array<float2, 3>& primaries,
-        const float2& whitePoint,
-        transfer_function OETF,
-        transfer_function EOTF,
-        clamping_function clamper) noexcept
-        : mName(name)
-        , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
-        , mXYZtoRGB(inverse(mRGBtoXYZ))
-        , mOETF(std::move(OETF))
-        , mEOTF(std::move(EOTF))
-        , mClamper(std::move(clamper))
-        , mPrimaries(primaries)
-        , mWhitePoint(whitePoint) {
-}
-
-ColorSpace::ColorSpace(
-        const std::string& name,
-        const std::array<float2, 3>& primaries,
-        const float2& whitePoint,
-        const TransferParameters parameters,
-        clamping_function clamper) noexcept
-        : mName(name)
-        , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
-        , mXYZtoRGB(inverse(mRGBtoXYZ))
-        , mParameters(parameters)
-        , mOETF(toOETF(mParameters))
-        , mEOTF(toEOTF(mParameters))
-        , mClamper(std::move(clamper))
-        , mPrimaries(primaries)
-        , mWhitePoint(whitePoint) {
-}
-
-ColorSpace::ColorSpace(
-        const std::string& name,
-        const std::array<float2, 3>& primaries,
-        const float2& whitePoint,
-        float gamma,
-        clamping_function clamper) noexcept
-        : mName(name)
-        , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
-        , mXYZtoRGB(inverse(mRGBtoXYZ))
-        , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
-        , mOETF(toOETF(gamma))
-        , mEOTF(toEOTF(gamma))
-        , mClamper(std::move(clamper))
-        , mPrimaries(primaries)
-        , mWhitePoint(whitePoint) {
-}
-
-constexpr mat3 ColorSpace::computeXYZMatrix(
-        const std::array<float2, 3>& primaries, const float2& whitePoint) {
-    const float2& R = primaries[0];
-    const float2& G = primaries[1];
-    const float2& B = primaries[2];
-    const float2& W = whitePoint;
-
-    float oneRxRy = (1 - R.x) / R.y;
-    float oneGxGy = (1 - G.x) / G.y;
-    float oneBxBy = (1 - B.x) / B.y;
-    float oneWxWy = (1 - W.x) / W.y;
-
-    float RxRy = R.x / R.y;
-    float GxGy = G.x / G.y;
-    float BxBy = B.x / B.y;
-    float WxWy = W.x / W.y;
-
-    float BY =
-            ((oneWxWy - oneRxRy) * (GxGy - RxRy) - (WxWy - RxRy) * (oneGxGy - oneRxRy)) /
-            ((oneBxBy - oneRxRy) * (GxGy - RxRy) - (BxBy - RxRy) * (oneGxGy - oneRxRy));
-    float GY = (WxWy - RxRy - BY * (BxBy - RxRy)) / (GxGy - RxRy);
-    float RY = 1 - GY - BY;
-
-    float RYRy = RY / R.y;
-    float GYGy = GY / G.y;
-    float BYBy = BY / B.y;
-
-    return {
-        float3{RYRy * R.x, RY, RYRy * (1 - R.x - R.y)},
-        float3{GYGy * G.x, GY, GYGy * (1 - G.x - G.y)},
-        float3{BYBy * B.x, BY, BYBy * (1 - B.x - B.y)}
-    };
-}
-
-const ColorSpace ColorSpace::sRGB() {
-    return {
-        "sRGB IEC61966-2.1",
-        {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
-        {0.3127f, 0.3290f},
-        {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f, 0.0f, 0.0f}
-    };
-}
-
-const ColorSpace ColorSpace::linearSRGB() {
-    return {
-        "sRGB IEC61966-2.1 (Linear)",
-        {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
-        {0.3127f, 0.3290f}
-    };
-}
-
-const ColorSpace ColorSpace::extendedSRGB() {
-    return {
-        "scRGB-nl IEC 61966-2-2:2003",
-        {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
-        {0.3127f, 0.3290f},
-        std::bind(absRcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
-        std::bind(absResponse,    _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
-        std::bind(clamp<float>, _1, -0.799f, 2.399f)
-    };
-}
-
-const ColorSpace ColorSpace::linearExtendedSRGB() {
-    return {
-        "scRGB IEC 61966-2-2:2003",
-        {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
-        {0.3127f, 0.3290f},
-        1.0f,
-        std::bind(clamp<float>, _1, -0.5f, 7.499f)
-    };
-}
-
-const ColorSpace ColorSpace::NTSC() {
-    return {
-        "NTSC (1953)",
-        {{float2{0.67f, 0.33f}, {0.21f, 0.71f}, {0.14f, 0.08f}}},
-        {0.310f, 0.316f},
-        {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
-    };
-}
-
-const ColorSpace ColorSpace::BT709() {
-    return {
-        "Rec. ITU-R BT.709-5",
-        {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
-        {0.3127f, 0.3290f},
-        {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
-    };
-}
-
-const ColorSpace ColorSpace::BT2020() {
-    return {
-        "Rec. ITU-R BT.2020-1",
-        {{float2{0.708f, 0.292f}, {0.170f, 0.797f}, {0.131f, 0.046f}}},
-        {0.3127f, 0.3290f},
-        {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
-    };
-}
-
-const ColorSpace ColorSpace::AdobeRGB() {
-    return {
-        "Adobe RGB (1998)",
-        {{float2{0.64f, 0.33f}, {0.21f, 0.71f}, {0.15f, 0.06f}}},
-        {0.3127f, 0.3290f},
-        2.2f
-    };
-}
-
-const ColorSpace ColorSpace::ProPhotoRGB() {
-    return {
-        "ROMM RGB ISO 22028-2:2013",
-        {{float2{0.7347f, 0.2653f}, {0.1596f, 0.8404f}, {0.0366f, 0.0001f}}},
-        {0.34567f, 0.35850f},
-        {1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f, 0.0f, 0.0f}
-    };
-}
-
-const ColorSpace ColorSpace::DisplayP3() {
-    return {
-        "Display P3",
-        {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
-        {0.3127f, 0.3290f},
-        {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f, 0.0f, 0.0f}
-    };
-}
-
-const ColorSpace ColorSpace::DCIP3() {
-    return {
-        "SMPTE RP 431-2-2007 DCI (P3)",
-        {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
-        {0.314f, 0.351f},
-        2.6f
-    };
-}
-
-const ColorSpace ColorSpace::ACES() {
-    return {
-        "SMPTE ST 2065-1:2012 ACES",
-        {{float2{0.73470f, 0.26530f}, {0.0f, 1.0f}, {0.00010f, -0.0770f}}},
-        {0.32168f, 0.33767f},
-        1.0f,
-        std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
-    };
-}
-
-const ColorSpace ColorSpace::ACEScg() {
-    return {
-        "Academy S-2014-004 ACEScg",
-        {{float2{0.713f, 0.293f}, {0.165f, 0.830f}, {0.128f, 0.044f}}},
-        {0.32168f, 0.33767f},
-        1.0f,
-        std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
-    };
-}
-
-std::unique_ptr<float3[]> ColorSpace::createLUT(uint32_t size, const ColorSpace& src,
-                                                const ColorSpace& dst) {
-    size = clamp(size, 2u, 256u);
-    float m = 1.0f / float(size - 1);
-
-    std::unique_ptr<float3[]> lut(new float3[size * size * size]);
-    float3* data = lut.get();
-
-    ColorSpaceConnector connector(src, dst);
-
-    for (uint32_t z = 0; z < size; z++) {
-        for (int32_t y = int32_t(size - 1); y >= 0; y--) {
-            for (uint32_t x = 0; x < size; x++) {
-                *data++ = connector.transform({x * m, y * m, z * m});
-            }
-        }
-    }
-
-    return lut;
-}
-
-static const float2 ILLUMINANT_D50_XY = {0.34567f, 0.35850f};
-static const float3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f};
-static const mat3 BRADFORD = mat3{
-    float3{ 0.8951f, -0.7502f,  0.0389f},
-    float3{ 0.2664f,  1.7135f, -0.0685f},
-    float3{-0.1614f,  0.0367f,  1.0296f}
-};
-
-static mat3 adaptation(const mat3& matrix, const float3& srcWhitePoint, const float3& dstWhitePoint) {
-    float3 srcLMS = matrix * srcWhitePoint;
-    float3 dstLMS = matrix * dstWhitePoint;
-    return inverse(matrix) * mat3{dstLMS / srcLMS} * matrix;
-}
-
-ColorSpaceConnector::ColorSpaceConnector(
-        const ColorSpace& src,
-        const ColorSpace& dst) noexcept
-        : mSource(src)
-        , mDestination(dst) {
-
-    if (all(lessThan(abs(src.getWhitePoint() - dst.getWhitePoint()), float2{1e-3f}))) {
-        mTransform = dst.getXYZtoRGB() * src.getRGBtoXYZ();
-    } else {
-        mat3 rgbToXYZ(src.getRGBtoXYZ());
-        mat3 xyzToRGB(dst.getXYZtoRGB());
-
-        float3 srcXYZ = ColorSpace::XYZ(float3{src.getWhitePoint(), 1});
-        float3 dstXYZ = ColorSpace::XYZ(float3{dst.getWhitePoint(), 1});
-
-        if (any(greaterThan(abs(src.getWhitePoint() - ILLUMINANT_D50_XY), float2{1e-3f}))) {
-            rgbToXYZ = adaptation(BRADFORD, srcXYZ, ILLUMINANT_D50_XYZ) * src.getRGBtoXYZ();
-        }
-
-        if (any(greaterThan(abs(dst.getWhitePoint() - ILLUMINANT_D50_XY), float2{1e-3f}))) {
-            xyzToRGB = inverse(adaptation(BRADFORD, dstXYZ, ILLUMINANT_D50_XYZ) * dst.getRGBtoXYZ());
-        }
-
-        mTransform = xyzToRGB * rgbToXYZ;
-    }
-}
-
-}; // namespace android
diff --git a/location/api/current.txt b/location/api/current.txt
index c55676b..c7954fe 100644
--- a/location/api/current.txt
+++ b/location/api/current.txt
@@ -682,6 +682,7 @@
   public final class AltitudeConverter {
     ctor public AltitudeConverter();
     method @WorkerThread public void addMslAltitudeToLocation(@NonNull android.content.Context, @NonNull android.location.Location) throws java.io.IOException;
+    method @FlaggedApi(Flags.FLAG_GEOID_HEIGHTS_VIA_ALTITUDE_HAL) public boolean addMslAltitudeToLocation(@NonNull android.location.Location);
   }
 
 }
diff --git a/location/java/android/location/altitude/AltitudeConverter.java b/location/java/android/location/altitude/AltitudeConverter.java
index 3dc024ef..461dafb 100644
--- a/location/java/android/location/altitude/AltitudeConverter.java
+++ b/location/java/android/location/altitude/AltitudeConverter.java
@@ -16,12 +16,16 @@
 
 package android.location.altitude;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.WorkerThread;
 import android.content.Context;
+import android.frameworks.location.altitude.GetGeoidHeightRequest;
+import android.frameworks.location.altitude.GetGeoidHeightResponse;
 import android.location.Location;
+import android.location.flags.Flags;
 
-import com.android.internal.location.altitude.GeoidHeightMap;
+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.util.Preconditions;
@@ -37,7 +41,7 @@
  * <pre>
  * Brian Julian and Michael Angermann.
  * "Resource efficient and accurate altitude conversion to Mean Sea Level."
- * To appear in 2023 IEEE/ION Position, Location and Navigation Symposium (PLANS).
+ * 2023 IEEE/ION Position, Location and Navigation Symposium (PLANS).
  * </pre>
  */
 public final class AltitudeConverter {
@@ -45,8 +49,8 @@
     private static final double MAX_ABS_VALID_LATITUDE = 90;
     private static final double MAX_ABS_VALID_LONGITUDE = 180;
 
-    /** Manages a mapping of geoid heights associated with S2 cells. */
-    private final GeoidHeightMap mGeoidHeightMap = new GeoidHeightMap();
+    /** Manages a mapping of geoid heights and expiration distances associated with S2 cells. */
+    private final GeoidMap mGeoidMap = new GeoidMap();
 
     /**
      * Creates an instance that manages an independent cache to optimized conversions of locations
@@ -78,75 +82,87 @@
     /**
      * Returns the four S2 cell IDs for the map square associated with the {@code location}.
      *
-     * <p>The first map cell contains the location, while the others are located horizontally,
-     * vertically, and diagonally, in that order, with respect to the S2 (i,j) coordinate system. If
-     * the diagonal map cell does not exist (i.e., the location is near an S2 cube vertex), its
-     * corresponding ID is set to zero.
+     * <p>The first map cell, denoted z11 in the appendix of the referenced paper above, contains
+     * the location. The others are the map cells denoted z21, z12, and z22, in that order.
      */
-    @NonNull
-    private static long[] findMapSquare(@NonNull MapParamsProto params,
+    private static long[] findMapSquare(@NonNull MapParamsProto geoidHeightParams,
             @NonNull Location location) {
         long s2CellId = S2CellIdUtils.fromLatLngDegrees(location.getLatitude(),
                 location.getLongitude());
 
         // Cell-space properties and coordinates.
-        int sizeIj = 1 << (S2CellIdUtils.MAX_LEVEL - params.mapS2Level);
+        int sizeIj = 1 << (S2CellIdUtils.MAX_LEVEL - geoidHeightParams.mapS2Level);
         int maxIj = 1 << S2CellIdUtils.MAX_LEVEL;
-        long s0 = S2CellIdUtils.getParent(s2CellId, params.mapS2Level);
-        int f0 = S2CellIdUtils.getFace(s2CellId);
-        int i0 = S2CellIdUtils.getI(s2CellId);
-        int j0 = S2CellIdUtils.getJ(s2CellId);
-        int i1 = i0 + sizeIj;
-        int j1 = j0 + sizeIj;
+        long z11 = S2CellIdUtils.getParent(s2CellId, geoidHeightParams.mapS2Level);
+        int f11 = S2CellIdUtils.getFace(s2CellId);
+        int i1 = S2CellIdUtils.getI(s2CellId);
+        int j1 = S2CellIdUtils.getJ(s2CellId);
+        int i2 = i1 + sizeIj;
+        int j2 = j1 + sizeIj;
 
         // Non-boundary region calculation - simplest and most common case.
-        if (i1 < maxIj && j1 < maxIj) {
-            return new long[]{
-                    s0,
-                    S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f0, i1, j0), params.mapS2Level),
-                    S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f0, i0, j1), params.mapS2Level),
-                    S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f0, i1, j1), params.mapS2Level)
-            };
+        if (i2 < maxIj && j2 < maxIj) {
+            return new long[]{z11, S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f11, i2, j1),
+                    geoidHeightParams.mapS2Level), S2CellIdUtils.getParent(
+                    S2CellIdUtils.fromFij(f11, i1, j2), geoidHeightParams.mapS2Level),
+                    S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f11, i2, j2),
+                            geoidHeightParams.mapS2Level)};
         }
 
-        // Boundary region calculation.
+        // Boundary region calculation
         long[] edgeNeighbors = new long[4];
-        S2CellIdUtils.getEdgeNeighbors(s0, edgeNeighbors);
-        long s1 = edgeNeighbors[1];
-        long s2 = edgeNeighbors[2];
-        long s3;
-        if (f0 % 2 == 1) {
-            S2CellIdUtils.getEdgeNeighbors(s1, edgeNeighbors);
-            if (i1 < maxIj) {
-                s3 = edgeNeighbors[2];
-            } else {
-                s3 = s1;
-                s1 = edgeNeighbors[1];
-            }
-        } else {
-            S2CellIdUtils.getEdgeNeighbors(s2, edgeNeighbors);
-            if (j1 < maxIj) {
-                s3 = edgeNeighbors[1];
-            } else {
-                s3 = s2;
-                s2 = edgeNeighbors[3];
-            }
-        }
+        S2CellIdUtils.getEdgeNeighbors(z11, edgeNeighbors);
+        long z11W = edgeNeighbors[0];
+        long z11S = edgeNeighbors[1];
+        long z11E = edgeNeighbors[2];
+        long z11N = edgeNeighbors[3];
+
+        long[] otherEdgeNeighbors = new long[4];
+        S2CellIdUtils.getEdgeNeighbors(z11W, otherEdgeNeighbors);
+        S2CellIdUtils.getEdgeNeighbors(z11S, edgeNeighbors);
+        long z11Sw = findCommonNeighbor(edgeNeighbors, otherEdgeNeighbors, z11);
+        S2CellIdUtils.getEdgeNeighbors(z11E, otherEdgeNeighbors);
+        long z11Se = findCommonNeighbor(edgeNeighbors, otherEdgeNeighbors, z11);
+        S2CellIdUtils.getEdgeNeighbors(z11N, edgeNeighbors);
+        long z11Ne = findCommonNeighbor(edgeNeighbors, otherEdgeNeighbors, z11);
+
+        long z21 = (f11 % 2 == 1 && i2 >= maxIj) ? z11Sw : z11S;
+        long z12 = (f11 % 2 == 0 && j2 >= maxIj) ? z11Ne : z11E;
+        long z22 = (z21 == z11Sw) ? z11S : (z12 == z11Ne) ? z11E : z11Se;
 
         // Reuse edge neighbors' array to avoid an extra allocation.
-        edgeNeighbors[0] = s0;
-        edgeNeighbors[1] = s1;
-        edgeNeighbors[2] = s2;
-        edgeNeighbors[3] = s3;
+        edgeNeighbors[0] = z11;
+        edgeNeighbors[1] = z21;
+        edgeNeighbors[2] = z12;
+        edgeNeighbors[3] = z22;
         return edgeNeighbors;
     }
 
     /**
+     * Returns the first common non-z11 neighbor found between the two arrays of edge neighbors. If
+     * such a common neighbor does not exist, returns z11.
+     */
+    private static long findCommonNeighbor(long[] edgeNeighbors, long[] otherEdgeNeighbors,
+            long z11) {
+        for (long edgeNeighbor : edgeNeighbors) {
+            if (edgeNeighbor == z11) {
+                continue;
+            }
+            for (long otherEdgeNeighbor : otherEdgeNeighbors) {
+                if (edgeNeighbor == otherEdgeNeighbor) {
+                    return edgeNeighbor;
+                }
+            }
+        }
+        return z11;
+    }
+
+    /**
      * Adds to {@code location} the bilinearly interpolated Mean Sea Level altitude. In addition, a
      * Mean Sea Level altitude accuracy is added if the {@code location} has a valid vertical
      * accuracy; otherwise, does not add a corresponding accuracy.
      */
-    private static void addMslAltitude(@NonNull MapParamsProto params,
+    private static void addMslAltitude(@NonNull MapParamsProto geoidHeightParams,
             @NonNull double[] geoidHeightsMeters, @NonNull Location location) {
         double h0 = geoidHeightsMeters[0];
         double h1 = geoidHeightsMeters[1];
@@ -158,7 +174,7 @@
         // employ the simplified unit square formulation.
         long s2CellId = S2CellIdUtils.fromLatLngDegrees(location.getLatitude(),
                 location.getLongitude());
-        double sizeIj = 1 << (S2CellIdUtils.MAX_LEVEL - params.mapS2Level);
+        double sizeIj = 1 << (S2CellIdUtils.MAX_LEVEL - geoidHeightParams.mapS2Level);
         double wi = (S2CellIdUtils.getI(s2CellId) % sizeIj) / sizeIj;
         double wj = (S2CellIdUtils.getJ(s2CellId) % sizeIj) / sizeIj;
         double offsetMeters = h0 + (h1 - h0) * wi + (h2 - h0) * wj + (h3 - h1 - h2 + h0) * wi * wj;
@@ -167,8 +183,8 @@
         if (location.hasVerticalAccuracy()) {
             double verticalAccuracyMeters = location.getVerticalAccuracyMeters();
             if (Double.isFinite(verticalAccuracyMeters) && verticalAccuracyMeters >= 0) {
-                location.setMslAltitudeAccuracyMeters(
-                        (float) Math.hypot(verticalAccuracyMeters, params.modelRmseMeters));
+                location.setMslAltitudeAccuracyMeters((float) Math.hypot(verticalAccuracyMeters,
+                        geoidHeightParams.modelRmseMeters));
             }
         }
     }
@@ -191,33 +207,84 @@
     public void addMslAltitudeToLocation(@NonNull Context context, @NonNull Location location)
             throws IOException {
         validate(location);
-        MapParamsProto params = GeoidHeightMap.getParams(context);
-        long[] s2CellIds = findMapSquare(params, location);
-        double[] geoidHeightsMeters = mGeoidHeightMap.readGeoidHeights(params, context, s2CellIds);
-        addMslAltitude(params, geoidHeightsMeters, location);
+        MapParamsProto geoidHeightParams = GeoidMap.getGeoidHeightParams(context);
+        long[] mapCells = findMapSquare(geoidHeightParams, location);
+        double[] geoidHeightsMeters = mGeoidMap.readGeoidHeights(geoidHeightParams, context,
+                mapCells);
+        addMslAltitude(geoidHeightParams, geoidHeightsMeters, location);
     }
 
     /**
-     * Same as {@link #addMslAltitudeToLocation(Context, Location)} except that data will not be
-     * loaded from raw assets. Returns true if a Mean Sea Level altitude is added to the
-     * {@code location}; otherwise, returns false and leaves the {@code location} unchanged.
-     *
-     * @hide
+     * Same as {@link #addMslAltitudeToLocation(Context, Location)} except that this method can be
+     * called on the main thread as data will not be loaded from raw assets. Returns true if a Mean
+     * Sea Level altitude is added to the {@code location}; otherwise, returns false and leaves the
+     * {@code location} unchanged.
      */
+    @FlaggedApi(Flags.FLAG_GEOID_HEIGHTS_VIA_ALTITUDE_HAL)
     public boolean addMslAltitudeToLocation(@NonNull Location location) {
         validate(location);
-        MapParamsProto params = GeoidHeightMap.getParams();
-        if (params == null) {
+        MapParamsProto geoidHeightParams = GeoidMap.getGeoidHeightParams();
+        if (geoidHeightParams == null) {
             return false;
         }
 
-        long[] s2CellIds = findMapSquare(params, location);
-        double[] geoidHeightsMeters = mGeoidHeightMap.readGeoidHeights(params, s2CellIds);
+        long[] mapCells = findMapSquare(geoidHeightParams, location);
+        double[] geoidHeightsMeters = mGeoidMap.readGeoidHeights(geoidHeightParams, mapCells);
         if (geoidHeightsMeters == null) {
             return false;
         }
 
-        addMslAltitude(params, geoidHeightsMeters, location);
+        addMslAltitude(geoidHeightParams, geoidHeightsMeters, location);
         return true;
     }
+
+    /**
+     * Returns the geoid height (a.k.a. geoid undulation) at the location specified in {@code
+     * request}. The geoid height at a location is defined as the difference between an altitude
+     * measured above the World Geodetic System 1984 reference ellipsoid (WGS84) and its
+     * corresponding Mean Sea Level altitude.
+     *
+     * <p>Must be called off the main thread as data may be loaded from raw assets.
+     *
+     * @throws IOException              if an I/O error occurs when loading data from raw assets.
+     * @throws IllegalArgumentException if the {@code request} has an invalid latitude or longitude.
+     *                                  Specifically, the latitude must be between -90 and 90 (both
+     *                                  inclusive), and the longitude must be between -180 and 180
+     *                                  (both inclusive).
+     * @hide
+     */
+    @WorkerThread
+    public @NonNull GetGeoidHeightResponse getGeoidHeight(@NonNull Context context,
+            @NonNull GetGeoidHeightRequest request) throws IOException {
+        // Create a valid location from which the geoid height and its accuracy will be extracted.
+        Location location = new Location("");
+        location.setLatitude(request.latitudeDegrees);
+        location.setLongitude(request.longitudeDegrees);
+        location.setAltitude(0.0);
+        location.setVerticalAccuracyMeters(0.0f);
+
+        addMslAltitudeToLocation(context, location);
+        // The geoid height for a location with zero WGS84 altitude is equal in value to the
+        // negative of corresponding MSL altitude.
+        double geoidHeightMeters = -location.getMslAltitudeMeters();
+        // The geoid height error for a location with zero vertical accuracy is equal in value to
+        // the corresponding MSL altitude accuracy.
+        float geoidHeightErrorMeters = location.getMslAltitudeAccuracyMeters();
+
+        MapParamsProto expirationDistanceParams = GeoidMap.getExpirationDistanceParams(context);
+        long s2CellId = S2CellIdUtils.fromLatLngDegrees(location.getLatitude(),
+                location.getLongitude());
+        long[] mapCell = {S2CellIdUtils.getParent(s2CellId, expirationDistanceParams.mapS2Level)};
+        double expirationDistanceMeters = mGeoidMap.readExpirationDistances(
+                expirationDistanceParams, context, mapCell)[0];
+        float additionalGeoidHeightErrorMeters = (float) expirationDistanceParams.modelRmseMeters;
+
+        GetGeoidHeightResponse response = new GetGeoidHeightResponse();
+        response.geoidHeightMeters = geoidHeightMeters;
+        response.geoidHeightErrorMeters = geoidHeightErrorMeters;
+        response.expirationDistanceMeters = expirationDistanceMeters;
+        response.additionalGeoidHeightErrorMeters = additionalGeoidHeightErrorMeters;
+        response.success = true;
+        return response;
+    }
 }
diff --git a/location/java/android/location/flags/gnss.aconfig b/location/java/android/location/flags/location.aconfig
similarity index 77%
rename from location/java/android/location/flags/gnss.aconfig
rename to location/java/android/location/flags/location.aconfig
index 8c7c871..a96fe47 100644
--- a/location/java/android/location/flags/gnss.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -1,6 +1,20 @@
 package: "android.location.flags"
 
 flag {
+    name: "fix_service_watcher"
+    namespace: "location"
+    description: "Enable null explicit services in ServiceWatcher"
+    bug: "311210517"
+}
+
+flag {
+    name: "geoid_heights_via_altitude_hal"
+    namespace: "location"
+    description: "Flag for making geoid heights available via the Altitude HAL"
+    bug: "304375846"
+}
+
+flag {
     name: "gnss_api_navic_l1"
     namespace: "location"
     description: "Flag for GNSS API for NavIC L1"
diff --git a/location/java/com/android/internal/location/altitude/GeoidHeightMap.java b/location/java/com/android/internal/location/altitude/GeoidMap.java
similarity index 65%
rename from location/java/com/android/internal/location/altitude/GeoidHeightMap.java
rename to location/java/com/android/internal/location/altitude/GeoidMap.java
index 8067050..9bf5689 100644
--- a/location/java/com/android/internal/location/altitude/GeoidHeightMap.java
+++ b/location/java/com/android/internal/location/altitude/GeoidMap.java
@@ -34,11 +34,12 @@
 import java.util.Objects;
 
 /**
- * Manages a mapping of geoid heights associated with S2 cells, referred to as MAP CELLS.
+ * Manages a mapping of geoid heights and expiration distances associated with S2 cells, referred to
+ * as MAP CELLS.
  *
  * <p>Tiles are used extensively to reduce the number of entries needed to be stored in memory and
- * on disk. A tile associates geoid heights with all map cells of a common parent at a specified S2
- * level.
+ * on disk. A tile associates geoid heights or expiration distances with all map cells of a common
+ * parent at a specified S2 level.
  *
  * <p>Since bilinear interpolation considers at most four map cells at a time, at most four tiles
  * are simultaneously stored in memory. These tiles, referred to as CACHE TILES, are each keyed by
@@ -48,42 +49,79 @@
  * The latter tiles, referred to as DISK TILES, are each keyed by its common parent's S2 cell token,
  * referred to as a DISK TOKEN.
  */
-public final class GeoidHeightMap {
+public final class GeoidMap {
 
-    private static final Object sLock = new Object();
+    private static final Object GEOID_HEIGHT_PARAMS_LOCK = new Object();
 
-    @GuardedBy("sLock")
+    private static final Object EXPIRATION_DISTANCE_PARAMS_LOCK = new Object();
+
+    @GuardedBy("GEOID_HEIGHT_PARAMS_LOCK")
     @Nullable
-    private static MapParamsProto sParams;
+    private static MapParamsProto sGeoidHeightParams;
 
-    /** Defines a cache large enough to hold all cache tiles needed for interpolation. */
-    private final LruCache<Long, S2TileProto> mCacheTiles = new LruCache<>(4);
+    @GuardedBy("EXPIRATION_DISTANCE_PARAMS_LOCK")
+    @Nullable
+    private static MapParamsProto sExpirationDistanceParams;
 
     /**
-     * Returns the singleton parameter instance for a spherically projected geoid height map and its
-     * corresponding tile management.
+     * Defines a cache large enough to hold all geoid height cache tiles needed for interpolation.
+     */
+    private final LruCache<Long, S2TileProto> mGeoidHeightCacheTiles = new LruCache<>(4);
+
+    /**
+     * Defines a cache large enough to hold all expiration distance cache tiles needed for
+     * interpolation.
+     */
+    private final LruCache<Long, S2TileProto> mExpirationDistanceCacheTiles = new LruCache<>(4);
+
+    /**
+     * Returns the singleton parameter instance for geoid height parameters of a spherically
+     * projected map.
      */
     @NonNull
-    public static MapParamsProto getParams(@NonNull Context context) throws IOException {
-        synchronized (sLock) {
-            if (sParams == null) {
-                try (InputStream is = context.getApplicationContext().getAssets().open(
-                        "geoid_height_map/map-params.pb")) {
-                    sParams = MapParamsProto.parseFrom(is.readAllBytes());
-                }
+    public static MapParamsProto getGeoidHeightParams(@NonNull Context context) throws IOException {
+        synchronized (GEOID_HEIGHT_PARAMS_LOCK) {
+            if (sGeoidHeightParams == null) {
+                // TODO: b/304375846 - Configure with disk tile prefix once resources are updated.
+                sGeoidHeightParams = parseParams(context);
             }
-            return sParams;
+            return sGeoidHeightParams;
         }
     }
 
     /**
-     * Same as {@link #getParams(Context)} except that null is returned if the singleton parameter
-     * instance is not yet initialized.
+     * Returns the singleton parameter instance for expiration distance parameters of a spherically
+     * projected
+     * map.
+     */
+    @NonNull
+    public static MapParamsProto getExpirationDistanceParams(@NonNull Context context)
+            throws IOException {
+        synchronized (EXPIRATION_DISTANCE_PARAMS_LOCK) {
+            if (sExpirationDistanceParams == null) {
+                // TODO: b/304375846 - Configure with disk tile prefix once resources are updated.
+                sExpirationDistanceParams = parseParams(context);
+            }
+            return sExpirationDistanceParams;
+        }
+    }
+
+    @NonNull
+    private static MapParamsProto parseParams(@NonNull Context context) throws IOException {
+        try (InputStream is = context.getApplicationContext().getAssets().open(
+                "geoid_height_map/map-params.pb")) {
+            return MapParamsProto.parseFrom(is.readAllBytes());
+        }
+    }
+
+    /**
+     * Same as {@link #getGeoidHeightParams(Context)} except that null is returned if the singleton
+     * parameter instance is not yet initialized.
      */
     @Nullable
-    public static MapParamsProto getParams() {
-        synchronized (sLock) {
-            return sParams;
+    public static MapParamsProto getGeoidHeightParams() {
+        synchronized (GEOID_HEIGHT_PARAMS_LOCK) {
+            return sGeoidHeightParams;
         }
     }
 
@@ -93,18 +131,17 @@
 
     @NonNull
     private static String getDiskToken(@NonNull MapParamsProto params, long s2CellId) {
-        return S2CellIdUtils.getToken(
-                S2CellIdUtils.getParent(s2CellId, params.diskTileS2Level));
+        return S2CellIdUtils.getToken(S2CellIdUtils.getParent(s2CellId, params.diskTileS2Level));
     }
 
     /**
      * Adds to {@code values} values in the unit interval [0, 1] for the map cells identified by
-     * {@code s2CellIds}. Returns true if values are present for all IDs; otherwise, returns false
-     * and adds NaNs for absent values.
+     * {@code s2CellIds}. Returns true if values are present for all IDs; otherwise, adds NaNs for
+     * absent values and returns false.
      */
     private static boolean getUnitIntervalValues(@NonNull MapParamsProto params,
-            @NonNull TileFunction tileFunction,
-            @NonNull long[] s2CellIds, @NonNull double[] values) {
+            @NonNull TileFunction tileFunction, @NonNull long[] s2CellIds,
+            @NonNull double[] values) {
         int len = s2CellIds.length;
 
         S2TileProto[] tiles = new S2TileProto[len];
@@ -137,9 +174,8 @@
 
     @SuppressWarnings("ReferenceEquality")
     private static void mergeByteBufferValues(@NonNull MapParamsProto params,
-            @NonNull long[] s2CellIds,
-            @NonNull S2TileProto[] tiles,
-            int tileIndex, @NonNull double[] values) {
+            @NonNull long[] s2CellIds, @NonNull S2TileProto[] tiles, int tileIndex,
+            @NonNull double[] values) {
         byte[] bytes = tiles[tileIndex].byteBuffer;
         if (bytes == null || bytes.length == 0) {
             return;
@@ -163,24 +199,22 @@
     }
 
     private static void mergeByteJpegValues(@NonNull MapParamsProto params,
-            @NonNull long[] s2CellIds,
-            @NonNull S2TileProto[] tiles,
-            int tileIndex, @NonNull double[] values) {
+            @NonNull long[] s2CellIds, @NonNull S2TileProto[] tiles, int tileIndex,
+            @NonNull double[] values) {
         mergeByteImageValues(params, tiles[tileIndex].byteJpeg, s2CellIds, tiles, tileIndex,
                 values);
     }
 
     private static void mergeBytePngValues(@NonNull MapParamsProto params,
-            @NonNull long[] s2CellIds,
-            @NonNull S2TileProto[] tiles,
-            int tileIndex, @NonNull double[] values) {
+            @NonNull long[] s2CellIds, @NonNull S2TileProto[] tiles, int tileIndex,
+            @NonNull double[] values) {
         mergeByteImageValues(params, tiles[tileIndex].bytePng, s2CellIds, tiles, tileIndex, values);
     }
 
     @SuppressWarnings("ReferenceEquality")
     private static void mergeByteImageValues(@NonNull MapParamsProto params, @NonNull byte[] bytes,
-            @NonNull long[] s2CellIds,
-            @NonNull S2TileProto[] tiles, int tileIndex, @NonNull double[] values) {
+            @NonNull long[] s2CellIds, @NonNull S2TileProto[] tiles, int tileIndex,
+            @NonNull double[] values) {
         if (bytes == null || bytes.length == 0) {
             return;
         }
@@ -219,7 +253,7 @@
      * ID.
      */
     private static void validate(@NonNull MapParamsProto params, @NonNull long[] s2CellIds) {
-        Preconditions.checkArgument(s2CellIds.length == 4);
+        Preconditions.checkArgument(s2CellIds.length <= 4);
         for (long s2CellId : s2CellIds) {
             Preconditions.checkArgument(S2CellIdUtils.getLevel(s2CellId) == params.mapS2Level);
         }
@@ -233,15 +267,38 @@
     @NonNull
     public double[] readGeoidHeights(@NonNull MapParamsProto params, @NonNull Context context,
             @NonNull long[] s2CellIds) throws IOException {
+        return readMapValues(params, context, s2CellIds, mGeoidHeightCacheTiles);
+    }
+
+    /**
+     * Returns the expiration distances in meters associated with the map cells identified by
+     * {@code s2CellIds}. Throws an {@link IOException} if a geoid height cannot be calculated for
+     * an ID.
+     */
+    @NonNull
+    public double[] readExpirationDistances(@NonNull MapParamsProto params,
+            @NonNull Context context, @NonNull long[] s2CellIds) throws IOException {
+        return readMapValues(params, context, s2CellIds, mExpirationDistanceCacheTiles);
+    }
+
+    /**
+     * Returns the map values in meters associated with the map cells identified by
+     * {@code s2CellIds}. Throws an {@link IOException} if a map value cannot be calculated for an
+     * ID.
+     */
+    @NonNull
+    private static double[] readMapValues(@NonNull MapParamsProto params, @NonNull Context context,
+            @NonNull long[] s2CellIds, @NonNull LruCache<Long, S2TileProto> cacheTiles)
+            throws IOException {
         validate(params, s2CellIds);
-        double[] heightsMeters = new double[s2CellIds.length];
-        if (getGeoidHeights(params, mCacheTiles::get, s2CellIds, heightsMeters)) {
-            return heightsMeters;
+        double[] mapValuesMeters = new double[s2CellIds.length];
+        if (getMapValues(params, cacheTiles::get, s2CellIds, mapValuesMeters)) {
+            return mapValuesMeters;
         }
 
-        TileFunction loadedTiles = loadFromCacheAndDisk(params, context, s2CellIds);
-        if (getGeoidHeights(params, loadedTiles, s2CellIds, heightsMeters)) {
-            return heightsMeters;
+        TileFunction loadedTiles = loadFromCacheAndDisk(params, context, s2CellIds, cacheTiles);
+        if (getMapValues(params, loadedTiles, s2CellIds, mapValuesMeters)) {
+            return mapValuesMeters;
         }
         throw new IOException("Unable to calculate geoid heights from raw assets.");
     }
@@ -255,32 +312,33 @@
     public double[] readGeoidHeights(@NonNull MapParamsProto params, @NonNull long[] s2CellIds) {
         validate(params, s2CellIds);
         double[] heightsMeters = new double[s2CellIds.length];
-        if (getGeoidHeights(params, mCacheTiles::get, s2CellIds, heightsMeters)) {
+        if (getMapValues(params, mGeoidHeightCacheTiles::get, s2CellIds, heightsMeters)) {
             return heightsMeters;
         }
         return null;
     }
 
     /**
-     * Adds to {@code heightsMeters} the geoid heights in meters associated with the map cells
+     * Adds to {@code mapValuesMeters} the map values in meters associated with the map cells
      * identified by {@code s2CellIds}. Returns true if heights are present for all IDs; otherwise,
-     * returns false and adds NaNs for absent heights.
+     * adds NaNs for absent heights and returns false.
      */
-    private boolean getGeoidHeights(@NonNull MapParamsProto params,
+    private static boolean getMapValues(@NonNull MapParamsProto params,
             @NonNull TileFunction tileFunction, @NonNull long[] s2CellIds,
-            @NonNull double[] heightsMeters) {
-        boolean allFound = getUnitIntervalValues(params, tileFunction, s2CellIds, heightsMeters);
-        for (int i = 0; i < heightsMeters.length; i++) {
+            @NonNull double[] mapValuesMeters) {
+        boolean allFound = getUnitIntervalValues(params, tileFunction, s2CellIds, mapValuesMeters);
+        for (int i = 0; i < mapValuesMeters.length; i++) {
             // NaNs are properly preserved.
-            heightsMeters[i] *= params.modelAMeters;
-            heightsMeters[i] += params.modelBMeters;
+            mapValuesMeters[i] *= params.modelAMeters;
+            mapValuesMeters[i] += params.modelBMeters;
         }
         return allFound;
     }
 
     @NonNull
-    private TileFunction loadFromCacheAndDisk(@NonNull MapParamsProto params,
-            @NonNull Context context, @NonNull long[] s2CellIds) throws IOException {
+    private static TileFunction loadFromCacheAndDisk(@NonNull MapParamsProto params,
+            @NonNull Context context, @NonNull long[] s2CellIds,
+            @NonNull LruCache<Long, S2TileProto> cacheTiles) throws IOException {
         int len = s2CellIds.length;
 
         // Enable batch loading by finding all cache keys upfront.
@@ -296,7 +354,7 @@
             if (diskTokens[i] != null) {
                 continue;
             }
-            loadedTiles[i] = mCacheTiles.get(cacheKeys[i]);
+            loadedTiles[i] = cacheTiles.get(cacheKeys[i]);
             diskTokens[i] = getDiskToken(params, cacheKeys[i]);
 
             // Batch across common cache key.
@@ -319,7 +377,7 @@
                     "geoid_height_map/tile-" + diskTokens[i] + ".pb")) {
                 tile = S2TileProto.parseFrom(is.readAllBytes());
             }
-            mergeFromDiskTile(params, tile, cacheKeys, diskTokens, i, loadedTiles);
+            mergeFromDiskTile(params, tile, cacheKeys, diskTokens, i, loadedTiles, cacheTiles);
         }
 
         return cacheKey -> {
@@ -332,9 +390,10 @@
         };
     }
 
-    private void mergeFromDiskTile(@NonNull MapParamsProto params, @NonNull S2TileProto diskTile,
-            @NonNull long[] cacheKeys, @NonNull String[] diskTokens, int diskTokenIndex,
-            @NonNull S2TileProto[] loadedTiles) throws IOException {
+    private static void mergeFromDiskTile(@NonNull MapParamsProto params,
+            @NonNull S2TileProto diskTile, @NonNull long[] cacheKeys, @NonNull String[] diskTokens,
+            int diskTokenIndex, @NonNull S2TileProto[] loadedTiles,
+            @NonNull LruCache<Long, S2TileProto> cacheTiles) throws IOException {
         int len = cacheKeys.length;
         int numMapCellsPerCacheTile = 1 << (2 * (params.mapS2Level - params.cacheTileS2Level));
 
@@ -375,7 +434,7 @@
             }
 
             // Side load into tile cache.
-            mCacheTiles.put(cacheKeys[i], loadedTiles[i]);
+            cacheTiles.put(cacheKeys[i], loadedTiles[i]);
         }
     }
 
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 470a8ac..bfb4b42 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.Manifest;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -43,21 +44,25 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.ReadOnlyBufferException;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
 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.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
+import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
 /**
  MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components.
  It is part of the Android low-level multimedia support infrastructure (normally used together
@@ -1824,6 +1829,7 @@
     private static final String EOS_AND_DECODE_ONLY_ERROR_MESSAGE = "An input buffer cannot have "
             + "both BUFFER_FLAG_END_OF_STREAM and BUFFER_FLAG_DECODE_ONLY flags";
     private static final int CB_CRYPTO_ERROR = 6;
+    private static final int CB_LARGE_FRAME_OUTPUT_AVAILABLE = 7;
 
     private class EventHandler extends Handler {
         private MediaCodec mCodec;
@@ -1945,6 +1951,39 @@
                     break;
                 }
 
+                case CB_LARGE_FRAME_OUTPUT_AVAILABLE:
+                {
+                    int index = msg.arg2;
+                    ArrayDeque<BufferInfo> infos = (ArrayDeque<BufferInfo>)msg.obj;
+                    synchronized(mBufferLock) {
+                        switch (mBufferMode) {
+                            case BUFFER_MODE_LEGACY:
+                                validateOutputByteBuffersLocked(mCachedOutputBuffers,
+                                        index, infos);
+                                break;
+                            case BUFFER_MODE_BLOCK:
+                                while (mOutputFrames.size() <= index) {
+                                    mOutputFrames.add(null);
+                                }
+                                OutputFrame frame = mOutputFrames.get(index);
+                                if (frame == null) {
+                                    frame = new OutputFrame(index);
+                                    mOutputFrames.set(index, frame);
+                                }
+                                frame.setBufferInfos(infos);
+                                frame.setAccessible(true);
+                                break;
+                            default:
+                                throw new IllegalArgumentException(
+                                        "Unrecognized buffer mode: for large frame output");
+                        }
+                    }
+                    mCallback.onOutputBuffersAvailable(
+                            mCodec, index, infos);
+
+                    break;
+                }
+
                 case CB_ERROR:
                 {
                     mCallback.onError(mCodec, (MediaCodec.CodecException) msg.obj);
@@ -2836,11 +2875,72 @@
         }
     }
 
+    /**
+     * Submit multiple access units to the codec along with multiple
+     * {@link MediaCodec.BufferInfo} describing the contents of the buffer. This method
+     * is supported only in asynchronous mode. While this method can be used for all codecs,
+     * it is meant for buffer batching, which is only supported by codecs that advertise
+     * FEATURE_MultipleFrames. Other codecs will not output large output buffers via
+     * onOutputBuffersAvailable, and instead will output single-access-unit output via
+     * onOutputBufferAvailable.
+     * <p>
+     * Output buffer size can be configured using the following MediaFormat keys.
+     * {@link MediaFormat#KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE} and
+     * {@link MediaFormat#KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE}.
+     * Details for each access unit present in the buffer should be described using
+     * {@link MediaCodec.BufferInfo}. Access units must be laid out contiguously (without any gaps)
+     * and in order. Multiple access units in the output if present, will be available in
+     * {@link Callback#onOutputBuffersAvailable} or {@link Callback#onOutputBufferAvailable}
+     * in case of single-access-unit output or when output does not contain any buffers,
+     * such as flags.
+     * <p>
+     * All other details for populating {@link MediaCodec.BufferInfo} is the same as described in
+     * {@link #queueInputBuffer}.
+     *
+     * @param index The index of a client-owned input buffer previously returned
+     *              in a call to {@link #dequeueInputBuffer}.
+     * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
+     *                    contents in the buffer. The ArrayDeque and the BufferInfo objects provided
+     *                    can be recycled by the caller for re-use.
+     * @throws IllegalStateException if not in the Executing state or not in asynchronous mode.
+     * @throws MediaCodec.CodecException upon codec error.
+     * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
+     *                    access units are not contiguous.
+     * @throws CryptoException if a crypto object has been specified in
+     *         {@link #configure}
+     */
+    @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+    public final void queueInputBuffers(
+            int index,
+            @NonNull ArrayDeque<BufferInfo> bufferInfos) {
+        synchronized(mBufferLock) {
+            if (mBufferMode == BUFFER_MODE_BLOCK) {
+                throw new IncompatibleWithBlockModelException("queueInputBuffers() "
+                        + "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+                        + "Please use getQueueRequest() to queue buffers");
+            }
+            invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
+            mDequeuedInputBuffers.remove(index);
+        }
+        try {
+            native_queueInputBuffers(
+                    index, bufferInfos.toArray());
+        } catch (CryptoException | IllegalStateException | IllegalArgumentException e) {
+            revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
+            throw e;
+        }
+    }
+
     private native final void native_queueInputBuffer(
             int index,
             int offset, int size, long presentationTimeUs, int flags)
         throws CryptoException;
 
+    private native final void native_queueInputBuffers(
+            int index,
+            @NonNull Object[] infos)
+        throws CryptoException, CodecException;
+
     public static final int CRYPTO_MODE_UNENCRYPTED = 0;
     public static final int CRYPTO_MODE_AES_CTR     = 1;
     public static final int CRYPTO_MODE_AES_CBC     = 2;
@@ -3464,6 +3564,26 @@
         }
 
         /**
+         * Sets MediaCodec.BufferInfo objects describing the access units
+         * contained in this queue request. Access units must be laid out
+         * contiguously without gaps and in order.
+         *
+         * @param infos Represents {@link MediaCodec.BufferInfo} objects to mark
+         *              individual access-unit boundaries and the timestamps associated with it.
+         *              The buffer is expected to contain the data in a continuous manner.
+         * @return this object
+         */
+        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+        public @NonNull QueueRequest setBufferInfos(@NonNull ArrayDeque<BufferInfo> infos) {
+            if (!isAccessible()) {
+                throw new IllegalStateException("The request is stale");
+            }
+            mBufferInfos.clear();
+            mBufferInfos.addAll(infos);
+            return this;
+        }
+
+        /**
          * Add an integer parameter.
          * See {@link MediaFormat} for an exhaustive list of supported keys with
          * values of type int, that can also be set with {@link MediaFormat#setInteger}.
@@ -3579,10 +3699,18 @@
                 throw new IllegalStateException("No block is set");
             }
             setAccessible(false);
+            if (mBufferInfos.isEmpty()) {
+                BufferInfo info = new BufferInfo();
+                info.size = mSize;
+                info.offset = mOffset;
+                info.presentationTimeUs = mPresentationTimeUs;
+                info.flags = mFlags;
+                mBufferInfos.add(info);
+            }
             if (mLinearBlock != null) {
                 mCodec.native_queueLinearBlock(
-                        mIndex, mLinearBlock, mOffset, mSize, mCryptoInfo,
-                        mPresentationTimeUs, mFlags,
+                        mIndex, mLinearBlock, mCryptoInfo,
+                        mBufferInfos.toArray(),
                         mTuningKeys, mTuningValues);
             } else if (mHardwareBuffer != null) {
                 mCodec.native_queueHardwareBuffer(
@@ -3600,6 +3728,7 @@
             mHardwareBuffer = null;
             mPresentationTimeUs = 0;
             mFlags = 0;
+            mBufferInfos.clear();
             mTuningKeys.clear();
             mTuningValues.clear();
             return this;
@@ -3623,6 +3752,7 @@
         private HardwareBuffer mHardwareBuffer = null;
         private long mPresentationTimeUs = 0;
         private @BufferFlag int mFlags = 0;
+        private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
         private final ArrayList<String> mTuningKeys = new ArrayList<>();
         private final ArrayList<Object> mTuningValues = new ArrayList<>();
 
@@ -3632,11 +3762,8 @@
     private native void native_queueLinearBlock(
             int index,
             @NonNull LinearBlock block,
-            int offset,
-            int size,
             @Nullable CryptoInfo cryptoInfo,
-            long presentationTimeUs,
-            int flags,
+            @NonNull Object[] bufferInfos,
             @NonNull ArrayList<String> keys,
             @NonNull ArrayList<Object> values);
 
@@ -4050,6 +4177,27 @@
         }
     }
 
+    private void validateOutputByteBuffersLocked(
+        @Nullable ByteBuffer[] buffers, int index, @NonNull ArrayDeque<BufferInfo> infoDeque) {
+        Optional<BufferInfo> minInfo = infoDeque.stream().min(
+                (info1, info2) -> Integer.compare(info1.offset, info2.offset));
+        Optional<BufferInfo> maxInfo = infoDeque.stream().max(
+                (info1, info2) -> Integer.compare(info1.offset, info2.offset));
+        if (buffers == null) {
+            if (index >= 0) {
+                mValidOutputIndices.set(index);
+            }
+        } else if (index >= 0 && index < buffers.length) {
+            ByteBuffer buffer = buffers[index];
+            if (buffer != null && minInfo.isPresent() && maxInfo.isPresent()) {
+                buffer.setAccessible(true);
+                buffer.limit(maxInfo.get().offset + maxInfo.get().size);
+                buffer.position(minInfo.get().offset);
+            }
+        }
+
+    }
+
     private void validateOutputByteBufferLocked(
             @Nullable ByteBuffer[] buffers, int index, @NonNull BufferInfo info) {
         if (buffers == null) {
@@ -4407,6 +4555,22 @@
             return mFlags;
         }
 
+        /*
+         * Returns the BufferInfos associated with this OutputFrame. These BufferInfos
+         * describes the access units present in the OutputFrame. Access units are laid
+         * out contiguously without gaps and in order.
+         */
+        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+        public @NonNull ArrayDeque<BufferInfo> getBufferInfos() {
+            if (mBufferInfos.isEmpty()) {
+                // single BufferInfo could be present.
+                BufferInfo bufferInfo = new BufferInfo();
+                bufferInfo.set(0, 0, mPresentationTimeUs, mFlags);
+                mBufferInfos.add(bufferInfo);
+            }
+            return mBufferInfos;
+        }
+
         /**
          * Returns a read-only {@link MediaFormat} for this frame. The returned
          * object is valid only until the client calls {@link MediaCodec#releaseOutputBuffer}.
@@ -4432,6 +4596,7 @@
             mLinearBlock = null;
             mHardwareBuffer = null;
             mFormat = null;
+            mBufferInfos.clear();
             mChangedKeys.clear();
             mKeySet.clear();
             mLoaded = false;
@@ -4450,6 +4615,11 @@
             mFlags = info.flags;
         }
 
+        void setBufferInfos(ArrayDeque<BufferInfo> infos) {
+            mBufferInfos.clear();
+            mBufferInfos.addAll(infos);
+        }
+
         boolean isLoaded() {
             return mLoaded;
         }
@@ -4464,6 +4634,7 @@
         private long mPresentationTimeUs = 0;
         private @BufferFlag int mFlags = 0;
         private MediaFormat mFormat = null;
+        private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
         private final ArrayList<String> mChangedKeys = new ArrayList<>();
         private final Set<String> mKeySet = new HashSet<>();
         private boolean mAccessible = false;
@@ -5172,6 +5343,32 @@
                 @NonNull MediaCodec codec, int index, @NonNull BufferInfo info);
 
         /**
+         * Called when multiple access-units are available in the output.
+         *
+         * @param codec The MediaCodec object.
+         * @param index The index of the available output buffer.
+         * @param infos Infos describing the available output buffer {@link MediaCodec.BufferInfo}.
+         *              Access units present in the output buffer are laid out contiguously
+         *              without gaps and in order.
+         */
+        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+        public void onOutputBuffersAvailable(
+                @NonNull MediaCodec codec, int index, @NonNull ArrayDeque<BufferInfo> infos) {
+            /*
+             * This callback returns multiple BufferInfos when codecs are configured to operate on
+             * large audio frame. Since at this point, we have a single large buffer, returning
+             * each BufferInfo using
+             * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable} may cause the
+             * index to be released to the codec using {@link MediaCodec#releaseOutputBuffer}
+             * before all BuffersInfos can be returned to the client.
+             * Hence this callback is required to be implemented or else an exception is thrown.
+             */
+            throw new IllegalStateException(
+                    "Client must override onOutputBuffersAvailable when codec is " +
+                    "configured to operate with multiple access units");
+        }
+
+        /**
          * Called when the MediaCodec encountered an error
          *
          * @param codec The MediaCodec object.
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 30f4562..80b606c 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -514,7 +514,7 @@
      * The following table summarizes support for specific format keys across android releases.
      * Keys marked with '+:' are required.
      *
-     * <table style="width: 0%">
+     * <table>
      *  <thead>
      *   <tr>
      *    <th rowspan=2>OS Version(s)</th>
@@ -583,7 +583,7 @@
      * <p>
      * The following table summarizes codec support for containers across android releases:
      *
-     * <table style="width: 0%">
+     * <table>
      *  <thead>
      *   <tr>
      *    <th rowspan=2>OS Version(s)</th>
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index aa30748..bdfa6301 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -65,7 +65,8 @@
  *
  * <p>A common case of using MediaRecorder to record audio works as follows:
  *
- * <pre>MediaRecorder recorder = new MediaRecorder();
+ * <pre>
+ * MediaRecorder recorder = new MediaRecorder(context);
  * recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  * recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
  * recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 691aa77..425db06 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -183,23 +183,23 @@
      *       preference} passed by a proxy router. Use {@link RouteDiscoveryPreference#EMPTY} when
      *       setting a route callback.
      *   <li>
-     *       <p>Methods returning non-system {@link RoutingController controllers} always return
-     *       new instances with the latest data. Do not attempt to compare or store them. Instead,
-     *       use {@link #getController(String)} or {@link #getControllers()} to query the most
+     *       <p>Methods returning non-system {@link RoutingController controllers} always return new
+     *       instances with the latest data. Do not attempt to compare or store them. Instead, use
+     *       {@link #getController(String)} or {@link #getControllers()} to query the most
      *       up-to-date state.
      *   <li>
      *       <p>Calls to {@link #setOnGetControllerHintsListener} are ignored.
      * </ul>
      *
      * @param clientPackageName the package name of the app to control
-     * @throws SecurityException if the caller doesn't have {@link
-     *     Manifest.permission#MEDIA_CONTENT_CONTROL MEDIA_CONTENT_CONTROL} permission.
-     * @hide
+     * @return a proxy MediaRouter2 instance if {@code clientPackageName} exists or {@code null}.
      */
-    // TODO (b/311711420): Deprecate once #getInstance(Context, String, UserHandle) reaches public
-    //  SDK.
-    @SystemApi
-    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    @FlaggedApi(FLAG_ENABLE_CROSS_USER_ROUTING_IN_MEDIA_ROUTER2)
+    @RequiresPermission(
+            anyOf = {
+                Manifest.permission.MEDIA_CONTENT_CONTROL,
+                Manifest.permission.MEDIA_ROUTING_CONTROL
+            })
     @Nullable
     public static MediaRouter2 getInstance(
             @NonNull Context context, @NonNull String clientPackageName) {
@@ -226,9 +226,9 @@
      *       {@link RouteDiscoveryPreference.Builder#setPreferredFeatures(List) preferred features}
      *       when setting a route callback.
      *   <li>
-     *       <p>Methods returning non-system {@link RoutingController controllers} always return
-     *       new instances with the latest data. Do not attempt to compare or store them. Instead,
-     *       use {@link #getController(String)} or {@link #getControllers()} to query the most
+     *       <p>Methods returning non-system {@link RoutingController controllers} always return new
+     *       instances with the latest data. Do not attempt to compare or store them. Instead, use
+     *       {@link #getController(String)} or {@link #getControllers()} to query the most
      *       up-to-date state.
      *   <li>
      *       <p>Calls to {@link #setOnGetControllerHintsListener} are ignored.
@@ -242,8 +242,8 @@
      * @throws SecurityException if {@code user} does not match {@link Process#myUserHandle()} and
      *     the caller does not hold {@code Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
      * @throws IllegalArgumentException if {@code clientPackageName} does not exist in {@code user}.
+     * @hide
      */
-    @FlaggedApi(FLAG_ENABLE_CROSS_USER_ROUTING_IN_MEDIA_ROUTER2)
     @RequiresPermission(
             anyOf = {
                 Manifest.permission.MEDIA_CONTENT_CONTROL,
@@ -251,9 +251,7 @@
             })
     @NonNull
     public static MediaRouter2 getInstance(
-            @NonNull Context context,
-            @NonNull String clientPackageName,
-            @NonNull UserHandle user) {
+            @NonNull Context context, @NonNull String clientPackageName, @NonNull UserHandle user) {
         return findOrCreateProxyInstanceForCallingUser(context, clientPackageName, user);
     }
 
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index d28c26d..2202766 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -182,7 +182,7 @@
         mControlHints = src.readBundle();
         mIsSystemSession = src.readBoolean();
         mTransferReason = src.readInt();
-        mTransferInitiatorUserHandle = src.readParcelable(null, android.os.UserHandle.class);
+        mTransferInitiatorUserHandle = UserHandle.readFromParcel(src);
         mTransferInitiatorPackageName = src.readString();
     }
 
@@ -417,11 +417,7 @@
         dest.writeBundle(mControlHints);
         dest.writeBoolean(mIsSystemSession);
         dest.writeInt(mTransferReason);
-        if (mTransferInitiatorUserHandle != null) {
-            mTransferInitiatorUserHandle.writeToParcel(dest, /* flags= */ 0);
-        } else {
-            dest.writeParcelable(null, /* flags= */ 0);
-        }
+        UserHandle.writeToParcel(mTransferInitiatorUserHandle, dest);
         dest.writeString(mTransferInitiatorPackageName);
     }
 
diff --git a/media/java/android/media/flags/editing.aconfig b/media/java/android/media/flags/editing.aconfig
new file mode 100644
index 0000000..c3997e9
--- /dev/null
+++ b/media/java/android/media/flags/editing.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.media.editing.flags"
+
+flag {
+  name: "add_media_metrics_editing"
+  namespace: "media_solutions"
+  description: "Add media metrics for transcoding/editing events."
+  bug: "297487694"
+}
diff --git a/core/java/android/credentials/ui/UiResult.java b/media/java/android/media/metrics/EditingEndedEvent.aidl
similarity index 81%
rename from core/java/android/credentials/ui/UiResult.java
rename to media/java/android/media/metrics/EditingEndedEvent.aidl
index 692584d..e099dea 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/media/java/android/media/metrics/EditingEndedEvent.aidl
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package android.media.metrics;
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+parcelable EditingEndedEvent;
diff --git a/media/java/android/media/metrics/EditingEndedEvent.java b/media/java/android/media/metrics/EditingEndedEvent.java
new file mode 100644
index 0000000..72e6db8
--- /dev/null
+++ b/media/java/android/media/metrics/EditingEndedEvent.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.metrics;
+
+import static com.android.media.editing.flags.Flags.FLAG_ADD_MEDIA_METRICS_EDITING;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.util.Objects;
+
+/** Event for an editing operation having ended. */
+@FlaggedApi(FLAG_ADD_MEDIA_METRICS_EDITING)
+public final class EditingEndedEvent extends Event implements Parcelable {
+
+    // The special value 0 is reserved for the field being unspecified in the proto.
+
+    /** The editing operation was successful. */
+    public static final int FINAL_STATE_SUCCEEDED = 1;
+
+    /** The editing operation was canceled. */
+    public static final int FINAL_STATE_CANCELED = 2;
+
+    /** The editing operation failed due to an error. */
+    public static final int FINAL_STATE_ERROR = 3;
+
+    /** @hide */
+    @IntDef(
+            prefix = {"FINAL_STATE_"},
+            value = {
+                FINAL_STATE_SUCCEEDED,
+                FINAL_STATE_CANCELED,
+                FINAL_STATE_ERROR,
+            })
+    @Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    public @interface FinalState {}
+
+    private final @FinalState int mFinalState;
+
+    // The special value 0 is reserved for the field being unspecified in the proto.
+
+    /** Special value representing that no error occurred. */
+    public static final int ERROR_CODE_NONE = 1;
+
+    /** Error code for unexpected runtime errors. */
+    public static final int ERROR_CODE_FAILED_RUNTIME_CHECK = 2;
+
+    /** Error code for non-specific errors during input/output. */
+    public static final int ERROR_CODE_IO_UNSPECIFIED = 3;
+
+    /** Error code for network connection failures. */
+    public static final int ERROR_CODE_IO_NETWORK_CONNECTION_FAILED = 4;
+
+    /** Error code for network timeouts. */
+    public static final int ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT = 5;
+
+    /** Caused by an HTTP server returning an unexpected HTTP response status code. */
+    public static final int ERROR_CODE_IO_BAD_HTTP_STATUS = 6;
+
+    /** Caused by a non-existent file. */
+    public static final int ERROR_CODE_IO_FILE_NOT_FOUND = 7;
+
+    /**
+     * Caused by lack of permission to perform an IO operation. For example, lack of permission to
+     * access internet or external storage.
+     */
+    public static final int ERROR_CODE_IO_NO_PERMISSION = 8;
+
+    /** */
+    public static final int ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED = 9;
+
+    /** Caused by reading data out of the data bounds. */
+    public static final int ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE = 10;
+
+    /** Caused by a decoder initialization failure. */
+    public static final int ERROR_CODE_DECODER_INIT_FAILED = 11;
+
+    /** Caused by a failure while trying to decode media samples. */
+    public static final int ERROR_CODE_DECODING_FAILED = 12;
+
+    /** Caused by trying to decode content whose format is not supported. */
+    public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 13;
+
+    /** Caused by an encoder initialization failure. */
+    public static final int ERROR_CODE_ENCODER_INIT_FAILED = 14;
+
+    /** Caused by a failure while trying to encode media samples. */
+    public static final int ERROR_CODE_ENCODING_FAILED = 15;
+
+    /** Caused by trying to encode content whose format is not supported. */
+    public static final int ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED = 16;
+
+    /** Caused by a video frame processing failure. */
+    public static final int ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED = 17;
+
+    /** Caused by an audio processing failure. */
+    public static final int ERROR_CODE_AUDIO_PROCESSING_FAILED = 18;
+
+    /** Caused by a failure while muxing media samples. */
+    public static final int ERROR_CODE_MUXING_FAILED = 19;
+
+    /** @hide */
+    @IntDef(
+            prefix = {"ERROR_CODE_"},
+            value = {
+                ERROR_CODE_NONE,
+                ERROR_CODE_FAILED_RUNTIME_CHECK,
+                ERROR_CODE_IO_UNSPECIFIED,
+                ERROR_CODE_IO_NETWORK_CONNECTION_FAILED,
+                ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT,
+                ERROR_CODE_IO_BAD_HTTP_STATUS,
+                ERROR_CODE_IO_FILE_NOT_FOUND,
+                ERROR_CODE_IO_NO_PERMISSION,
+                ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED,
+                ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE,
+                ERROR_CODE_DECODER_INIT_FAILED,
+                ERROR_CODE_DECODING_FAILED,
+                ERROR_CODE_DECODING_FORMAT_UNSUPPORTED,
+                ERROR_CODE_ENCODER_INIT_FAILED,
+                ERROR_CODE_ENCODING_FAILED,
+                ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED,
+                ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED,
+                ERROR_CODE_AUDIO_PROCESSING_FAILED,
+                ERROR_CODE_MUXING_FAILED,
+            })
+    @Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    public @interface ErrorCode {}
+
+    private final @ErrorCode int mErrorCode;
+    @SuppressWarnings("HidingField") // Hiding field from superclass as for playback events.
+    private final long mTimeSinceCreatedMillis;
+
+    private EditingEndedEvent(
+            @FinalState int finalState,
+            @ErrorCode int errorCode,
+            long timeSinceCreatedMillis,
+            @NonNull Bundle extras) {
+        mFinalState = finalState;
+        mErrorCode = errorCode;
+        mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+        mMetricsBundle = extras.deepCopy();
+    }
+
+    /** Returns the state of the editing session when it ended. */
+    @FinalState
+    public int getFinalState() {
+        return mFinalState;
+    }
+
+    /** Returns the error code for a {@linkplain #FINAL_STATE_ERROR failed} editing session. */
+    @ErrorCode
+    public int getErrorCode() {
+        return mErrorCode;
+    }
+
+    /**
+     * Gets the elapsed time since creating of the editing session, in milliseconds, or -1 if
+     * unknown.
+     *
+     * @return The elapsed time since creating the editing session, in milliseconds, or -1 if
+     *     unknown.
+     * @see LogSessionId
+     * @see EditingSession
+     */
+    @Override
+    @IntRange(from = -1)
+    public long getTimeSinceCreatedMillis() {
+        return mTimeSinceCreatedMillis;
+    }
+
+    /**
+     * Gets metrics-related information that is not supported by dedicated methods.
+     *
+     * <p>It is intended to be used for backwards compatibility by the metrics infrastructure.
+     */
+    @Override
+    @NonNull
+    public Bundle getMetricsBundle() {
+        return mMetricsBundle;
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+        return "PlaybackErrorEvent { "
+                + "finalState = "
+                + mFinalState
+                + ", "
+                + "errorCode = "
+                + mErrorCode
+                + ", "
+                + "timeSinceCreatedMillis = "
+                + mTimeSinceCreatedMillis
+                + " }";
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        EditingEndedEvent that = (EditingEndedEvent) o;
+        return mFinalState == that.mFinalState
+                && mErrorCode == that.mErrorCode
+                && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mFinalState, mErrorCode, mTimeSinceCreatedMillis);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mFinalState);
+        dest.writeInt(mErrorCode);
+        dest.writeLong(mTimeSinceCreatedMillis);
+        dest.writeBundle(mMetricsBundle);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    private EditingEndedEvent(@NonNull Parcel in) {
+        int finalState = in.readInt();
+        int errorCode = in.readInt();
+        long timeSinceCreatedMillis = in.readLong();
+        Bundle metricsBundle = in.readBundle();
+
+        mFinalState = finalState;
+        mErrorCode = errorCode;
+        mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+        mMetricsBundle = metricsBundle;
+    }
+
+    public static final @NonNull Creator<EditingEndedEvent> CREATOR =
+            new Creator<>() {
+                @Override
+                public EditingEndedEvent[] newArray(int size) {
+                    return new EditingEndedEvent[size];
+                }
+
+                @Override
+                public EditingEndedEvent createFromParcel(@NonNull Parcel in) {
+                    return new EditingEndedEvent(in);
+                }
+            };
+
+    /** Builder for {@link EditingEndedEvent} */
+    @FlaggedApi(FLAG_ADD_MEDIA_METRICS_EDITING)
+    public static final class Builder {
+        private final @FinalState int mFinalState;
+        private @ErrorCode int mErrorCode;
+        private long mTimeSinceCreatedMillis;
+        private Bundle mMetricsBundle;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param finalState The state of the editing session when it ended.
+         */
+        public Builder(@FinalState int finalState) {
+            mFinalState = finalState;
+            mErrorCode = ERROR_CODE_NONE;
+            mTimeSinceCreatedMillis = -1;
+            mMetricsBundle = new Bundle();
+        }
+
+        /**
+         * Sets the elapsed time since creating the editing session, in milliseconds.
+         *
+         * @param timeSinceCreatedMillis The elapsed time since creating the editing session, in
+         *     milliseconds, or -1 if the value is unknown.
+         * @see #getTimeSinceCreatedMillis()
+         */
+        public @NonNull Builder setTimeSinceCreatedMillis(
+                @IntRange(from = -1) long timeSinceCreatedMillis) {
+            mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+            return this;
+        }
+
+        /** Sets the error code for a {@linkplain #FINAL_STATE_ERROR failed} editing session. */
+        public @NonNull Builder setErrorCode(@ErrorCode int value) {
+            mErrorCode = value;
+            return this;
+        }
+
+        /**
+         * Sets metrics-related information that is not supported by dedicated methods.
+         *
+         * <p>Used for backwards compatibility by the metrics infrastructure.
+         */
+        public @NonNull Builder setMetricsBundle(@NonNull Bundle metricsBundle) {
+            mMetricsBundle = metricsBundle;
+            return this;
+        }
+
+        /** Builds an instance. */
+        public @NonNull EditingEndedEvent build() {
+            return new EditingEndedEvent(
+                    mFinalState, mErrorCode, mTimeSinceCreatedMillis, mMetricsBundle);
+        }
+    }
+}
diff --git a/media/java/android/media/metrics/EditingSession.java b/media/java/android/media/metrics/EditingSession.java
index 2ddf623b..964e12c 100644
--- a/media/java/android/media/metrics/EditingSession.java
+++ b/media/java/android/media/metrics/EditingSession.java
@@ -16,6 +16,9 @@
 
 package android.media.metrics;
 
+import static com.android.media.editing.flags.Flags.FLAG_ADD_MEDIA_METRICS_EDITING;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
@@ -24,7 +27,8 @@
 import java.util.Objects;
 
 /**
- * An instances of this class represents a session of media editing.
+ * Represents a session of media editing, for example, transcoding between formats, transmuxing or
+ * applying trimming or audio/video effects to a stream.
  */
 public final class EditingSession implements AutoCloseable {
     private final @NonNull String mId;
@@ -40,6 +44,13 @@
         mLogSessionId = new LogSessionId(mId);
     }
 
+    /** Reports that an editing operation ended. */
+    @FlaggedApi(FLAG_ADD_MEDIA_METRICS_EDITING)
+    public void reportEditingEndedEvent(@NonNull EditingEndedEvent editingEndedEvent) {
+        mManager.reportEditingEndedEvent(mId, editingEndedEvent);
+    }
+
+    /** Returns the identifier for logging this session. */
     public @NonNull LogSessionId getSessionId() {
         return mLogSessionId;
     }
diff --git a/media/java/android/media/metrics/IMediaMetricsManager.aidl b/media/java/android/media/metrics/IMediaMetricsManager.aidl
index 51b1cc2..e07ca67 100644
--- a/media/java/android/media/metrics/IMediaMetricsManager.aidl
+++ b/media/java/android/media/metrics/IMediaMetricsManager.aidl
@@ -16,6 +16,7 @@
 
 package android.media.metrics;
 
+import android.media.metrics.EditingEndedEvent;
 import android.media.metrics.NetworkEvent;
 import android.media.metrics.PlaybackErrorEvent;
 import android.media.metrics.PlaybackMetrics;
@@ -24,7 +25,7 @@
 import android.os.PersistableBundle;
 
 /**
- * Interface to the playback manager service.
+ * Interface to the media metrics manager service.
  * @hide
  */
 interface IMediaMetricsManager {
@@ -37,6 +38,8 @@
     void reportPlaybackStateEvent(in String sessionId, in PlaybackStateEvent event, int userId);
     void reportTrackChangeEvent(in String sessionId, in TrackChangeEvent event, int userId);
 
+    void reportEditingEndedEvent(in String sessionId, in EditingEndedEvent event, int userId);
+
     String getTranscodingSessionId(int userId);
     String getEditingSessionId(int userId);
     String getBundleSessionId(int userId);
diff --git a/media/java/android/media/metrics/MediaMetricsManager.java b/media/java/android/media/metrics/MediaMetricsManager.java
index 0898874..622b0c1 100644
--- a/media/java/android/media/metrics/MediaMetricsManager.java
+++ b/media/java/android/media/metrics/MediaMetricsManager.java
@@ -193,4 +193,18 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Reports the event of an editing session ending.
+     *
+     * @hide
+     */
+    public void reportEditingEndedEvent(
+            @NonNull String sessionId, EditingEndedEvent editingEndedEvent) {
+        try {
+            mService.reportEditingEndedEvent(sessionId, editingEndedEvent, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 388b2c5..2fb0af5 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -18,6 +18,7 @@
 
 import android.media.projection.IMediaProjectionCallback;
 import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
 
 /** {@hide} */
 interface IMediaProjection {
@@ -38,22 +39,22 @@
     void unregisterCallback(IMediaProjectionCallback callback);
 
     /**
-     * Returns the {@link android.os.IBinder} identifying the task to record, or {@code null} if
+     * Returns the {@link LaunchCookie} identifying the task to record, or {@code null} if
      * there is none.
      */
     @EnforcePermission("MANAGE_MEDIA_PROJECTION")
     @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
             + ".permission.MANAGE_MEDIA_PROJECTION)")
-    IBinder getLaunchCookie();
+    LaunchCookie getLaunchCookie();
 
     /**
-     * Updates the {@link android.os.IBinder} identifying the task to record, or {@code null} if
+     * Updates the {@link LaunchCookie} identifying the task to record, or {@code null} if
      * there is none.
      */
     @EnforcePermission("MANAGE_MEDIA_PROJECTION")
     @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
             + ".permission.MANAGE_MEDIA_PROJECTION)")
-    void setLaunchCookie(in IBinder launchCookie);
+    void setLaunchCookie(in LaunchCookie launchCookie);
 
     /**
      * Returns {@code true} if this token is still valid. A token is valid as long as the token
diff --git a/media/java/android/media/projection/MediaProjectionInfo.java b/media/java/android/media/projection/MediaProjectionInfo.java
index c820392..cd0763d 100644
--- a/media/java/android/media/projection/MediaProjectionInfo.java
+++ b/media/java/android/media/projection/MediaProjectionInfo.java
@@ -16,7 +16,7 @@
 
 package android.media.projection;
 
-import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
@@ -27,9 +27,9 @@
 public final class MediaProjectionInfo implements Parcelable {
     private final String mPackageName;
     private final UserHandle mUserHandle;
-    private final IBinder mLaunchCookie;
+    private final LaunchCookie mLaunchCookie;
 
-    public MediaProjectionInfo(String packageName, UserHandle handle, IBinder launchCookie) {
+    public MediaProjectionInfo(String packageName, UserHandle handle, LaunchCookie launchCookie) {
         mPackageName = packageName;
         mUserHandle = handle;
         mLaunchCookie = launchCookie;
@@ -38,7 +38,7 @@
     public MediaProjectionInfo(Parcel in) {
         mPackageName = in.readString();
         mUserHandle = UserHandle.readFromParcel(in);
-        mLaunchCookie = in.readStrongBinder();
+        mLaunchCookie = LaunchCookie.readFromParcel(in);
     }
 
     public String getPackageName() {
@@ -49,7 +49,7 @@
         return mUserHandle;
     }
 
-    public IBinder getLaunchCookie() {
+    public LaunchCookie getLaunchCookie() {
         return mLaunchCookie;
     }
 
@@ -72,7 +72,7 @@
     public String toString() {
         return "MediaProjectionInfo{mPackageName="
             + mPackageName + ", mUserHandle="
-            + mUserHandle + ", mLaunchCookie"
+            + mUserHandle + ", mLaunchCookie="
             + mLaunchCookie + "}";
     }
 
@@ -85,7 +85,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mPackageName);
         UserHandle.writeToParcel(mUserHandle, out);
-        out.writeStrongBinder(mLaunchCookie);
+        LaunchCookie.writeToParcel(mLaunchCookie, out);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<MediaProjectionInfo> CREATOR =
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index 9790d02..e3290d6 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -18,8 +18,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.app.Activity;
+import android.app.ActivityOptions.LaunchCookie;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -73,6 +76,9 @@
     /** @hide */
     public static final String EXTRA_MEDIA_PROJECTION =
             "android.media.projection.extra.EXTRA_MEDIA_PROJECTION";
+    /** @hide */
+    public static final String EXTRA_LAUNCH_COOKIE =
+            "android.media.projection.extra.EXTRA_LAUNCH_COOKIE";
 
     /** @hide */
     public static final int TYPE_SCREEN_CAPTURE = 0;
@@ -158,17 +164,29 @@
      */
     @NonNull
     public Intent createScreenCaptureIntent(@NonNull MediaProjectionConfig config) {
-        Intent i = new Intent();
-        final ComponentName mediaProjectionPermissionDialogComponent =
-                ComponentName.unflattenFromString(mContext.getResources()
-                        .getString(com.android.internal.R.string
-                                .config_mediaProjectionPermissionDialogComponent));
-        i.setComponent(mediaProjectionPermissionDialogComponent);
+        Intent i = createScreenCaptureIntent();
         i.putExtra(EXTRA_MEDIA_PROJECTION_CONFIG, config);
         return i;
     }
 
     /**
+     * Returns an intent similar to {@link #createScreenCaptureIntent()} that will enable screen
+     * recording of the task with the specified launch cookie. This method should only be used for
+     * testing.
+     *
+     * @param launchCookie the launch cookie corresponding to the task to record.
+     * @hide
+     */
+    @SuppressLint("UnflaggedApi")
+    @TestApi
+    @NonNull
+    public Intent createScreenCaptureIntent(@Nullable LaunchCookie launchCookie) {
+        Intent i = createScreenCaptureIntent();
+        i.putExtra(EXTRA_LAUNCH_COOKIE, launchCookie);
+        return i;
+    }
+
+    /**
      * Retrieves the {@link MediaProjection} obtained from a successful screen
      * capture request. The result code and data from the request are provided by overriding
      * {@link Activity#onActivityResult(int, int, Intent) onActivityResult(int, int, Intent)},
diff --git a/media/java/android/media/tv/SignalingDataRequest.aidl b/media/java/android/media/tv/SignalingDataRequest.aidl
new file mode 100644
index 0000000..29e89fe
--- /dev/null
+++ b/media/java/android/media/tv/SignalingDataRequest.aidl
@@ -0,0 +1,3 @@
+package android.media.tv;
+
+parcelable SignalingDataRequest;
diff --git a/media/java/android/media/tv/SignalingDataRequest.java b/media/java/android/media/tv/SignalingDataRequest.java
new file mode 100644
index 0000000..dcf1d48
--- /dev/null
+++ b/media/java/android/media/tv/SignalingDataRequest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+
+/**
+ * Request to retrieve the Low-level Signalling Tables (LLS) and Service-layer Signalling (SLS)
+ * metadata.
+ *
+ * <p>For more details on each type of metadata that can be requested, refer to the ATSC standard
+ * A/344:2023-5 9.2.10 - Query Signaling Data API.
+ *
+ * @hide
+ */
+public class SignalingDataRequest extends BroadcastInfoRequest implements Parcelable {
+    private static final @TvInputManager.BroadcastInfoType int REQUEST_TYPE =
+            TvInputManager.BROADCAST_INFO_TYPE_SIGNALING_DATA;
+
+    public static final @NonNull Parcelable.Creator<SignalingDataRequest> CREATOR =
+            new Parcelable.Creator<SignalingDataRequest>() {
+                @Override
+                public SignalingDataRequest[] newArray(int size) {
+                    return new SignalingDataRequest[size];
+                }
+
+                @Override
+                public SignalingDataRequest createFromParcel(@NonNull android.os.Parcel in) {
+                    return new SignalingDataRequest(in);
+                }
+            };
+
+    /** SLS Metadata: All metadata objects for the requested service(s) */
+    public static final int SLS_METADATA_ALL = 0x7FFFFFF;
+
+    /** SLS Metadata: APD for the requested service(s) */
+    public static final int SLS_METADATA_APD = 1;
+
+    /** SLS Metadata: USBD for the requested service(s) */
+    public static final int SLS_METADATA_USBD = 1 << 1;
+
+    /** SLS Metadata: S-TSID for the requested service(s) */
+    public static final int SLS_METADATA_STSID = 1 << 2;
+
+    /** SLS Metadata: DASH MPD for the requested service(s) */
+    public static final int SLS_METADATA_MPD = 1 << 3;
+
+    /** SLS Metadata: User Service Description for MMTP */
+    public static final int SLS_METADATA_USD = 1 << 4;
+
+    /** SLS Metadata: MMT Package Access Table for the requested service(s) */
+    public static final int SLS_METADATA_PAT = 1 << 5;
+
+    /** SLS Metadata: MMT Package Table for the requested service(s) */
+    public static final int SLS_METADATA_MPT = 1 << 6;
+
+    /** SLS Metadata: MMT Media Presentation Information Table for the requested service(s) */
+    public static final int SLS_METADATA_MPIT = 1 << 7;
+
+    /** SLS Metadata: MMT Clock Relation Information for the requested service(s) */
+    public static final int SLS_METADATA_CRIT = 1 << 8;
+
+    /** SLS Metadata: MMT Device Capabilities Information Table for the requested service(s) */
+    public static final int SLS_METADATA_DCIT = 1 << 9;
+
+    /** SLS Metadata: HTML Entry Pages Location Description for the requested service(s) */
+    public static final int SLS_METADATA_HELD = 1 << 10;
+
+    /** SLS Metadata: Distribution Window Desciription for the requested service(s) */
+    public static final int SLS_METADATA_DWD = 1 << 11;
+
+    /** SLS Metadata: MMT Application Event Information for the requested service(s) */
+    public static final int SLS_METADATA_AEI = 1 << 12;
+
+    /** SLS Metadata: Video Stream Properties Descriptor */
+    public static final int SLS_METADATA_VSPD = 1 << 13;
+
+    /** SLS Metadata: ATSC Staggercast Descriptor */
+    public static final int SLS_METADATA_ASD = 1 << 14;
+
+    /** SLS Metadata: Inband Event Descriptor */
+    public static final int SLS_METADATA_IED = 1 << 15;
+
+    /** SLS Metadata: Caption Asset Descriptor */
+    public static final int SLS_METADATA_CAD = 1 << 16;
+
+    /** SLS Metadata: Audio Stream Properties Descriptor */
+    public static final int SLS_METADATA_ASPD = 1 << 17;
+
+    /** SLS Metadata: Security Properties Descriptor */
+    public static final int SLS_METADATA_SSD = 1 << 18;
+
+    /** SLS Metadata: ROUTE/DASH Application Dynamic Event for the requested service(s) */
+    public static final int SLS_METADATA_EMSG = 1 << 19;
+
+    /** SLS Metadata: MMT Application Dynamic Event for the requested service(s) */
+    public static final int SLS_METADATA_EVTI = 1 << 20;
+
+    /** Regional Service Availability Table for the requested service(s) */
+    public static final int SLS_METADATA_RSAT = 1 << 21;
+
+    private final int mGroup;
+    private @NonNull final int[] mLlsTableIds;
+    private final int mSlsMetadataTypes;
+
+    SignalingDataRequest(
+            int requestId,
+            int option,
+            int group,
+            @NonNull int[] llsTableIds,
+            int slsMetadataTypes) {
+        super(REQUEST_TYPE, requestId, option);
+        mGroup = group;
+        mLlsTableIds = llsTableIds;
+        mSlsMetadataTypes = slsMetadataTypes;
+    }
+
+    SignalingDataRequest(@NonNull android.os.Parcel in) {
+        super(REQUEST_TYPE, in);
+
+        int group = in.readInt();
+        int[] llsTableIds = in.createIntArray();
+        int slsMetadataTypes = in.readInt();
+
+        this.mGroup = group;
+        this.mLlsTableIds = llsTableIds;
+        com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, mLlsTableIds);
+        this.mSlsMetadataTypes = slsMetadataTypes;
+    }
+
+    public int getGroup() {
+        return mGroup;
+    }
+
+    public @NonNull int[] getLlsTableIds() {
+        return mLlsTableIds;
+    }
+
+    public int getSlsMetadataTypes() {
+        return mSlsMetadataTypes;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mGroup);
+        dest.writeIntArray(mLlsTableIds);
+        dest.writeInt(mSlsMetadataTypes);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 2b31bfe..be1b675 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -489,10 +489,19 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "BROADCAST_INFO_TYPE_", value =
-            {BROADCAST_INFO_TYPE_TS, BROADCAST_INFO_TYPE_TABLE, BROADCAST_INFO_TYPE_SECTION,
-            BROADCAST_INFO_TYPE_PES, BROADCAST_INFO_STREAM_EVENT, BROADCAST_INFO_TYPE_DSMCC,
-            BROADCAST_INFO_TYPE_COMMAND, BROADCAST_INFO_TYPE_TIMELINE})
+    @IntDef(
+            prefix = "BROADCAST_INFO_TYPE_",
+            value = {
+                BROADCAST_INFO_TYPE_TS,
+                BROADCAST_INFO_TYPE_TABLE,
+                BROADCAST_INFO_TYPE_SECTION,
+                BROADCAST_INFO_TYPE_PES,
+                BROADCAST_INFO_STREAM_EVENT,
+                BROADCAST_INFO_TYPE_DSMCC,
+                BROADCAST_INFO_TYPE_COMMAND,
+                BROADCAST_INFO_TYPE_TIMELINE,
+                BROADCAST_INFO_TYPE_SIGNALING_DATA
+            })
     public @interface BroadcastInfoType {}
 
     public static final int BROADCAST_INFO_TYPE_TS = 1;
@@ -505,6 +514,9 @@
     public static final int BROADCAST_INFO_TYPE_TIMELINE = 8;
 
     /** @hide */
+    public static final int BROADCAST_INFO_TYPE_SIGNALING_DATA = 9;
+
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "SIGNAL_STRENGTH_",
             value = {SIGNAL_STRENGTH_LOST, SIGNAL_STRENGTH_WEAK, SIGNAL_STRENGTH_STRONG})
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index e3dba03..1404d7c 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -61,7 +61,10 @@
     void onSetTvRecordingInfo(in String recordingId, in TvRecordingInfo recordingInfo, int seq);
     void onRequestTvRecordingInfo(in String recordingId, int seq);
     void onRequestTvRecordingInfoList(in int type, int seq);
-    void onRequestSigning(
-            in String id, in String algorithm, in String alias, in byte[] data, int seq);
+    void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data,
+            int seq);
+    void onRequestSigning2(in String id, in String algorithm, in String host,
+            int port, in byte[] data, int seq);
+    void onRequestCertificate(in String host, int port, int seq);
     void onAdRequest(in AdRequest request, int Seq);
 }
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index 0f58b29..1b9450b 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -58,6 +58,8 @@
     void sendAvailableSpeeds(in IBinder sessionToken, in float[] speeds, int userId);
     void sendSigningResult(in IBinder sessionToken, in String signingId, in byte[] result,
             int userId);
+    void sendCertificate(in IBinder sessionToken, in String host, int port,
+            in Bundle certBundle, int userId);
     void sendTvRecordingInfo(in IBinder sessionToken, in TvRecordingInfo recordingInfo, int userId);
     void sendTvRecordingInfoList(in IBinder sessionToken,
             in List<TvRecordingInfo> recordingInfoList, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index 06808c9..3969315 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -49,6 +49,7 @@
     void sendTimeShiftMode(int mode);
     void sendAvailableSpeeds(in float[] speeds);
     void sendSigningResult(in String signingId, in byte[] result);
+    void sendCertificate(in String host, int port, in Bundle certBundle);
     void sendTvRecordingInfo(in TvRecordingInfo recordingInfo);
     void sendTvRecordingInfoList(in List<TvRecordingInfo> recordingInfoList);
     void notifyError(in String errMsg, in Bundle params);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index 416b8f1..3c91a3e 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -61,5 +61,7 @@
     void onRequestTvRecordingInfo(in String recordingId);
     void onRequestTvRecordingInfoList(in int type);
     void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data);
+    void onRequestSigning2(in String id, in String algorithm, in String host, int port, in byte[] data);
+    void onRequestCertificate(in String host, int port);
     void onAdRequest(in AdRequest request);
 }
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index 77730aa..ec6c2bf 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -104,6 +104,7 @@
     private static final int DO_SEND_AVAILABLE_SPEEDS = 47;
     private static final int DO_SEND_SELECTED_TRACK_INFO = 48;
     private static final int DO_NOTIFY_VIDEO_FREEZE_UPDATED = 49;
+    private static final int DO_SEND_CERTIFICATE = 50;
 
     private final HandlerCaller mCaller;
     private Session mSessionImpl;
@@ -369,6 +370,13 @@
                 mSessionImpl.notifyVideoFreezeUpdated((Boolean) msg.obj);
                 break;
             }
+            case DO_SEND_CERTIFICATE: {
+                SomeArgs args = (SomeArgs) msg.obj;
+                mSessionImpl.sendCertificate((String) args.arg1, (Integer) args.arg2,
+                        (Bundle) args.arg3);
+                args.recycle();
+                break;
+            }
             default: {
                 Log.w(TAG, "Unhandled message code: " + msg.what);
                 break;
@@ -483,6 +491,12 @@
     }
 
     @Override
+    public void sendCertificate(@NonNull String host, int port, @NonNull Bundle certBundle) {
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageOOO(DO_SEND_CERTIFICATE, host, port, certBundle));
+    }
+
+    @Override
     public void notifyError(@NonNull String errMsg, @NonNull Bundle params) {
         mCaller.executeOrSendMessage(
                 mCaller.obtainMessageOO(DO_NOTIFY_ERROR, errMsg, params));
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 8a340f6..498eec6 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -34,6 +34,7 @@
 import android.media.tv.TvRecordingInfo;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
+import android.net.http.SslCertificate;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -656,6 +657,31 @@
             }
 
             @Override
+            public void onRequestSigning2(
+                    String id, String algorithm, String host, int port, byte[] data, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestSigning(id, algorithm, host, port, data);
+                }
+            }
+
+            @Override
+            public void onRequestCertificate(String host, int port, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestCertificate(host, port);
+                }
+            }
+
+            @Override
             public void onSessionStateChanged(int state, int err, int seq) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -1328,6 +1354,19 @@
             }
         }
 
+        void sendCertificate(@NonNull String host, int port, @NonNull SslCertificate cert) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.sendCertificate(mToken, host, port, SslCertificate.saveState(cert),
+                        mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         void notifyError(@NonNull String errMsg, @NonNull Bundle params) {
             if (mToken == null) {
                 Log.w(TAG, "The session has been already released");
@@ -2232,6 +2271,26 @@
             });
         }
 
+        void postRequestSigning(String id, String algorithm, String host, int port,
+                byte[] data) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRequestSigning(mSession, id, algorithm, host,
+                            port, data);
+                }
+            });
+        }
+
+        void postRequestCertificate(String host, int port) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRequestCertificate(mSession, host, port);
+                }
+            });
+        }
+
         void postRequestTvRecordingInfo(String recordingId) {
             mHandler.post(new Runnable() {
                 @Override
@@ -2574,6 +2633,36 @@
         }
 
         /**
+         * This is called when
+         * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, int, byte[])} is
+         * called.
+         *
+         * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
+         * @param signingId the ID to identify the request.
+         * @param algorithm the standard name of the signature algorithm requested, such as
+         *                  MD5withRSA, SHA256withDSA, etc.
+         * @param host The host of the SSL CLient Authentication Server
+         * @param port The port of the SSL Client Authentication Server
+         * @param data the original bytes to be signed.
+         * @hide
+         */
+        public void onRequestSigning(
+                Session session, String signingId, String algorithm, String host,
+                int port, byte[] data) {
+        }
+
+        /**
+         * This is called when the service requests a SSL certificate for client validation.
+         *
+         * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
+         * @param host the host name of the SSL authentication server.
+         * @param port the port of the SSL authentication server. E.g., 443
+         * @hide
+         */
+        public void onRequestCertificate(Session session, String host, int port) {
+        }
+
+        /**
          * This is called when {@link TvInteractiveAppService.Session#notifySessionStateChanged} is
          * called.
          *
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 5247a0e..7b6dc38 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -46,6 +46,7 @@
 import android.media.tv.TvView;
 import android.media.tv.interactive.TvInteractiveAppView.TvInteractiveAppCallback;
 import android.net.Uri;
+import android.net.http.SslCertificate;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -734,6 +735,17 @@
         }
 
         /**
+         * Receives the requested Certificate
+         *
+         * @param host the host name of the SSL authentication server.
+         * @param port the port of the SSL authentication server. E.g., 443
+         * @param cert the SSL certificate received.
+         * @hide
+         */
+        public void onCertificate(@NonNull String host, int port, @NonNull SslCertificate cert) {
+        }
+
+        /**
          * Called when the application sends information of an error.
          *
          * @param errMsg the message of the error.
@@ -1633,6 +1645,76 @@
         }
 
         /**
+         * Requests signing of the given data.
+         *
+         * <p>This is used when the corresponding server of the broadcast-independent interactive
+         * app requires signing during handshaking, and the interactive app service doesn't have
+         * the built-in private key. The private key is provided by the content providers and
+         * pre-built in the related app, such as TV app.
+         *
+         * @param signingId the ID to identify the request. When a result is received, this ID can
+         *                  be used to correlate the result with the request.
+         * @param algorithm the standard name of the signature algorithm requested, such as
+         *                  MD5withRSA, SHA256withDSA, etc. The name is from standards like
+         *                  FIPS PUB 186-4 and PKCS #1.
+         * @param host the host of the SSL client authentication server.
+         * @param port the port of the SSL client authentication server.
+         * @param data the original bytes to be signed.
+         *
+         * @see #onSigningResult(String, byte[])
+         * @see TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+         * @see TvInteractiveAppView#BI_INTERACTIVE_APP_KEY_ALIAS
+         * @hide
+         */
+        @CallSuper
+        public void requestSigning(@NonNull String signingId, @NonNull String algorithm,
+                @NonNull String host, int port, @NonNull byte[] data) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestSigning");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRequestSigning2(signingId, algorithm,
+                                    host, port, data);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestSigning", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Requests a SSL certificate for client validation.
+         *
+         * @param host the host name of the SSL authentication server.
+         * @param port the port of the SSL authentication server. E.g., 443
+         * @hide
+         */
+        public void requestCertificate(@NonNull String host, int port) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestCertificate");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRequestCertificate(host, port);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestCertificate", e);
+                    }
+                }
+            });
+        }
+
+        /**
          * Sends an advertisement request to be processed by the related TV input.
          *
          * @param request The advertisement request
@@ -1725,6 +1807,11 @@
             onSigningResult(signingId, result);
         }
 
+        void sendCertificate(String host, int port, Bundle certBundle) {
+            SslCertificate cert = SslCertificate.restoreState(certBundle);
+            onCertificate(host, port, cert);
+        }
+
         void notifyError(String errMsg, Bundle params) {
             onError(errMsg, params);
         }
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 5bb61c2..3b29574 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -34,6 +34,7 @@
 import android.media.tv.interactive.TvInteractiveAppManager.Session.FinishedInputEventCallback;
 import android.media.tv.interactive.TvInteractiveAppManager.SessionCallback;
 import android.net.Uri;
+import android.net.http.SslCertificate;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.AttributeSet;
@@ -756,6 +757,22 @@
     }
 
     /**
+     * Send the requested SSL certificate to the TV Interactive App
+     * @param host the host name of the SSL authentication server.
+     * @param port the port of the SSL authentication server. E.g., 443
+     * @param cert the SSL certificate requested
+     * @hide
+     */
+    public void sendCertificate(@NonNull String host, int port, @NonNull SslCertificate cert) {
+        if (DEBUG) {
+            Log.d(TAG, "sendCertificate");
+        }
+        if (mSession != null) {
+            mSession.sendCertificate(host, port, cert);
+        }
+    }
+
+    /**
      * Notifies the corresponding {@link TvInteractiveAppService} when there is an error.
      *
      * @param errMsg the message of the error.
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index ef90bf9..8cdd59e 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -163,6 +163,13 @@
 static struct {
     jclass clazz;
     jmethodID ctorId;
+    jmethodID sizeId;
+    jmethodID addId;
+} gArrayDequeInfo;
+
+static struct {
+    jclass clazz;
+    jmethodID ctorId;
     jmethodID setInternalStateId;
     jfieldID contextId;
     jfieldID validId;
@@ -200,8 +207,14 @@
     jfieldID queueRequestIndexID;
     jfieldID outputFrameLinearBlockID;
     jfieldID outputFrameHardwareBufferID;
+    jfieldID outputFramebufferInfosID;
     jfieldID outputFrameChangedKeysID;
     jfieldID outputFrameFormatID;
+    jfieldID bufferInfoFlags;
+    jfieldID bufferInfoOffset;
+    jfieldID bufferInfoSize;
+    jfieldID bufferInfoPresentationTimeUs;
+
 };
 
 static fields_t gFields;
@@ -412,6 +425,22 @@
             index, offset, size, timeUs, flags, errorDetailMsg);
 }
 
+status_t JMediaCodec::queueInputBuffers(
+        size_t index,
+        size_t offset,
+        size_t size,
+        const sp<RefBase> &infos,
+        AString *errorDetailMsg) {
+
+    sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
+    return mCodec->queueInputBuffers(
+            index,
+            offset,
+            size,
+            auInfo,
+            errorDetailMsg);
+}
+
 status_t JMediaCodec::queueSecureInputBuffer(
         size_t index,
         size_t offset,
@@ -430,10 +459,11 @@
 }
 
 status_t JMediaCodec::queueBuffer(
-        size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
-        uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
+        size_t index, const std::shared_ptr<C2Buffer> &buffer,
+        const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
+    sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
     return mCodec->queueBuffer(
-            index, buffer, timeUs, flags, tunings, errorDetailMsg);
+            index, buffer, auInfo, tunings, errorDetailMsg);
 }
 
 status_t JMediaCodec::queueEncryptedLinearBlock(
@@ -446,13 +476,13 @@
         const uint8_t iv[16],
         CryptoPlugin::Mode mode,
         const CryptoPlugin::Pattern &pattern,
-        int64_t presentationTimeUs,
-        uint32_t flags,
+        const sp<RefBase> &infos,
         const sp<AMessage> &tunings,
         AString *errorDetailMsg) {
+    sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
     return mCodec->queueEncryptedBuffer(
             index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
-            presentationTimeUs, flags, tunings, errorDetailMsg);
+            auInfo, tunings, errorDetailMsg);
 }
 
 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
@@ -722,6 +752,42 @@
     return OK;
 }
 
+void maybeSetBufferInfos(JNIEnv *env, jobject &frame, const sp<BufferInfosWrapper> &bufInfos) {
+    if (!bufInfos) {
+        return;
+    }
+    std::vector<AccessUnitInfo> &infos = bufInfos.get()->value;
+    if (infos.empty()) {
+        return;
+    }
+    ScopedLocalRef<jobject> dequeObj{env, env->NewObject(
+            gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId)};
+    jint offset = 0;
+    std::vector<jobject> jObjectInfos;
+    for (int i = 0 ; i < infos.size(); i++) {
+        jobject bufferInfo = env->NewObject(
+                gBufferInfo.clazz, gBufferInfo.ctorId);
+        if (bufferInfo != NULL) {
+            env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
+                    offset,
+                    (jint)(infos)[i].mSize,
+                    (infos)[i].mTimestamp,
+                    (infos)[i].mFlags);
+            (void)env->CallBooleanMethod(
+                    dequeObj.get(), gArrayDequeInfo.addId, bufferInfo);
+            offset += (infos)[i].mSize;
+            jObjectInfos.push_back(bufferInfo);
+        }
+    }
+    env->SetObjectField(
+            frame,
+            gFields.outputFramebufferInfosID,
+            dequeObj.get());
+    for (int i = 0; i < jObjectInfos.size(); i++) {
+        env->DeleteLocalRef(jObjectInfos[i]);
+    }
+}
+
 status_t JMediaCodec::getOutputFrame(
         JNIEnv *env, jobject frame, size_t index) const {
     sp<MediaCodecBuffer> buffer;
@@ -732,6 +798,11 @@
     }
 
     if (buffer->size() > 0) {
+        sp<RefBase> obj;
+        sp<BufferInfosWrapper> bufInfos;
+        if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
+            bufInfos = std::move(((decltype(bufInfos.get()))obj.get()));
+        }
         std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
         if (c2Buffer) {
             switch (c2Buffer->data().type()) {
@@ -747,6 +818,7 @@
                             (jlong)context.release(),
                             true);
                     env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
+                    maybeSetBufferInfos(env, frame, bufInfos);
                     break;
                 }
                 case C2BufferData::GRAPHIC: {
@@ -787,6 +859,7 @@
                         (jlong)context.release(),
                         true);
                 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
+                maybeSetBufferInfos(env, frame, bufInfos);
             } else {
                 // No-op.
             }
@@ -1250,6 +1323,7 @@
 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
     int32_t arg1, arg2 = 0;
     jobject obj = NULL;
+    std::vector<jobject> jObjectInfos;
     CHECK(msg->findInt32("callbackID", &arg1));
     JNIEnv *env = AndroidRuntime::getJNIEnv();
 
@@ -1287,6 +1361,35 @@
             break;
         }
 
+        case MediaCodec::CB_LARGE_FRAME_OUTPUT_AVAILABLE:
+        {
+            sp<RefBase> spobj = nullptr;
+            CHECK(msg->findInt32("index", &arg2));
+            CHECK(msg->findObject("accessUnitInfo", &spobj));
+            if (spobj != nullptr) {
+                sp<BufferInfosWrapper> bufferInfoParamsWrapper {
+                        (BufferInfosWrapper *)spobj.get()};
+                std::vector<AccessUnitInfo> &bufferInfoParams =
+                        bufferInfoParamsWrapper.get()->value;
+                obj = env->NewObject(gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId);
+                jint offset = 0;
+                for (int i = 0 ; i < bufferInfoParams.size(); i++) {
+                    jobject bufferInfo = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
+                    if (bufferInfo != NULL) {
+                        env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
+                                            offset,
+                                            (jint)(bufferInfoParams)[i].mSize,
+                                            (bufferInfoParams)[i].mTimestamp,
+                                            (bufferInfoParams)[i].mFlags);
+                        (void)env->CallBooleanMethod(obj, gArrayDequeInfo.addId, bufferInfo);
+                        offset += (bufferInfoParams)[i].mSize;
+                        jObjectInfos.push_back(bufferInfo);
+                    }
+                }
+            }
+            break;
+        }
+
         case MediaCodec::CB_CRYPTO_ERROR:
         {
             int32_t err, actionCode;
@@ -1346,6 +1449,9 @@
             arg2,
             obj);
 
+    for (int i = 0; i < jObjectInfos.size(); i++) {
+        env->DeleteLocalRef(jObjectInfos[i]);
+    }
     env->DeleteLocalRef(obj);
 }
 
@@ -1913,6 +2019,103 @@
             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
 }
 
+static status_t extractInfosFromObject(
+        JNIEnv * const env,
+        jint * const initialOffset,
+        jint * const totalSize,
+        std::vector<AccessUnitInfo> * const infos,
+        const jobjectArray &objArray,
+        AString * const errorDetailMsg) {
+    if (totalSize == nullptr
+            || initialOffset == nullptr
+            || infos == nullptr) {
+        if (errorDetailMsg) {
+            *errorDetailMsg = "Error: Null arguments provided for extracting Access unit info";
+        }
+        return BAD_VALUE;
+    }
+    const jsize numEntries = env->GetArrayLength(objArray);
+    if (numEntries <= 0) {
+        if (errorDetailMsg) {
+            *errorDetailMsg = "Error: No BufferInfo found while queuing for large frame input";
+        }
+        return BAD_VALUE;
+    }
+    *initialOffset = 0;
+    *totalSize = 0;
+    for (jsize i = 0; i < numEntries; i++) {
+        jobject param = env->GetObjectArrayElement(objArray, i);
+        if (param == NULL) {
+            if (errorDetailMsg) {
+                *errorDetailMsg = "Error: Queuing a null BufferInfo";
+            }
+            return BAD_VALUE;
+        }
+        size_t offset = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoOffset));
+        size_t size = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoSize));
+        uint32_t flags = static_cast<uint32_t>(env->GetIntField(param, gFields.bufferInfoFlags));
+        if (flags == 0 && size == 0) {
+            if (errorDetailMsg) {
+                *errorDetailMsg = "Error: Queuing an empty BufferInfo";
+            }
+            return BAD_VALUE;
+        }
+        if (i == 0) {
+            *initialOffset = offset;
+        }
+        if (CC_UNLIKELY((offset >  UINT32_MAX)
+                || ((long)(offset + size) > UINT32_MAX)
+                || ((offset - *initialOffset) != *totalSize))) {
+            if (errorDetailMsg) {
+                *errorDetailMsg = "Error: offset/size in BufferInfo";
+            }
+            return BAD_VALUE;
+        }
+        infos->emplace_back(
+                flags,
+                size,
+                env->GetLongField(param, gFields.bufferInfoPresentationTimeUs));
+        *totalSize += size;
+    }
+    return OK;
+}
+
+static void android_media_MediaCodec_queueInputBuffers(
+        JNIEnv *env,
+        jobject thiz,
+        jint index,
+        jobjectArray objArray) {
+    ALOGV("android_media_MediaCodec_queueInputBuffers");
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+    if (codec == NULL || codec->initCheck() != OK || objArray == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
+        return;
+    }
+    sp<BufferInfosWrapper> infoObj =
+            new BufferInfosWrapper{decltype(infoObj->value)()};
+    AString errorDetailMsg;
+    jint initialOffset = 0;
+    jint totalSize = 0;
+    status_t err = extractInfosFromObject(
+            env,
+            &initialOffset,
+            &totalSize,
+            &infoObj->value,
+            objArray,
+            &errorDetailMsg);
+    if (err == OK) {
+        err = codec->queueInputBuffers(
+            index,
+            initialOffset,
+            totalSize,
+            infoObj,
+            &errorDetailMsg);
+    }
+    throwExceptionAsNecessary(
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
+}
+
 struct NativeCryptoInfo {
     NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
         : mEnv{env},
@@ -2559,8 +2762,7 @@
 
 static void android_media_MediaCodec_native_queueLinearBlock(
         JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
-        jint offset, jint size, jobject cryptoInfoObj,
-        jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
+        jobject cryptoInfoObj, jobjectArray objArray, jobject keys, jobject values) {
     ALOGV("android_media_MediaCodec_native_queueLinearBlock");
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -2578,7 +2780,24 @@
                 "error occurred while converting tunings from Java to native");
         return;
     }
-
+    jint totalSize;
+    jint initialOffset;
+    std::vector<AccessUnitInfo> infoVec;
+    AString errorDetailMsg;
+    err = extractInfosFromObject(env,
+            &initialOffset,
+            &totalSize,
+            &infoVec,
+            objArray,
+            &errorDetailMsg);
+    if (err != OK) {
+        throwExceptionAsNecessary(
+                env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
+        return;
+    }
+    sp<BufferInfosWrapper> infos =
+            new BufferInfosWrapper{std::move(infoVec)};
     std::shared_ptr<C2Buffer> buffer;
     sp<hardware::HidlMemory> memory;
     ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
@@ -2587,10 +2806,10 @@
             JMediaCodecLinearBlock *context =
                 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
             if (codec->hasCryptoOrDescrambler()) {
-                extractMemoryFromContext(context, offset, size, &memory);
-                offset += context->mHidlMemoryOffset;
+                extractMemoryFromContext(context, initialOffset, totalSize, &memory);
+                initialOffset += context->mHidlMemoryOffset;
             } else {
-                extractBufferFromContext(context, offset, size, &buffer);
+                extractBufferFromContext(context, initialOffset, totalSize, &buffer);
             }
         }
         env->MonitorExit(lock.get());
@@ -2601,7 +2820,6 @@
         return;
     }
 
-    AString errorDetailMsg;
     if (codec->hasCryptoOrDescrambler()) {
         if (!memory) {
             // It means there was an unexpected failure in extractMemoryFromContext above
@@ -2615,7 +2833,7 @@
             return;
         }
         auto cryptoInfo =
-                cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{size};
+                cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{totalSize};
         if (env->ExceptionCheck()) {
             // Creation of cryptoInfo failed. Let the exception bubble up.
             return;
@@ -2623,13 +2841,12 @@
         err = codec->queueEncryptedLinearBlock(
                 index,
                 memory,
-                offset,
+                initialOffset,
                 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
                 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
                 cryptoInfo.mMode,
                 cryptoInfo.mPattern,
-                presentationTimeUs,
-                flags,
+                infos,
                 tunings,
                 &errorDetailMsg);
         ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
@@ -2646,7 +2863,7 @@
             return;
         }
         err = codec->queueBuffer(
-                index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
+                index, buffer, infos, tunings, &errorDetailMsg);
     }
     throwExceptionAsNecessary(
             env, err, ACTION_CODE_FATAL,
@@ -2704,8 +2921,11 @@
     std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
             block->crop(), C2Fence{}));
     AString errorDetailMsg;
+    sp<BufferInfosWrapper> infos =
+        new BufferInfosWrapper{decltype(infos->value)()};
+    infos->value.emplace_back(flags, 0 /*not used*/, presentationTimeUs);
     err = codec->queueBuffer(
-            index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
+            index, buffer, infos, tunings, &errorDetailMsg);
     throwExceptionAsNecessary(
             env, err, ACTION_CODE_FATAL,
             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
@@ -3214,6 +3434,10 @@
         env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
     CHECK(gFields.outputFrameLinearBlockID != NULL);
 
+    gFields.outputFramebufferInfosID =
+        env->GetFieldID(clazz.get(), "mBufferInfos", "Ljava/util/ArrayDeque;");
+    CHECK(gFields.outputFramebufferInfosID != NULL);
+
     gFields.outputFrameHardwareBufferID =
         env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
     CHECK(gFields.outputFrameHardwareBufferID != NULL);
@@ -3401,6 +3625,19 @@
     gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
     CHECK(gArrayListInfo.addId != NULL);
 
+    clazz.reset(env->FindClass("java/util/ArrayDeque"));
+    CHECK(clazz.get() != NULL);
+    gArrayDequeInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+
+    gArrayDequeInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+    CHECK(gArrayDequeInfo.ctorId != NULL);
+
+    gArrayDequeInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
+    CHECK(gArrayDequeInfo.sizeId != NULL);
+
+    gArrayDequeInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
+    CHECK(gArrayDequeInfo.addId != NULL);
+
     clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
     CHECK(clazz.get() != NULL);
 
@@ -3444,6 +3681,12 @@
 
     gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
     CHECK(gBufferInfo.setId != NULL);
+
+    gFields.bufferInfoSize = env->GetFieldID(clazz.get(), "size", "I");
+    gFields.bufferInfoFlags = env->GetFieldID(clazz.get(), "flags", "I");
+    gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
+    gFields.bufferInfoPresentationTimeUs =
+            env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
 }
 
 static void android_media_MediaCodec_native_setup(
@@ -3701,6 +3944,9 @@
     { "native_queueInputBuffer", "(IIIJI)V",
       (void *)android_media_MediaCodec_queueInputBuffer },
 
+    { "native_queueInputBuffers", "(I[Ljava/lang/Object;)V",
+      (void *)android_media_MediaCodec_queueInputBuffers },
+
     { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
       (void *)android_media_MediaCodec_queueSecureInputBuffer },
 
@@ -3711,8 +3957,8 @@
     { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
 
     { "native_queueLinearBlock",
-      "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
-      "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
+      "(ILandroid/media/MediaCodec$LinearBlock;Landroid/media/MediaCodec$CryptoInfo;"
+      "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
       (void *)android_media_MediaCodec_native_queueLinearBlock },
 
     { "native_queueHardwareBuffer",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index fbaf64f..02708ef 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -35,6 +35,7 @@
 namespace android {
 
 struct ABuffer;
+struct AccessUnitInfo;
 struct ALooper;
 struct AMessage;
 struct AString;
@@ -93,6 +94,13 @@
             size_t offset, size_t size, int64_t timeUs, uint32_t flags,
             AString *errorDetailMsg);
 
+    status_t queueInputBuffers(
+            size_t index,
+            size_t offset,
+            size_t size,
+            const sp<RefBase> &auInfo,
+            AString *errorDetailMsg = NULL);
+
     status_t queueSecureInputBuffer(
             size_t index,
             size_t offset,
@@ -108,7 +116,7 @@
 
     status_t queueBuffer(
             size_t index, const std::shared_ptr<C2Buffer> &buffer,
-            int64_t timeUs, uint32_t flags, const sp<AMessage> &tunings,
+            const sp<RefBase> &infos, const sp<AMessage> &tunings,
             AString *errorDetailMsg);
 
     status_t queueEncryptedLinearBlock(
@@ -121,8 +129,7 @@
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
             const CryptoPlugin::Pattern &pattern,
-            int64_t presentationTimeUs,
-            uint32_t flags,
+            const sp<RefBase> &infos,
             const sp<AMessage> &tunings,
             AString *errorDetailMsg);
 
diff --git a/media/jni/soundpool/SoundDecoder.cpp b/media/jni/soundpool/SoundDecoder.cpp
index 5ed10b0..ae57634 100644
--- a/media/jni/soundpool/SoundDecoder.cpp
+++ b/media/jni/soundpool/SoundDecoder.cpp
@@ -29,14 +29,15 @@
 // before the SoundDecoder thread closes.
 static constexpr int32_t kWaitTimeBeforeCloseMs = 1000;
 
-SoundDecoder::SoundDecoder(SoundManager* soundManager, size_t threads)
+SoundDecoder::SoundDecoder(SoundManager* soundManager, size_t threads, int32_t threadPriority)
     : mSoundManager(soundManager)
 {
     ALOGV("%s(%p, %zu)", __func__, soundManager, threads);
     // ThreadPool is created, but we don't launch any threads.
     mThreadPool = std::make_unique<ThreadPool>(
             std::min(threads, (size_t)std::thread::hardware_concurrency()),
-            "SoundDecoder_");
+            "SoundDecoder_",
+            threadPriority);
 }
 
 SoundDecoder::~SoundDecoder()
diff --git a/media/jni/soundpool/SoundDecoder.h b/media/jni/soundpool/SoundDecoder.h
index 7b62114..3f44a0d 100644
--- a/media/jni/soundpool/SoundDecoder.h
+++ b/media/jni/soundpool/SoundDecoder.h
@@ -28,7 +28,7 @@
  */
 class SoundDecoder {
 public:
-    SoundDecoder(SoundManager* soundManager, size_t threads);
+    SoundDecoder(SoundManager* soundManager, size_t threads, int32_t threadPriority);
     ~SoundDecoder();
     void loadSound(int32_t soundID) NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock
     void quit();
diff --git a/media/jni/soundpool/SoundManager.cpp b/media/jni/soundpool/SoundManager.cpp
index 5b16174..fa35813 100644
--- a/media/jni/soundpool/SoundManager.cpp
+++ b/media/jni/soundpool/SoundManager.cpp
@@ -29,7 +29,7 @@
 static const size_t kDecoderThreads = std::thread::hardware_concurrency() >= 4 ? 2 : 1;
 
 SoundManager::SoundManager()
-    : mDecoder{std::make_unique<SoundDecoder>(this, kDecoderThreads)}
+    : mDecoder{std::make_unique<SoundDecoder>(this, kDecoderThreads, ANDROID_PRIORITY_NORMAL)}
 {
     ALOGV("%s()", __func__);
 }
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 66fec1c..e11ccbc 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -126,7 +126,8 @@
     mThreadPool = std::make_unique<ThreadPool>(
             std::min((size_t)streams,  // do not make more threads than streams to play
                     std::min(threads, (size_t)std::thread::hardware_concurrency())),
-            "SoundPool_");
+            "SoundPool_",
+            ANDROID_PRIORITY_AUDIO);
 }
 
 #pragma clang diagnostic pop
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
index 340b49b..a4cb286 100644
--- a/media/jni/soundpool/StreamManager.h
+++ b/media/jni/soundpool/StreamManager.h
@@ -46,9 +46,9 @@
  */
 class JavaThread {
 public:
-    JavaThread(std::function<void()> f, const char *name)
+    JavaThread(std::function<void()> f, const char *name, int32_t threadPriority)
         : mF{std::move(f)} {
-        createThreadEtc(staticFunction, this, name, ANDROID_PRIORITY_AUDIO);
+        createThreadEtc(staticFunction, this, name, threadPriority);
     }
 
     JavaThread(JavaThread &&) = delete; // uses "this" ptr, not moveable.
@@ -109,9 +109,11 @@
  */
 class ThreadPool {
 public:
-    ThreadPool(size_t maxThreadCount, std::string name)
+    ThreadPool(size_t maxThreadCount, std::string name,
+            int32_t threadPriority = ANDROID_PRIORITY_NORMAL)
         : mMaxThreadCount(maxThreadCount)
-        , mName{std::move(name)} { }
+        , mName{std::move(name)}
+        , mThreadPriority(threadPriority) {}
 
     ~ThreadPool() { quit(); }
 
@@ -159,7 +161,8 @@
             const int32_t id = mNextThreadId;
             mThreads.emplace_back(std::make_unique<JavaThread>(
                     [this, id, mf = std::move(f)] { mf(id); --mActiveThreadCount; },
-                    (mName + std::to_string(id)).c_str()));
+                    (mName + std::to_string(id)).c_str(),
+                    mThreadPriority));
             ++mActiveThreadCount;
             return id;
         }
@@ -180,6 +183,7 @@
 private:
     const size_t            mMaxThreadCount;
     const std::string       mName;
+    const int32_t           mThreadPriority;
 
     std::atomic_size_t      mActiveThreadCount = 0;
 
diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
index 774de5f..0df36af 100644
--- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
+++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
@@ -19,7 +19,7 @@
 import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
 
 import android.annotation.EnforcePermission;
-import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
 import android.os.PermissionEnforcer;
 import android.os.RemoteException;
 
@@ -29,7 +29,7 @@
  */
 public final class FakeIMediaProjection extends IMediaProjection.Stub {
     boolean mIsStarted = false;
-    IBinder mLaunchCookie = null;
+    LaunchCookie mLaunchCookie = null;
     IMediaProjectionCallback mIMediaProjectionCallback = null;
 
     FakeIMediaProjection(PermissionEnforcer enforcer) {
@@ -80,14 +80,14 @@
 
     @Override
     @EnforcePermission(MANAGE_MEDIA_PROJECTION)
-    public IBinder getLaunchCookie() throws RemoteException {
+    public LaunchCookie getLaunchCookie() throws RemoteException {
         getLaunchCookie_enforcePermission();
         return mLaunchCookie;
     }
 
     @Override
     @EnforcePermission(MANAGE_MEDIA_PROJECTION)
-    public void setLaunchCookie(IBinder launchCookie) throws RemoteException {
+    public void setLaunchCookie(LaunchCookie launchCookie) throws RemoteException {
         setLaunchCookie_enforcePermission();
         mLaunchCookie = launchCookie;
     }
diff --git a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
index 2e0396f..1323e89 100644
--- a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
+++ b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
@@ -31,15 +31,14 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 
 import android.annotation.Nullable;
+import android.app.ActivityOptions.LaunchCookie;
 import android.compat.testing.PlatformCompatChangeRule;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.hardware.display.VirtualDisplayConfig;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.test.FakePermissionEnforcer;
@@ -117,7 +116,7 @@
         permissionEnforcer.grant(MANAGE_MEDIA_PROJECTION);
         // Support the MediaProjection instance.
         mFakeIMediaProjection = new FakeIMediaProjection(permissionEnforcer);
-        mFakeIMediaProjection.setLaunchCookie(mock(IBinder.class));
+        mFakeIMediaProjection.setLaunchCookie(new LaunchCookie());
         mMediaProjection = new MediaProjection(mTestableContext, mFakeIMediaProjection,
                 mDisplayManager);
 
diff --git a/nfc/jarjar-rules.txt b/nfc/jarjar-rules.txt
index 4cd652d..99ae144 100644
--- a/nfc/jarjar-rules.txt
+++ b/nfc/jarjar-rules.txt
@@ -4,6 +4,7 @@
 rule android.content.IntentProto* com.android.nfc.x.@0
 rule android.content.IntentFilterProto* com.android.nfc.x.@0
 rule android.content.AuthorityEntryProto* com.android.nfc.x.@0
+rule android.content.UriRelativeFilter* com.android.nfc.x.@0
 rule android.nfc.cardemulation.AidGroupProto* com.android.nfc.x.@0
 rule android.nfc.cardemulation.ApduServiceInfoProto* com.android.nfc.x.@0
 rule android.nfc.cardemulation.NfcFServiceInfoProto* com.android.nfc.x.@0
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 9d38e4c..1f41b81 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -338,8 +338,10 @@
         }
     }
     /**
-     * Sets whether the system should default to observe mode or not when
-     * the service is in the foreground or the default payment service.
+     * Sets whether the system should default to observe mode or not when the service is in the
+     * foreground or the default payment service. The default is to not enable observe mode when
+     * a service either the foreground default service or the default payment service so not
+     * calling this method will preserve that behavior.
      *
      * @param service The component name of the service
      * @param enable Whether the servic should default to observe mode or not
diff --git a/packages/CrashRecovery/aconfig/flags.aconfig b/packages/CrashRecovery/aconfig/flags.aconfig
new file mode 100644
index 0000000..5636266
--- /dev/null
+++ b/packages/CrashRecovery/aconfig/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.crashrecovery.flags"
+
+flag {
+    name: "recoverability_detection"
+    namespace: "package_watchdog"
+    description: "Feature flag for recoverability detection"
+    bug: "310236690"
+    is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
index a2d2a96..3614240 100644
--- a/packages/CredentialManager/res/values-af/strings.xml
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Van ’n ander toestel af"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gebruik ’n ander toestel"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Versoek is deur <xliff:g id="APP_NAME">%1$s</xliff:g> gekanselleer"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml
index 475dcf7..e5759fa 100644
--- a/packages/CredentialManager/res/values-am/strings.xml
+++ b/packages/CredentialManager/res/values-am/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ከሌላ መሣሪያ"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"የተለየ መሣሪያ ይጠቀሙ"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"ጥያቄ በ<xliff:g id="APP_NAME">%1$s</xliff:g> ተሰርዟል"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml
index 3f85b58..fdd9043 100644
--- a/packages/CredentialManager/res/values-ar/strings.xml
+++ b/packages/CredentialManager/res/values-ar/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"من جهاز آخر"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استخدام جهاز مختلف"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"تم إلغاء الطلب بواسطة \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml
index e14b34b..005079e 100644
--- a/packages/CredentialManager/res/values-as/strings.xml
+++ b/packages/CredentialManager/res/values-as/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য এটা ডিভাইচৰ পৰা"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"অন্য এটা ডিভাইচ ব্যৱহাৰ কৰক"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ অনুৰোধটো বাতিল কৰিছে"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml
index d0f8bb0..9937942 100644
--- a/packages/CredentialManager/res/values-az/strings.xml
+++ b/packages/CredentialManager/res/values-az/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başqa cihazdan"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Başqa cihaz istifadə edin"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> sorğunu ləğv etdi"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
index 780274c..171e841 100644
--- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Sa drugog uređaja"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Koristi drugi uređaj"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Zahtve je otkazala aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml
index 144bb86..323b683 100644
--- a/packages/CredentialManager/res/values-be/strings.xml
+++ b/packages/CredentialManager/res/values-be/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншай прылады"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Скарыстаць іншую прыладу"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Запыт скасаваны праграмай \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml
index ef4dd54c..1efec45 100644
--- a/packages/CredentialManager/res/values-bg/strings.xml
+++ b/packages/CredentialManager/res/values-bg/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"От друго устройство"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Използване на друго устройство"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Заявката е анулирана от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml
index 14f4a9b..3fcc91a 100644
--- a/packages/CredentialManager/res/values-bn/strings.xml
+++ b/packages/CredentialManager/res/values-bn/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য ডিভাইস থেকে"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"আলাদা ডিভাইস ব্যবহার করুন"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> দ্বারা অনুরোধ বাতিল করা হয়েছে"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml
index 6315ea8..6a3d25e 100644
--- a/packages/CredentialManager/res/values-bs/strings.xml
+++ b/packages/CredentialManager/res/values-bs/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"S drugog uređaja"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je otkazala zahtjev"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml
index 8e3fda8..d491b70 100644
--- a/packages/CredentialManager/res/values-ca/strings.xml
+++ b/packages/CredentialManager/res/values-ca/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Des d\'un altre dispositiu"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utilitza un dispositiu diferent"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha cancel·lat la sol·licitud"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml
index 9fe5a49..133f3f8 100644
--- a/packages/CredentialManager/res/values-cs/strings.xml
+++ b/packages/CredentialManager/res/values-cs/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z jiného zařízení"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použít jiné zařízení"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> žádost zrušila"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml
index c7ee038..93de75f 100644
--- a/packages/CredentialManager/res/values-da/strings.xml
+++ b/packages/CredentialManager/res/values-da/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en anden enhed"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Brug en anden enhed"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Anmodningen blev annulleret af <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml
index 29d9a86b..d3648a1 100644
--- a/packages/CredentialManager/res/values-de/strings.xml
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Von einem anderen Gerät"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Anderes Gerät verwenden"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Anfrage abgebrochen von <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index 089f898..da3ae13 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Από άλλη συσκευή"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Χρήση διαφορετικής συσκευής"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Το αίτημα ακυρώθηκε από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml
index 7b80db0..056b8ff 100644
--- a/packages/CredentialManager/res/values-en-rAU/strings.xml
+++ b/packages/CredentialManager/res/values-en-rAU/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml
index b173616..e23711f 100644
--- a/packages/CredentialManager/res/values-en-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-en-rCA/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml
index 7b80db0..056b8ff 100644
--- a/packages/CredentialManager/res/values-en-rGB/strings.xml
+++ b/packages/CredentialManager/res/values-en-rGB/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml
index 7b80db0..056b8ff 100644
--- a/packages/CredentialManager/res/values-en-rIN/strings.xml
+++ b/packages/CredentialManager/res/values-en-rIN/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml
index c3eeb04..0db7324 100644
--- a/packages/CredentialManager/res/values-en-rXC/strings.xml
+++ b/packages/CredentialManager/res/values-en-rXC/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎From another device‎‏‎‎‏‎"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎Use a different device‎‏‎‎‏‎"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎Request cancelled by ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml
index f6a5dcb..818d715 100644
--- a/packages/CredentialManager/res/values-es-rUS/strings.xml
+++ b/packages/CredentialManager/res/values-es-rUS/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Desde otro dispositivo"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otra voz"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> canceló la solicitud"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml
index fb0cbf9..f9776fb 100644
--- a/packages/CredentialManager/res/values-es/strings.xml
+++ b/packages/CredentialManager/res/values-es/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De otro dispositivo"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otro dispositivo"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha cancelado la solicitud"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml
index 97dbe4d..4870e70 100644
--- a/packages/CredentialManager/res/values-et/strings.xml
+++ b/packages/CredentialManager/res/values-et/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Muus seadmes"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Kasuta teist seadet"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> tühistas taotluse"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml
index 8316283..21a66f9 100644
--- a/packages/CredentialManager/res/values-eu/strings.xml
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Beste gailu batean gordetakoak"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Erabili beste gailu bat"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Utzi du bertan behera eskaera <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml
index a6e0d3d..47385cd 100644
--- a/packages/CredentialManager/res/values-fa/strings.xml
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"از دستگاهی دیگر"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استفاده از دستگاه دیگری"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"درخواست را <xliff:g id="APP_NAME">%1$s</xliff:g> لغو کرد"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml
index fff45c9..d463ea1 100644
--- a/packages/CredentialManager/res/values-fi/strings.xml
+++ b/packages/CredentialManager/res/values-fi/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Toiselta laitteelta"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Käytä toista laitetta"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> hylkäsi pyynnön"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
index 155be6f..3596604 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"À partir d\'un autre appareil"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Demande annulée par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml
index e042815..fe545b3 100644
--- a/packages/CredentialManager/res/values-fr/strings.xml
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Depuis un autre appareil"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Requête annulée par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml
index 79e0b5e..6341ed89 100644
--- a/packages/CredentialManager/res/values-gl/strings.xml
+++ b/packages/CredentialManager/res/values-gl/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Doutro dispositivo"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar outro dispositivo"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> cancelou a solicitude"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml
index c3c5b62..19930df 100644
--- a/packages/CredentialManager/res/values-gu/strings.xml
+++ b/packages/CredentialManager/res/values-gu/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"કોઈ અન્ય ડિવાઇસમાંથી"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"કોઈ અન્ય ડિવાઇસનો ઉપયોગ કરો"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> દ્વારા વિનંતી રદ કરવામાં આવી"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml
index 05d21e0..8505b19 100644
--- a/packages/CredentialManager/res/values-hi/strings.xml
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"किसी दूसरे डिवाइस से"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"दूसरे डिवाइस का इस्तेमाल करें"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> की ओर से अनुरोध रद्द किया गया"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml
index 4425e24..3ea8847 100644
--- a/packages/CredentialManager/res/values-hr/strings.xml
+++ b/packages/CredentialManager/res/values-hr/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na drugom uređaju"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Zahtjev je otkazala aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
index c25fa99..620e976 100644
--- a/packages/CredentialManager/res/values-hu/strings.xml
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Másik eszközről"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Másik eszköz használata"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"A kérelmet törölte a(z) <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
index a6bda50..5423efe 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Մեկ այլ սարքից"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Օգտագործել այլ սարք"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Հարցումը չեղարկվել է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի կողմից"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml
index d6bf946..df9d32d 100644
--- a/packages/CredentialManager/res/values-in/strings.xml
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Dari perangkat lain"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan perangkat lain"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Permintaan dibatalkan oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml
index 76a869f..ba836f9 100644
--- a/packages/CredentialManager/res/values-is/strings.xml
+++ b/packages/CredentialManager/res/values-is/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Úr öðru tæki"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Nota annað tæki"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> hætti við beiðnina"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml
index c5fd89c..d16d11f 100644
--- a/packages/CredentialManager/res/values-it/strings.xml
+++ b/packages/CredentialManager/res/values-it/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Da un altro dispositivo"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usa un dispositivo diverso"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Richiesta annullata da <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml
index 0643568..a9b01e1 100644
--- a/packages/CredentialManager/res/values-iw/strings.xml
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ממכשיר אחר"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"צריך להשתמש במכשיר אחר"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> ביטלה את הבקשה"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml
index afbff90..b452ec3 100644
--- a/packages/CredentialManager/res/values-ja/strings.xml
+++ b/packages/CredentialManager/res/values-ja/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"別のデバイスを使う"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"別のデバイスを使用"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> がリクエストをキャンセルしました"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index 8125ec6..30479335 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"სხვა მოწყობილობიდან"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"გამოიყენეთ სხვა მოწყობილობა"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"თხოვნა გაუქმებულია <xliff:g id="APP_NAME">%1$s</xliff:g>-ის მიერ"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
index cb68444..891a600 100644
--- a/packages/CredentialManager/res/values-kk/strings.xml
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Басқа құрылғыдан жасау"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Басқа құрылғыны пайдалану"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы сұрауды тоқтатты."</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml
index d361ad9..d6fc505 100644
--- a/packages/CredentialManager/res/values-km/strings.xml
+++ b/packages/CredentialManager/res/values-km/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ពីឧបករណ៍ផ្សេងទៀត"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ប្រើឧបករណ៍ផ្សេង"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"បានបោះបង់សំណើដោយ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml
index 7447ab6..ff38e19 100644
--- a/packages/CredentialManager/res/values-kn/strings.xml
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ಮತ್ತೊಂದು ಸಾಧನದಿಂದ"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ಬೇರೆ ಸಾಧನವನ್ನು ಬಳಸಿ"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನಿಂದ ವಿನಂತಿಯನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml
index 07a7fbc..557c3ef 100644
--- a/packages/CredentialManager/res/values-ko/strings.xml
+++ b/packages/CredentialManager/res/values-ko/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"다른 기기에서"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"다른 기기 사용"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>에 의해 요청이 취소됨"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml
index e2de2ef..4bc96b1d 100644
--- a/packages/CredentialManager/res/values-ky/strings.xml
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Башка түзмөктөн"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Башка түзмөктү колдонуу"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Сурамды <xliff:g id="APP_NAME">%1$s</xliff:g> жокко чыгарды"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml
index 3b2e2aa..ce103e0 100644
--- a/packages/CredentialManager/res/values-lo/strings.xml
+++ b/packages/CredentialManager/res/values-lo/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ຈາກອຸປະກອນອື່ນ"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ໃຊ້ອຸປະກອນອື່ນ"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"ການຮ້ອງຂໍຖືກຍົກເລີກໂດຍ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml
index c3b941b..af27824 100644
--- a/packages/CredentialManager/res/values-lt/strings.xml
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Naudojant kitą įrenginį"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Naudoti kitą įrenginį"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Užklausą atšaukė „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml
index 27115ca..532ac5e 100644
--- a/packages/CredentialManager/res/values-lv/strings.xml
+++ b/packages/CredentialManager/res/values-lv/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"No citas ierīces"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Izmantot citu ierīci"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> atcēla pieprasījumu"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml
index 1f456bf..ec9ebef 100644
--- a/packages/CredentialManager/res/values-mk/strings.xml
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Од друг уред"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Употребете друг уред"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Барањето е откажано од <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml
index 07fea38..16ef8c8 100644
--- a/packages/CredentialManager/res/values-ml/strings.xml
+++ b/packages/CredentialManager/res/values-ml/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"മറ്റൊരു ഉപകരണത്തിൽ നിന്ന്"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"മറ്റൊരു ഉപകരണം ഉപയോഗിക്കുക"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"അഭ്യർത്ഥന <xliff:g id="APP_NAME">%1$s</xliff:g> റദ്ദാക്കി"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml
index e37155a..4a5a8eea 100644
--- a/packages/CredentialManager/res/values-mn/strings.xml
+++ b/packages/CredentialManager/res/values-mn/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Өөр төхөөрөмжөөс"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Өөр төхөөрөмж ашиглах"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Хүсэлтийг <xliff:g id="APP_NAME">%1$s</xliff:g> цуцалсан"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml
index ceba101..6a76b02 100644
--- a/packages/CredentialManager/res/values-mr/strings.xml
+++ b/packages/CredentialManager/res/values-mr/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"दुसऱ्या डिव्हाइस वरून"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"वेगळे डिव्हाइस वापरा"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ने विनंती रद्द केली आहे"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml
index b933f3e..f759eed 100644
--- a/packages/CredentialManager/res/values-ms/strings.xml
+++ b/packages/CredentialManager/res/values-ms/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Daripada peranti lain"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan peranti yang lain"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Permintaan dibatalkan oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml
index c359ce1..9c15226 100644
--- a/packages/CredentialManager/res/values-my/strings.xml
+++ b/packages/CredentialManager/res/values-my/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"စက်နောက်တစ်ခုမှ"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"အခြားစက်သုံးရန်"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"တောင်းဆိုချက်ကို <xliff:g id="APP_NAME">%1$s</xliff:g> က ပယ်ဖျက်လိုက်သည်"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml
index 7f63f10..327bc7f 100644
--- a/packages/CredentialManager/res/values-nb/strings.xml
+++ b/packages/CredentialManager/res/values-nb/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en annen enhet"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Bruk en annen enhet"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Forespørselen er kansellert av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml
index 042ed62..044853a 100644
--- a/packages/CredentialManager/res/values-ne/strings.xml
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"अर्को डिभाइसका लागि"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"अर्कै डिभाइस प्रयोग गरी हेर्नुहोस्"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले अनुरोध रद्द गरेको छ"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml
index 68f95a7..8386995 100644
--- a/packages/CredentialManager/res/values-nl/strings.xml
+++ b/packages/CredentialManager/res/values-nl/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via een ander apparaat"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Een ander apparaat gebruiken"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Verzoek geannuleerd door <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml
index 150ef0b..9f305ab 100644
--- a/packages/CredentialManager/res/values-or/strings.xml
+++ b/packages/CredentialManager/res/values-or/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ଅନ୍ୟ ଏକ ଡିଭାଇସରୁ"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ଏକ ଭିନ୍ନ ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଦ୍ୱାରା ଅନୁରୋଧ ବାତିଲ ହୋଇଛି"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml
index 10ff1ad..b90ae5e 100644
--- a/packages/CredentialManager/res/values-pa/strings.xml
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ਹੋਰ ਡੀਵਾਈਸ ਤੋਂ"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ਵੱਖਰੇ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਬੇਨਤੀ ਰੱਦ ਕੀਤੀ ਗਈ"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml
index be60af5..6966d21 100644
--- a/packages/CredentialManager/res/values-pl/strings.xml
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na innym urządzeniu"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Użyj innego urządzenia"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Żądanie anulowane przez aplikację <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
index 93459e6..79da371 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="4539824758261855508">"Gerenciador de credenciais"</string>
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
     <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
     <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
     <string name="string_more_options" msgid="2763852250269945472">"Salvar de outra forma"</string>
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar um dispositivo diferente"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Solicitação cancelada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
index 27b84aa..208b475 100644
--- a/packages/CredentialManager/res/values-pt-rPT/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use um dispositivo diferente"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Pedido cancelado pela app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index 93459e6..79da371 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="4539824758261855508">"Gerenciador de credenciais"</string>
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
     <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
     <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
     <string name="string_more_options" msgid="2763852250269945472">"Salvar de outra forma"</string>
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar um dispositivo diferente"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Solicitação cancelada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml
index 5292eca..8984cf2 100644
--- a/packages/CredentialManager/res/values-ro/strings.xml
+++ b/packages/CredentialManager/res/values-ro/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De pe alt dispozitiv"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Folosește alt dispozitiv"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Solicitare anulată de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml
index 99d2d7cc..0f99831 100644
--- a/packages/CredentialManager/res/values-ru/strings.xml
+++ b/packages/CredentialManager/res/values-ru/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"С другого устройства"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Использовать другое устройство"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" отменило запрос."</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml
index 79eaa13..9969a0c 100644
--- a/packages/CredentialManager/res/values-si/strings.xml
+++ b/packages/CredentialManager/res/values-si/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"වෙනත් උපාංගයකින්"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"වෙනස් උපාංගයක් භාවිතා කරන්න"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> විසින් ඉල්ලීම අවලංගු කරන ලදී"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml
index 90805a4..f91f546 100644
--- a/packages/CredentialManager/res/values-sk/strings.xml
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z iného zariadenia"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použiť iné zariadenie"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Požiadavku zrušila aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml
index 16ba222..196b0aa 100644
--- a/packages/CredentialManager/res/values-sl/strings.xml
+++ b/packages/CredentialManager/res/values-sl/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Iz druge naprave"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Uporaba druge naprave"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Zahtevo je preklicala aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml
index 391c511..5fceff5 100644
--- a/packages/CredentialManager/res/values-sq/strings.xml
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Nga një pajisje tjetër"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Përdor një pajisje tjetër"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Kërkesa u anulua nga <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml
index b83c698..d721a4b 100644
--- a/packages/CredentialManager/res/values-sr/strings.xml
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Са другог уређаја"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Користи други уређај"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Захтве је отказала апликација <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml
index 65319b0..d3099cbc4 100644
--- a/packages/CredentialManager/res/values-sv/strings.xml
+++ b/packages/CredentialManager/res/values-sv/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via en annan enhet"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Använd en annan enhet"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Begäran avbruten av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml
index ffb4fa0..1e31128 100644
--- a/packages/CredentialManager/res/values-sw/strings.xml
+++ b/packages/CredentialManager/res/values-sw/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kutoka kwenye kifaa kingine"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Tumia kifaa tofauti"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Ombi lilighairiwa na <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml
index 750b67d..1d4e55a 100644
--- a/packages/CredentialManager/res/values-ta/strings.xml
+++ b/packages/CredentialManager/res/values-ta/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"மற்றொரு சாதனத்திலிருந்து பயன்படுத்து"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"வேறு சாதனத்தைப் பயன்படுத்து"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸால் கோரிக்கை ரத்துசெய்யப்பட்டது"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml
index 064ee96..d546b66 100644
--- a/packages/CredentialManager/res/values-te/strings.xml
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"మరొక పరికరం నుండి"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"వేరే పరికరాన్ని ఉపయోగించండి"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>, రిక్వెస్ట్‌ను రద్దు చేసింది"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml
index 249bd88..7ebe82f 100644
--- a/packages/CredentialManager/res/values-th/strings.xml
+++ b/packages/CredentialManager/res/values-th/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"จากอุปกรณ์อื่น"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ใช้อุปกรณ์อื่น"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"ยกเลิกคำขอแล้วโดย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml
index e33f1bf..d069ffe 100644
--- a/packages/CredentialManager/res/values-tl/strings.xml
+++ b/packages/CredentialManager/res/values-tl/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Mula sa ibang device"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gumamit ng ibang device"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Kinansela ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang kahilingan"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml
index 4e4894c..718d7bd 100644
--- a/packages/CredentialManager/res/values-tr/strings.xml
+++ b/packages/CredentialManager/res/values-tr/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başka bir cihazdan"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Farklı bir cihaz kullan"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"İstek, <xliff:g id="APP_NAME">%1$s</xliff:g> tarafından iptal edildi"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml
index 78a5a5b..c23933a 100644
--- a/packages/CredentialManager/res/values-uk/strings.xml
+++ b/packages/CredentialManager/res/values-uk/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншого пристрою"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Використовувати інший пристрій"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> скасував запит"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml
index d3d5d85..9bb1662 100644
--- a/packages/CredentialManager/res/values-ur/strings.xml
+++ b/packages/CredentialManager/res/values-ur/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"دوسرے آلے سے"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ایک مختلف آلہ استعمال کریں"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> نے درخواست منسوخ کر دی"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml
index a0785b6..90264e9 100644
--- a/packages/CredentialManager/res/values-uz/strings.xml
+++ b/packages/CredentialManager/res/values-uz/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Boshqa qurilmada"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Boshqa qurilmadan foydalanish"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Soʻrovni <xliff:g id="APP_NAME">%1$s</xliff:g> bekor qilgan"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml
index 0e17025..c6f897e 100644
--- a/packages/CredentialManager/res/values-vi/strings.xml
+++ b/packages/CredentialManager/res/values-vi/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Từ một thiết bị khác"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Dùng thiết bị khác"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> đã huỷ yêu cầu"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
index 495abe6..f5bb10f 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"通过另一台设备"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他设备"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>已取消请求"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml
index f786254..ab54793 100644
--- a/packages/CredentialManager/res/values-zh-rHK/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」已取消要求"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml
index c09bf86..f8f8eec 100644
--- a/packages/CredentialManager/res/values-zh-rTW/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"要求已由 <xliff:g id="APP_NAME">%1$s</xliff:g> 取消"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml
index 91f93e2..85fe60a 100644
--- a/packages/CredentialManager/res/values-zu/strings.xml
+++ b/packages/CredentialManager/res/values-zu/strings.xml
@@ -92,4 +92,8 @@
     <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kusukela kwenye idivayisi"</string>
     <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Sebenzisa idivayisi ehlukile"</string>
     <string name="request_cancelled_by" msgid="3735222326886267820">"Isicelo sikhanselwe yi-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+    <skip />
+    <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+    <skip />
 </resources>
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
index 325d3f8..0fa248d 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
@@ -19,7 +19,7 @@
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.RequestInfo
 import android.util.Log
 import com.android.credentialmanager.ktx.appLabel
 import com.android.credentialmanager.ktx.cancelUiRequest
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/CredentialManagerClient.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/CredentialManagerClient.kt
index 49387cf..3fbff37 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/CredentialManagerClient.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/CredentialManagerClient.kt
@@ -17,8 +17,8 @@
 package com.android.credentialmanager.client
 
 import android.content.Intent
-import android.credentials.ui.BaseDialogResult
-import android.credentials.ui.UserSelectionDialogResult
+import android.credentials.selection.BaseDialogResult
+import android.credentials.selection.UserSelectionDialogResult
 import com.android.credentialmanager.model.Request
 import kotlinx.coroutines.flow.StateFlow
 
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
index 3ef65b0..ec1f052 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
@@ -18,8 +18,8 @@
 
 import android.content.Context
 import android.content.Intent
-import android.credentials.ui.BaseDialogResult
-import android.credentials.ui.UserSelectionDialogResult
+import android.credentials.selection.BaseDialogResult
+import android.credentials.selection.UserSelectionDialogResult
 import android.os.Bundle
 import android.util.Log
 import com.android.credentialmanager.TAG
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index f063074..a5f227a 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -23,9 +23,9 @@
 import android.content.pm.PackageManager
 import android.credentials.Credential
 import android.credentials.flags.Flags
-import android.credentials.ui.AuthenticationEntry
-import android.credentials.ui.Entry
-import android.credentials.ui.GetCredentialProviderData
+import android.credentials.selection.AuthenticationEntry
+import android.credentials.selection.Entry
+import android.credentials.selection.GetCredentialProviderData
 import android.graphics.drawable.Drawable
 import android.text.TextUtils
 import android.util.Log
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/IntentKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/IntentKtx.kt
index 3abdb6f..4155b03 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/IntentKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/IntentKtx.kt
@@ -17,12 +17,12 @@
 package com.android.credentialmanager.ktx
 
 import android.content.Intent
-import android.credentials.ui.CancelUiRequest
-import android.credentials.ui.Constants
-import android.credentials.ui.CreateCredentialProviderData
-import android.credentials.ui.GetCredentialProviderData
-import android.credentials.ui.ProviderData
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.CancelUiRequest
+import android.credentials.selection.Constants
+import android.credentials.selection.CreateCredentialProviderData
+import android.credentials.selection.GetCredentialProviderData
+import android.credentials.selection.ProviderData
+import android.credentials.selection.RequestInfo
 import android.os.ResultReceiver
 
 val Intent.cancelUiRequest: CancelUiRequest?
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index c0d7149..6cafcf7 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -18,16 +18,16 @@
 
 import android.content.Context
 import android.content.Intent
-import android.credentials.ui.CancelUiRequest
-import android.credentials.ui.Constants
-import android.credentials.ui.CreateCredentialProviderData
-import android.credentials.ui.GetCredentialProviderData
-import android.credentials.ui.DisabledProviderData
-import android.credentials.ui.ProviderData
-import android.credentials.ui.RequestInfo
-import android.credentials.ui.BaseDialogResult
-import android.credentials.ui.ProviderPendingIntentResponse
-import android.credentials.ui.UserSelectionDialogResult
+import android.credentials.selection.CancelUiRequest
+import android.credentials.selection.Constants
+import android.credentials.selection.CreateCredentialProviderData
+import android.credentials.selection.GetCredentialProviderData
+import android.credentials.selection.DisabledProviderData
+import android.credentials.selection.ProviderData
+import android.credentials.selection.RequestInfo
+import android.credentials.selection.BaseDialogResult
+import android.credentials.selection.ProviderPendingIntentResponse
+import android.credentials.selection.UserSelectionDialogResult
 import android.os.IBinder
 import android.os.Bundle
 import android.os.ResultReceiver
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index f8ffc9e..fa975aa 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -18,8 +18,8 @@
 
 import android.app.Activity
 import android.content.Intent
-import android.credentials.ui.BaseDialogResult
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.BaseDialogResult
+import android.credentials.selection.RequestInfo
 import android.net.Uri
 import android.os.Bundle
 import android.os.ResultReceiver
@@ -213,7 +213,7 @@
     private fun onInitializationError(e: Exception, intent: Intent) {
         Log.e(Constants.LOG_TAG, "Failed to show the credential selector; closing the activity", e)
         val resultReceiver = intent.getParcelableExtra(
-            android.credentials.ui.Constants.EXTRA_RESULT_RECEIVER,
+            android.credentials.selection.Constants.EXTRA_RESULT_RECEIVER,
             ResultReceiver::class.java
         )
         val requestInfo = intent.extras?.getParcelable(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index fc3970d..64595e2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -20,11 +20,11 @@
 import android.content.Context
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
-import android.credentials.ui.CreateCredentialProviderData
-import android.credentials.ui.DisabledProviderData
-import android.credentials.ui.Entry
-import android.credentials.ui.GetCredentialProviderData
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.CreateCredentialProviderData
+import android.credentials.selection.DisabledProviderData
+import android.credentials.selection.Entry
+import android.credentials.selection.GetCredentialProviderData
+import android.credentials.selection.RequestInfo
 import android.graphics.drawable.Drawable
 import android.text.TextUtils
 import android.util.Log
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 985f322..1f1d236 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -25,8 +25,8 @@
 import android.credentials.GetCandidateCredentialsResponse
 import android.credentials.GetCandidateCredentialsException
 import android.credentials.CredentialOption
+import android.credentials.selection.GetCredentialProviderData
 import android.graphics.drawable.Icon
-import android.credentials.ui.GetCredentialProviderData
 import android.os.Bundle
 import android.os.CancellationSignal
 import android.os.OutcomeReceiver
@@ -51,7 +51,6 @@
 import android.credentials.CredentialManager
 import android.widget.RemoteViews
 import androidx.autofill.inline.v1.InlineSuggestionUi
-import androidx.core.content.ContextCompat
 import androidx.credentials.provider.CustomCredentialEntry
 import androidx.credentials.provider.PasswordCredentialEntry
 import androidx.credentials.provider.PublicKeyCredentialEntry
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
index f40dc7e..22a5ec1 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
@@ -16,7 +16,7 @@
 
 package com.android.credentialmanager.common
 
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.RequestInfo
 
 enum class DialogType {
   CREATE_CREDENTIAL,
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
index 4f9fc46..c9c66b4 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
@@ -17,8 +17,8 @@
 package com.android.credentialmanager.ui.screens.single.password
 
 import android.content.Intent
-import android.credentials.ui.ProviderPendingIntentResponse
-import android.credentials.ui.UserSelectionDialogResult
+import android.credentials.selection.ProviderPendingIntentResponse
+import android.credentials.selection.UserSelectionDialogResult
 import androidx.activity.result.IntentSenderRequest
 import androidx.annotation.MainThread
 import androidx.lifecycle.ViewModel
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index 3a0e51b..4f61966 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -64,6 +64,8 @@
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.semantics.clearAndSetSemantics
+import androidx.compose.ui.semantics.heading
+import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.Constraints
@@ -129,7 +131,8 @@
         modifier = Modifier.padding(
             start = SettingsDimension.itemPaddingAround,
             end = SettingsDimension.itemPaddingEnd,
-        ),
+        )
+        .semantics { heading() },
         overflow = TextOverflow.Ellipsis,
         maxLines = maxLines,
     )
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
index e099f11..0a424bc 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
@@ -37,10 +37,11 @@
 fun Context.broadcastReceiverFlow(intentFilter: IntentFilter): Flow<Intent> = callbackFlow {
     val broadcastReceiver = object : BroadcastReceiver() {
         override fun onReceive(context: Context, intent: Intent) {
+            Log.d(TAG, "onReceive: $intent")
             trySend(intent)
         }
     }
-    registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
+    registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS)
 
     awaitClose { unregisterReceiver(broadcastReceiver) }
 }.catch { e ->
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
index 81a8b32..cea3d13 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
@@ -37,6 +37,7 @@
 interface AppRepository {
     fun loadLabel(app: ApplicationInfo): String
 
+    @Suppress("ABSTRACT_COMPOSABLE_DEFAULT_PARAMETER_VALUE")
     @Composable
     fun produceLabel(app: ApplicationInfo, isClonedAppPage: Boolean = false): State<String> {
         val context = LocalContext.current
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
index eef5225..772f925 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
@@ -43,7 +43,7 @@
 
     private val context = mock<Context> {
         on {
-            registerReceiver(any(), eq(INTENT_FILTER), eq(Context.RECEIVER_NOT_EXPORTED))
+            registerReceiver(any(), eq(INTENT_FILTER), eq(Context.RECEIVER_VISIBLE_TO_INSTANT_APPS))
         } doAnswer {
             registeredBroadcastReceiver = it.arguments[0] as BroadcastReceiver
             null
diff --git a/packages/SettingsLib/res/drawable/ic_external_display.xml b/packages/SettingsLib/res/drawable/ic_external_display.xml
new file mode 100644
index 0000000..de50de8
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_external_display.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="25dp"
+    android:viewportWidth="24"
+    android:viewportHeight="25">
+  <group>
+    <clip-path
+        android:pathData="M0,0.307h24v24h-24z"/>
+    <path
+        android:pathData="M8,21.307V19.307H10V17.307H4C3.45,17.307 2.975,17.115 2.575,16.732C2.192,16.332 2,15.857 2,15.307V5.307C2,4.757 2.192,4.29 2.575,3.907C2.975,3.507 3.45,3.307 4,3.307H20C20.55,3.307 21.017,3.507 21.4,3.907C21.8,4.29 22,4.757 22,5.307V15.307C22,15.857 21.8,16.332 21.4,16.732C21.017,17.115 20.55,17.307 20,17.307H14V19.307H16V21.307H8ZM4,15.307H20V5.307H4V15.307ZM4,15.307V5.307V15.307Z"
+        android:fillColor="#E5E3D6"/>
+  </group>
+</vector>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index e3a313c..fd2c076 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Prenttoestel"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Oorfoon"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Randinvoertoestel"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Gehoortoestelle"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi af."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi is ontkoppel."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Kleurregstelling kan nuttig wees wanneer jy die volgende wil doen:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Om kleure meer akkuraat te sien&lt;/li&gt; &lt;li&gt;&amp;nbsp;Om kleure te verwyder om jou te help fokus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laaiproses is onderbreek om battery te beskerm"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Kontroleer tans laaibykomstigheid"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor gegrond op jou gebruik"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laai tans draadloos"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Laai tans"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Laai nie"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Gekoppel, maar laai nie"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Gelaai"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Volgelaai"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Laai wag tans"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Beheer deur administrateur"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Beheer deur Beperkte Instellings"</string>
     <string name="disabled" msgid="8017887509554714950">"Gedeaktiveer"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index ff220fa..5afd9dc 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"تصوير"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"السمّاعة"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"جهاز إدخال ملحق"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"سماعات أذن طبية"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"بلوتوث"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"‏تم إيقاف Wi-Fi."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"‏تم قطع اتصال Wi-Fi."</string>
@@ -220,8 +219,8 @@
     <item msgid="6946761421234586000">"400%"</item>
   </string-array>
     <string name="choose_profile" msgid="343803890897657450">"اختيار ملف شخصي"</string>
-    <string name="category_personal" msgid="6236798763159385225">"التطبيقات الشخصية"</string>
-    <string name="category_work" msgid="4014193632325996115">"تطبيقات العمل"</string>
+    <string name="category_personal" msgid="6236798763159385225">"الحسابات الشخصية"</string>
+    <string name="category_work" msgid="4014193632325996115">"حسابات العمل"</string>
     <string name="category_private" msgid="4244892185452788977">"ملف شخصي"</string>
     <string name="category_clone" msgid="1554511758987195974">"استنساخ"</string>
     <string name="development_settings_title" msgid="140296922921597393">"خيارات المطورين"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"‏يمكنك الاستفادة من ميزة \"تصحيح الألوان\" من أجل:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;رؤية الألوان بدقة أكبر&lt;/li&gt; &lt;li&gt;&amp;nbsp;إزالة الألوان لمساعدتك على التركيز&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"‫<xliff:g id="LEVEL">%1$s</xliff:g> - الشحن معلَّق لحماية البطارية"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"‫<xliff:g id="LEVEL">%1$s</xliff:g> - يجب فحص ملحق الشحن"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا."</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا، بناءً على استخدامك"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"جارٍ الشحن لاسلكيًا"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"جارٍ الشحن"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"لا يتم الشحن"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"الجهاز متصل ولكن لا يتم شحنه"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"مشحونة"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"البطارية مشحونة بالكامل."</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"الشحن معلَّق"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"إعدادات يتحكم فيها المشرف"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"يتحكّم فيه إعداد محظور"</string>
     <string name="disabled" msgid="8017887509554714950">"غير مفعّل"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 63154fc..0ee8b89 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Şəkilləndirmə"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Qulaqlıq"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Daxiletmə periferiki"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Eşitmə aparatları"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi sönülüdür."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi bağlantı kəsildi."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Rəng korreksiyası bunları etmək istədikdə faydalı ola bilər:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Rəngləri daha dəqiq görmək&lt;/li&gt; &lt;li&gt;&amp;nbsp;Fokuslanmaq üçün rəngləri ləğv etmək&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batareyanı qorumaq üçün şarj gözlədilir"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj aksesuarı yoxlanır"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"İstifadəyə əsasən təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Simsiz şarj edilir"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Şarj edilir"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Doldurulmur"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Qoşulub, amma şarj edilmir"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Şarj edilib"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Tam şarj edilib"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Şarj gözlədilir"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Admin tərəfindən nəzarət olunur"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Məhdudlaşdırılmış Ayar ilə nəzarət edilir"</string>
     <string name="disabled" msgid="8017887509554714950">"Deaktiv"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 14f3883..0cf6887 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Obrada slika"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Slušalice"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periferni uređaj za unos"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Slušni aparati"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"WiFi je isključen."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"WiFi veza je prekinuta."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korekcija boja može da bude korisna kada želite:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Preciznije da vidite boje&lt;/li&gt; &lt;li&gt;&amp;nbsp;Da uklonite boje kako biste se fokusirali&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je na čekanju da bi se zaštitila baterija"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provera dodatne opreme za punjenje"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> na osnovu korišćenja"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Punjenje"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Uređaj je povezan, ali se ne puni"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Napunjeno do kraja"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Punjenje je na čekanju"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontroliše administrator"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolišu ograničena podešavanja"</string>
     <string name="disabled" msgid="8017887509554714950">"Onemogućeno"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 53ffe11..b7e90bc 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Изображения"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Слушалки"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферен вход"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слухови апарати"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi е изключен."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Няма връзка с Wi-Fi."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Функцията за корекция на цветовете може да бъде полезна, когато искате:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;да виждате по-точни цветове;&lt;/li&gt; &lt;li&gt;&amp;nbsp;да премахнете цветовете, за да се съсредоточите.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зареждането е поставено на пауза с цел запазване на батерията"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Аксесоарът за зареждане се проверява"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g> въз основа на използването"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Зарежда се безжично"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Зареждане"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се зарежда"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Свързано, но не се зарежда"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Заредена"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Напълно заредено"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Зареждането е поставено на пауза"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролира се от администратор"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Управлява се чрез ограничена настройка"</string>
     <string name="disabled" msgid="8017887509554714950">"Деактивирано"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 006849e..d2bcfb6 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -154,7 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Snimanje"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Slušalice"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Ulazni periferni uređaj"</string>
-    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Slušna pomagala"</string>
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Slušni aparati"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"WiFi je isključen."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"WiFi nije povezan."</string>
@@ -456,8 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Ispravka boja može biti korisna kada želite:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;jasnije vidjeti boje&lt;/li&gt; &lt;li&gt;&amp;nbsp;ukloniti boje radi lakšeg fokusiranja&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je pauzirano radi zaštite baterije"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjera dodatka za punjenje"</string>
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je na čekanju radi zaštite baterije"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjera opreme za punjenje"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> na osnovu vaše potrošnje"</string>
@@ -486,10 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Punjenje"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
-    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Povezano, ali se ne puni"</string>
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Uređaj je povezan, ali se ne puni"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Potpuno napunjeno"</string>
-    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Punjenje na čekanju"</string>
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Punjenje je na čekanju"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Pod kontrolom administratora"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolira ograničena postavka"</string>
     <string name="disabled" msgid="8017887509554714950">"Onemogućeno"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 6e95b3b..a556cf1 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imatges"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Auricular"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Perifèric d\'entrada"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Audiòfons"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi desactivada."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi desconnectada."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"La correcció de color pot ser útil si vols:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Veure els colors amb més precisió.&lt;/li&gt; &lt;li&gt;&amp;nbsp;Suprimir els colors per concentrar-te millor.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: la càrrega s\'ha posat en espera per protegir la bateria"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: s\'està comprovant l\'accessori de càrrega"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregant sense fil"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"S\'està carregant"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"No s\'està carregant"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connectat, però sense carregar"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Totalment carregada"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Càrrega en espera"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlat per l\'administrador"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlat per la configuració restringida"</string>
     <string name="disabled" msgid="8017887509554714950">"Desactivat"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 96ee652..45e089e 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Zobrazovací zařízení"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Sluchátka"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periferní vstupní zařízení"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Naslouchátka"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Síť Wi-Fi je vypnuta."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Síť Wi-Fi je odpojena."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korekce barev se může hodit, když chcete:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Vidět barvy přesněji.&lt;/li&gt; &lt;li&gt;&amp;nbsp;Odstranit barvy kvůli zlepšení soustředění.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Nabíjení je pozastaveno za účelem ochrany baterie"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Kontrola nabíjecího příslušenství"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Při vašem obvyklém využití zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bezdrátové nabíjení"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Nabíjení"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenabíjí se"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Připojeno, ale nenabíjí se"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Nabito"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Plně nabito"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Nabíjení pozastaveno"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Spravováno administrátorem"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Spravováno omezeným nastavením"</string>
     <string name="disabled" msgid="8017887509554714950">"Deaktivováno"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 61d0315..89d34a6 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Billede"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Hovedtelefoner"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Eksterne inputenheder"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Høreapparater"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi er slået fra."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi er afbrudt."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Farvekorrigering kan være en nyttig funktion, når du vil:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Se farver mere nøjagtigt&lt;/li&gt; &lt;li&gt;&amp;nbsp;Fjerne farver, så du nemmere kan fokusere&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Opladningen er sat på pause for at beskytte batteriet"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tjekker opladningstilbehøret"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage, alt efter hvordan du bruger enheden"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Trådløs opladning"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Oplader"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Oplader ikke"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Forbundet, men oplader ikke"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Opladet"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fuldt opladet"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Opladningen er blevet sat på pause"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolleret af administratoren"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Styres af en begrænset indstilling"</string>
     <string name="disabled" msgid="8017887509554714950">"Deaktiveret"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 2e4e507..b7df368 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Απεικόνιση"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Ακουστικά"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Περιφερειακό εισόδου"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Βοηθήματα ακοής"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi ανενεργό."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Το Wi-Fi έχει αποσυνδεθεί."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Η διόρθωση χρωμάτων μπορεί να σας φανεί χρήσιμη όταν θέλετε:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Μεγαλύτερη ακρίβεια στην απεικόνιση χρωμάτων&lt;/li&gt; &lt;li&gt;&amp;nbsp;Να καταργήσετε χρώματα για να συγκεντρωθείτε&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Η φόρτιση τέθηκε σε αναμονή για προστασία της μπαταρίας"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Έλεγχος αξεσουάρ φόρτισης"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>, βάσει της χρήσης σας"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ασύρματη φόρτιση"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Φόρτιση"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Δεν φορτίζει"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Συνδέθηκε, αλλά δεν φορτίζει"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Φορτισμένη"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Πλήρως φορτισμένο"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Η φόρτιση τέθηκε σε αναμονή"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Ελέγχονται από το διαχειριστή"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ελέγχεται από τη Ρύθμιση με περιορισμό"</string>
     <string name="disabled" msgid="8017887509554714950">"Απενεργοποιημένο"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 3c6e70e..66aaaf5 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imaging"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Input Peripheral"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Hearing aids"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi off."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi disconnected."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Colour correction can be helpful when you want to:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;See colours more accurately&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Charging"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connected, but not charging"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fully charged"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Charging on hold"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
     <string name="disabled" msgid="8017887509554714950">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 3c6e70e..66aaaf5 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imaging"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Input Peripheral"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Hearing aids"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi off."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi disconnected."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Colour correction can be helpful when you want to:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;See colours more accurately&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Charging"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connected, but not charging"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fully charged"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Charging on hold"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
     <string name="disabled" msgid="8017887509554714950">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 3c6e70e..66aaaf5 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imaging"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Input Peripheral"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Hearing aids"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi off."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi disconnected."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Colour correction can be helpful when you want to:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;See colours more accurately&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Charging"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connected, but not charging"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fully charged"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Charging on hold"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
     <string name="disabled" msgid="8017887509554714950">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 19f8b21..5e496cd 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -181,7 +181,7 @@
     <string name="launch_defaults_none" msgid="8049374306261262709">"Sin configuraciones predeterminadas"</string>
     <string name="tts_settings" msgid="8130616705989351312">"Configuración de texto a voz"</string>
     <string name="tts_settings_title" msgid="7602210956640483039">"Salida de texto a voz"</string>
-    <string name="tts_default_rate_title" msgid="3964187817364304022">"Velocidad de voz"</string>
+    <string name="tts_default_rate_title" msgid="3964187817364304022">"Velocidad de habla"</string>
     <string name="tts_default_rate_summary" msgid="3781937042151716987">"Velocidad en la que se habla el texto"</string>
     <string name="tts_default_pitch_title" msgid="6988592215554485479">"Tono"</string>
     <string name="tts_default_pitch_summary" msgid="9132719475281551884">"Afecta el tono de la voz sintetizada"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8334379a..3ce371f 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Escáner"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Auriculares"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periférico de entrada"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Audífonos"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi desactivado."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi desconectado."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Corrección de color puede ser útil si quieres:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ver los colores mejor&lt;/li&gt; &lt;li&gt;&amp;nbsp;Quitar los colores para concentrarte mejor&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga pausada para proteger la batería"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Comprobando accesorio de carga"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tiempo restante aproximado según tu uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carga inalámbrica"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Cargando"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectado, pero sin cargar"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Carga completa"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Carga pausada"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlada por el administrador"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlado por ajustes restringidos"</string>
     <string name="disabled" msgid="8017887509554714950">"Inhabilitada"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 35fd2da..115a64a 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Pildindus"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Kõrvaklapid"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Sisestatud välisseade"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Kuuldeaparaadid"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"WiFi on välja lülitatud."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"WiFi-ühendus on katkestatud."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Värvide korrigeerimisest võib abi olla, kui soovite:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;värve täpsemalt näha;&lt;/li&gt; &lt;li&gt;&amp;nbsp;värve eemaldada, et paremini keskenduda.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine on aku kaitsmiseks ootele pandud"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimistarviku kontrollimine"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Teie kasutuse põhjal on jäänud ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Juhtmevaba laadimine"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Laadimine"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ühendatud, kuid ei laadita"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Laetud"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Täielikult laetud"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Laadimine on ootele pandud"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Juhib administraator"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Haldavad piiranguga seaded"</string>
     <string name="disabled" msgid="8017887509554714950">"Keelatud"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 89ab3a4..f1e507e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Irudietarako gailua"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Entzungailua"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Idazteko gailua"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Audifonoak"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth bidezko gailua"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Desaktibatuta dago wifi-konexioa."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Deskonektatu egin da wifi-konexioa."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Baliteke koloreen zuzenketa lagungarria izatea hauek egin nahi dituzunean:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Koloreak zehaztasun handiagoz ikusi.&lt;/li&gt; &lt;li&gt;&amp;nbsp;Koloreak kendu, arreta gal ez dezazun.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: kargatze-prozesua zain dago bateria babesteko"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: kargatzeko osagarria egiaztatzen"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Erabilera kontuan izanda, <xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hari gabe kargatzen"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Kargatzen"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ez da kargatzen ari"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Konektatuta dago, baina ez da kargatzen ari"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Kargatuta"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Erabat kargatuta"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Kargatze-prozesua zain dago"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Administratzaileak kontrolatzen du"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ezarpen mugatuak kontrolatzen du"</string>
     <string name="disabled" msgid="8017887509554714950">"Desgaituta"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index cb6d27b..5d23510 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imagerie"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Écouteurs"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Périphérique d\'entrée"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Prothèses auditives"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi désactivé."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi déconnecté."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"La correction des couleurs peut être utile lorsque vous souhaitez :&lt;br/&gt; &lt;ol&gt; &lt;li&gt; voir les couleurs avec plus de précision;&lt;/li&gt; &lt;li&gt; retirer les couleurs pour vous aider à vous concentrer.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> : <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – La recharge a été mise en pause pour protéger la pile"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Vérification de l\'accessoire de recharge en cours…"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> en fonction de votre usage"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"En recharge sans fil"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Recharge en cours…"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"N\'est pas en charge"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connecté, mais ne se recharge pas"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Chargée"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Complètement rechargée"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Recharge en pause"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Contrôlé par l\'administrateur"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Contrôlé par les paramètres restreints"</string>
     <string name="disabled" msgid="8017887509554714950">"Désactivée"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 11d0838..75eb21f 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Dispositivo de imaxe"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Auriculares"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periférico de entrada"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Audiófonos"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi desactivada."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi desconectada."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"A corrección da cor pode serche útil se queres:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ver mellor as cores&lt;/li&gt; &lt;li&gt;&amp;nbsp;Quitar as cores para concentrarte mellor&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>. A carga púxose en pausa para protexer a batería"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>. Comprobando accesorio de carga"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tempo restante aproximado (<xliff:g id="LEVEL">%2$s</xliff:g>): <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tempo restante aproximado en función do uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Cargando sen fíos"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Cargando"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Non se está cargando"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectado, pero non cargando"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Carga completa"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Carga en pausa"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Opción controlada polo administrador"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Baixo o control de opcións restrinxidas"</string>
     <string name="disabled" msgid="8017887509554714950">"Desactivada"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index ebd02c3..e477063 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ઇમેજિંગ"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"હેડફોન"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ઇનપુટ પેરિફેરલ"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"સાંભળવામાં મદદ આપતા યંત્રો"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"બ્લૂટૂથ"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi બંધ."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi ડિસ્કનેક્ટ થયું."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"રંગમાં સુધારણા કરવાની સુવિધાનો ઉપયોગ ત્યારે સહાયરૂપ બની શકે છે કે જ્યારે તમે આ કરવા માગતા હો:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;વધુ સચોટપણે રંગ જોવા&lt;/li&gt; &lt;li&gt;&amp;nbsp;ફોકસ કરવામાં સહાય માટે અમુક રંગ કાઢી નાખવા&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - બૅટરીને સુરક્ષિત રાખવા માટે, ચાર્જિંગ હોલ્ડ પર રાખવામાં આવ્યું છે"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ ઍક્સેસરી ચેક કરી રહ્યાં છીએ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"તમારા વપરાશના આધારે લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"વાયરલેસથી ચાર્જિંગ"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ચાર્જ થઈ રહ્યું છે"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"ચાર્જ થઈ રહ્યું નથી"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"કનેક્ટેડ છે, પરંતુ ચાર્જ થઈ રહ્યું નથી"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"ચાર્જ થયું"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"સંપૂર્ણપણે ચાર્જ છે"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ચાર્જિંગ હોલ્ડ પર રાખવામાં આવ્યું"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"વ્યવસ્થાપક દ્વારા નિયંત્રિત"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"પ્રતિબંધિત સેટિંગ દ્વારા નિયંત્રિત"</string>
     <string name="disabled" msgid="8017887509554714950">"અક્ષમ કર્યો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index e03de15..0e91a37 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"इमेजिंग"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"हेडफ़ोन"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"इनपुट पेरिफ़ेरल"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"कान की मशीनें"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ब्लूटूथ"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"वाई-फ़ाई बंद है."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"वाई-फ़ाई डिसकनेक्ट है."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"रंग में सुधार करने की सुविधा का इस्तेमाल, इन मामलों में किया जा सकता है:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;आपको ज़्यादा सटीक तरह से रंग देखने हों&lt;/li&gt; &lt;li&gt;&amp;nbsp;ज़्यादा फ़ोकस करने के लिए, आपको कुछ खास रंग हटाने हों&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - बैटरी को सुरक्षित रखने के लिए, फ़ोन को चार्ज होने से रोक दिया गया है"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग ऐक्सेसरी की जांच की जा रही है"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"आपके इस्तेमाल के हिसाब से बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस चार्जिंग"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"चार्ज हो रहा है"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज नहीं हो रही है"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"फ़ोन कनेक्ट हो गया, लेकिन चार्ज नहीं हो रहा है"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"बैटरी चार्ज हो गई"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"बैटरी पूरी चार्ज है"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"फ़ोन को चार्ज होने से रोक दिया गया है"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"इसका नियंत्रण एडमिन के पास है"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"इसे पाबंदी मोड वाली सेटिंग से कंट्रोल किया जाता है"</string>
     <string name="disabled" msgid="8017887509554714950">"बंद किया गया"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 8bc6f66..1b28a0d 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Պատկերներ"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Ականջակալ"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Մուտքի արտաքին սարքեր"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Լսողական սարք"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi-ն անջատված է:"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi-ը կապակցված չէ:"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Գունաշտկումը կարող է օգնել, երբ դուք ուզում եք՝&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ավելի հստակ տեսնել գույները&lt;/li&gt; &lt;li&gt;&amp;nbsp;Հեռացնել գույները, որպեսզի կարողանաք կենտրոնանալ&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումը դադարեցվել է՝ մարտկոցը պաշտպանելու համար"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորման սարքը ստուգվում է"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Լիցքը (<xliff:g id="LEVEL">%2$s</xliff:g>) կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>՝ կախված օգտագործման եղանակից"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Անլար լիցքավորում"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Լիցքավորում"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Չի լիցքավորվում"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Սարքը միացած է, սակայն չի լիցքավորվում"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Լիցքավորված է"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Լրիվ լիցքավորված է"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Լրցքավորումը դադարեցված է"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Վերահսկվում է ադմինիստրատորի կողմից"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Կառավարվում է սահմանափակ ռեժիմի կարգավորումներով"</string>
     <string name="disabled" msgid="8017887509554714950">"Կասեցված է"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 2f27c62..9e9c79c 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Pencitraan"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periferal Masukan"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Alat Bantu Dengar"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi tidak aktif."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi tidak terhubung."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Koreksi warna dapat berguna jika Anda ingin:&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Melihat warna dengan lebih akurat&lt;/li&gt; &lt;li&gt; Menghapus warna agar Anda lebih fokus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dihentikan sementara untuk melindungi baterai"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Memeriksa aksesori pengisi daya"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi berdasarkan penggunaan Anda"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengisi daya nirkabel"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Pengisian daya"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengisi daya"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Terhubung, tetapi tidak mengisi daya"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Terisi"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Baterai Terisi Penuh"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Pengisian daya dihentikan sementara"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Dikontrol oleh admin"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Dikontrol oleh Setelan Terbatas"</string>
     <string name="disabled" msgid="8017887509554714950">"Dinonaktifkan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index c2d6de3..071597a 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Myndherming"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Heyrnartól"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Jaðartæki með inntak"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Heyrnartæki"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Slökkt á Wi-Fi."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi ótengt."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Litaleiðrétting kemur m.a. að gagni þegar þú vilt:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Sjá liti í aukinni skerpu&lt;/li&gt; &lt;li&gt;&amp;nbsp;Fjarlægja liti til að geta einbeitt þér betur&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Hleðsla í bið til að vernda rafhlöðuna"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Athugar hleðslutæki"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir miðað við notkun þína"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hleður þráðlaust"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Í hleðslu"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ekki í hleðslu"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Tækið er tengt en hleðst ekki"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Fullhlaðin"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Full hleðsla"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Hleðsla í bið"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Stjórnað af kerfisstjóra"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Stýrt af takmarkaði stillingu"</string>
     <string name="disabled" msgid="8017887509554714950">"Óvirkt"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 27b23b7..0540432 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Sistema di imaging"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Cuffie"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periferica di immissione"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Apparecchi acustici"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi non attivo."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Rete Wi-Fi scollegata."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"La correzione del colore può essere utile quando vuoi:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Vedere i colori con più precisione&lt;/li&gt; &lt;li&gt;&amp;nbsp;Rimuovere i colori per mettere meglio a fuoco&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica in sospeso per proteggere la batteria"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Controllo dell\'accessorio di ricarica"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tempo rimanente in base al tuo utilizzo: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"In carica, wireless"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"In carica"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Non in carica"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connesso, ma non in carica"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Carica"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Batteria completamente carica"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Ricarica in sospeso"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Gestita dall\'amministratore"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Gestita tramite impostazioni con restrizioni"</string>
     <string name="disabled" msgid="8017887509554714950">"Disattivato"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 0c3c4f7..6dbf7ab 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"הדמיה"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"אוזניות"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ציוד קלט היקפי"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"מכשירי שמיעה"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"‏Wi-Fi כבוי."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"‏Wi-Fi מנותק."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"‏תיקון הצבע יכול לעזור אם רוצים:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;לראות צבעים מדויקים יותר&lt;/li&gt; &lt;li&gt;&amp;nbsp;לראות פחות צבעים כדי לשפר את הריכוז&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – הטעינה הושהתה כדי להגן על הסוללה"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – מתבצעת בדיקה של אביזר הטעינה"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"הזמן הנותר על סמך השימוש שלך: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"בטעינה אלחוטית"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"טעינה"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"לא בטעינה"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"המכשיר מחובר אבל לא נטען"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"הסוללה טעונה"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"טעונה במלואה"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"הטעינה הושהתה"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"נמצא בשליטת מנהל מערכת"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"בשליטה של הגדרה מוגבלת"</string>
     <string name="disabled" msgid="8017887509554714950">"מושבת"</string>
@@ -527,7 +522,7 @@
     <string name="ims_reg_title" msgid="8197592958123671062">"‏סטטוס הרשמה ל-IMS"</string>
     <string name="ims_reg_status_registered" msgid="884916398194885457">"רשום"</string>
     <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"לא רשום"</string>
-    <string name="status_unavailable" msgid="5279036186589861608">"לא זמין"</string>
+    <string name="status_unavailable" msgid="5279036186589861608">"לא זמינה"</string>
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"‏כתובת ה-MAC אקראית"</string>
     <string name="wifi_tether_connected_summary" msgid="5100712926640492336">"{count,plural, =1{מכשיר אחד מחובר}one{# מכשירים מחוברים}two{# מכשירים מחוברים}other{# מכשירים מחוברים}}"</string>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"יותר זמן."</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 3f71b39..cc560b8 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Бейне құралы"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Құлақаспап"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Кіріс құралы"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Есту аппараттары"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi өшірулі."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi ажыратылған."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Түсті түзету мына жағдайларда пайдалы болуы мүмкін:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;түстерді анығырақ көру;&lt;/li&gt; &lt;li&gt;&amp;nbsp;зейін қоюға көмектесу үшін түстерді алып тастау.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: батареяны қорғау үшін зарядтау кідіртіледі."</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: зарядтау құрылғысы тексеріледі."</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Пайдалану деректеріңізге сәйкес енді шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Сымсыз зарядталуда"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Зарядталып жатыр."</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Зарядталу орындалып жатқан жоқ"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Құрылғы жалғанған, бірақ зарядталып жатқан жоқ."</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Зарядталды"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Толық зарядталды."</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Зарядтау кідіртілді."</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Әкімші басқарады"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Шектелген параметрлер арқылы басқарылады."</string>
     <string name="disabled" msgid="8017887509554714950">"Өшірілген"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index e7f0220..0288e92 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ಇಮೇಜಿಂಗ್"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ಹೆಡ್‌ಫೋನ್"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ಪೆರಿಪೆರಲ್ ಇನ್‌ಪುಟ್‌‌"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ಬ್ಲೂಟೂತ್"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"ವೈಫೈ ಆಫ್."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"ವೈಫೈ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"ನೀವು ಹೆಚ್ಚು ಸ್ಪಷ್ಟವಾದ ಬಣ್ಣಗಳನ್ನು ನೋಡಲು ಬಯಸಿದರೆ :&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp; ಬಣ್ಣದ ತಿದ್ದುಪಡಿಯು ಸಹಾಯಕವಾಗಿರುತ್ತದೆ; ಗಮನವನ್ನು ಕೇಂದ್ರೀಕರಿಸಲು ನಿಮಗೆ ಸಹಾಯ ಮಾಡಲು ಬಣ್ಣಗಳನ್ನು ತೆಗೆದುಹಾಕಿ &lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಬ್ಯಾಟರಿಯನ್ನು ರಕ್ಷಿಸಲು ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ಹೋಲ್ಡ್‌ ಮಾಡಲಾಗಿದೆ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಪರಿಕರವನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"(<xliff:g id="LEVEL">%2$s</xliff:g>) ತಲುಪಲು <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ನಿಮ್ಮ ಬಳಕೆಯ ಆಧಾರದ ಮೇಲೆ ಸುಮಾರು <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ವೈರ್‌ಲೆಸ್ ಚಾರ್ಜಿಂಗ್"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"ಚಾರ್ಜ್‌ ಆಗುತ್ತಿಲ್ಲ"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ, ಆದರೆ ಚಾರ್ಜಿಂಗ್ ಆಗುತ್ತಿಲ್ಲ"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"ಪೂರ್ಣವಾಗಿ ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ಹೋಲ್ಡ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ನಿರ್ವಾಹಕರ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ನಿರ್ಬಂಧಿಸಲಾದ ಸೆಟ್ಟಿಂಗ್ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗುತ್ತದೆ"</string>
     <string name="disabled" msgid="8017887509554714950">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index df43494..432f4ed 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"이미징"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"헤드폰"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"입력 주변기기"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"보청기"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"블루투스"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi가 꺼져 있습니다."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi 연결이 끊어졌습니다."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"색상 보정은 다음과 같은 경우에 유용할 수 있습니다.&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;색상을 보다 정확하게 확인하려는 경우&lt;/li&gt; &lt;li&gt;&amp;nbsp;집중에 도움이 되도록 색상을 제거하려는 경우&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>, <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 배터리 보호를 위해 충전 일시중지"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 액세서리 확인 중"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"남은 시간: 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"남은 시간 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"내 사용량을 기준으로 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> 남음"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"무선 충전 중"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"충전"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"충전 안함"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"연결되었으나 충전 중이 아님"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"충전됨"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"완전히 충전됨"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"충전 일시중지"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"관리자가 제어"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"제한된 설정으로 제어됨"</string>
     <string name="disabled" msgid="8017887509554714950">"사용 안함"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 6e6926e..aa685a2 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Сүрөт тартуучу түзмөк"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Кулакчын"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Дайындарды киргизүүчү тышкы түзмөк"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Угуу аппараттары"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi өчүк."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi туташуусу жок."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Түстөрдү тууралоо менен:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Керектүү түстөрдү аласыз&lt;/li&gt; &lt;li&gt;&amp;nbsp;Алагды кылган түстөрдү өчүрүп саласыз&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батареяны коргоо үчүн кубаттоо тындырылды"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубаттоо шайманы текшерилүүдө"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Колдонгонуңузга караганда болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Зымсыз кубатталууда"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Кубатталууда"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Кубат алган жок"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Туташкан, бирок кубатталбай жатат"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Кубатталды"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Толук кубатталды"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Кубаттоо күтүү режиминде"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Администратор тарабынан көзөмөлдөнөт"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Чектелген параметр аркылуу көзөмөлдөнөт"</string>
     <string name="disabled" msgid="8017887509554714950">"Өчүрүлгөн"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 5e2f696..d0d9507 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Vaizdavimo įrenginys"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Ausinės"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Išorinis įvesties įrenginys"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Klausos aparatai"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"„Wi-Fi“ išjungtas."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"„Wi-Fi“ atjungtas."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Spalvų taisymas gali būti naudingas, kai norite:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;aiškiau matyti spalvas;&lt;/li&gt; &lt;li&gt;&amp;nbsp;pašalinti spalvas, kad galėtumėte sutelkti dėmesį.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkrovimas pristabdytas, siekiant apsaugoti akumuliatorių"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – tikrinamas įkrovimo priedas"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>, atsižvelgiant į naudojimą"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kraunama be laidų"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Įkraunama"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nekraunama"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Prijungta, bet nekraunama"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Įkrauta"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Visiškai įkrautas"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Įkrovimas pristabdytas"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Valdo administratorius"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Valdoma pagal apribotą nustatymą"</string>
     <string name="disabled" msgid="8017887509554714950">"Neleidžiama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index f9bab6f..43a940b 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Attēlu apstrādes ierīce"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Austiņas"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Ievades ierīce"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Dzirdes aparāti"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi savienojums izslēgts"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi savienojums pārtraukts"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Krāsu korekcija var būt noderīga šādiem mērķiem:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;precīzākai krāsu attēlošanai;&lt;/li&gt; &lt;li&gt;&amp;nbsp;krāsu noņemšanai, lai būtu vieglāk koncentrēties.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> — <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> — uzlāde apturēta, lai aizsargātu akumulatoru"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> — notiek uzlādes piederuma pārbaude"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ņemot vērā lietojumu, atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bezvadu uzlāde"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Notiek uzlāde"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenotiek uzlāde"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Savienota, taču netiek uzlādēta"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Uzlādēts"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Pilnībā uzlādēts"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Uzlāde apturēta"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolē administrators"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolē ierobežots iestatījums"</string>
     <string name="disabled" msgid="8017887509554714950">"Atspējots"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index aafa846..db5bdf4 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Слики"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Слушалка"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферен влез"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слушни помагала"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi е исклучено."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi е исклучено."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Корекцијата на боите може да биде корисна кога сакате:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;да ги гледате боите попрецизно&lt;/li&gt; &lt;li&gt;&amp;nbsp;да ги отстраните боите за полесно да се концентрирате&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - полнењето е паузирано за да се заштити батеријата"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - се проверува додатокот за полнење"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g> според вашето користење"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Се полни безжично"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Се полни"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се полни"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Поврзано, но не се полни"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Полна"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Целосно полна"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Полнењето е паузирано"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролирано од администраторот"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролирано со ограничени поставки"</string>
     <string name="disabled" msgid="8017887509554714950">"Оневозможено"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c857a2b..787ce97 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Зураглал"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Чихэвч"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Нэмэлт оролт"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Сонсголын төхөөрөмжүүд"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi унтраалттай байна."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi холбогдоогүй байна."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Өнгө тохируулга нь таныг дараахыг хийхийг хүсэх үед хэрэгтэй байж болно:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Өнгөнүүдийг илүү нарийвчилж харах&lt;/li&gt; &lt;li&gt;&amp;nbsp;Төвлөрөхийн тулд өнгөнүүдийг хасах&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарейг хамгаалахын тулд цэнэглэхийг хүлээлгэсэн"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэх нэмэлт хэрэгслийг шалгаж байна"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Таны хэрэглээнд үндэслэн ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Утасгүй цэнэглэж байна"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Цэнэглэж байна"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Цэнэглэхгүй байна"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Холбогдсон ч цэнэглэхгүй байна"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Цэнэглэсэн"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Бүрэн цэнэглэсэн"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Цэнэглэхийг хүлээлгэд оруулсан"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Админ удирдсан"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Хязгаарлагдсан тохиргоогоор хянадаг"</string>
     <string name="disabled" msgid="8017887509554714950">"Идэвхгүйжүүлсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 26669b9..00482ea 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"इमेज"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"हेडफोन"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"इनपुट परिधीय"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"श्रवणयंत्रे"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ब्लूटूथ"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"वाय-फाय बंद."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"वाय-फाय डिस्कनेक्ट झाले."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"तुम्हाला पुढील गोष्टी करायच्या असतील, तेव्हा रंग सुधारणेची मदत होऊ शकते:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;रंग आणखी अचूकपणे पाहण्यासाठी&lt;/li&gt; &lt;li&gt;&amp;nbsp;तुम्हाला लक्ष केंद्रित करण्यात मदत करण्याकरिता रंग काढून टाकण्यासाठी&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - बॅटरीचे संरक्षण करण्यासाठी चार्जिंग थांबवले आहे"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंगसंबंधित ॲक्सेसरी तपासत आहे"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"तुमच्‍या वापरावर आधारित अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेसने चार्ज होत आहे"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"चार्ज होत आहे"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज होत नाही"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"कनेक्ट केलेले आहे, पण चार्ज होत नाही"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"चार्ज झाली"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"पूर्ण चार्ज झाली"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"चार्जिंग थांबवले आहे"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"प्रशासकाने नियंत्रित केलेले"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"प्रतिबंधित केलेल्या सेटिंग द्वारे नियंत्रित"</string>
     <string name="disabled" msgid="8017887509554714950">"अक्षम"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index dd31c85..bd3eb99 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Pengimejan"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Fon kepala"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Persisian Input"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Alat Bantu Pendengaran"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi dimatikan."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi diputuskan sambungannya."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Pembetulan warna dapat membantu apabila anda mahu:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Melihat warna dengan lebih tepat&lt;/li&gt; &lt;li&gt;&amp;nbsp;Mengalih keluar warna agar anda dapat menumpukan perhatian&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan ditunda untuk melindungi bateri"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Memeriksa aksesori pengecasan"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi berdasarkan penggunaan anda"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengecas tanpa wayar"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Pengecasan"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengecas"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Disambungkan tetapi tidak dicas"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Sudah dicas"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Dicas Penuh"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Pengecasan ditunda"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Dikawal oleh pentadbir"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Dikawal oleh Tetapan Terhad"</string>
     <string name="disabled" msgid="8017887509554714950">"Dilumpuhkan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7c74e1b..c18b273 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ဓာတ်ပုံဆိုင်ရာ"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"နားကြပ်"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ချိတ်ဆက်အသုံးပြုရသည့် စက်ပစ္စည်းများ"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"နားကြားကိရိယာ"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ဘလူးတုသ်"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi  ပိတ်ထားသည်"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi  ချိတ်ဆက်ထားမှု မရှိပါ"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း&lt;/li&gt; &lt;li&gt;&amp;nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ဘက်ထရီကာကွယ်ရန် အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းပစ္စည်း စစ်ဆေးနေသည်"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည် (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"သင်၏ အသုံးပြုမှု အပေါ် မူတည်၍ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ကြိုးမဲ့ အားသွင်းနေသည်"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"အားသွင်းနေသည်"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"အားသွင်းမနေပါ"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"ချိတ်ဆက်ထားသော်လည်း အားသွင်းမနေပါ"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"အားသွင်းပြီးပါပြီ"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"အားအပြည့်သွင်းထားသည်"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"စီမံခန့်ခွဲသူမှ ထိန်းချုပ်ပါသည်"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ကန့်သတ်ထားသော ဆက်တင်များဖြင့် ထိန်းချုပ်ထားသည်"</string>
     <string name="disabled" msgid="8017887509554714950">"ပိတ်ထားပြီး"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 4782f26..b3c4295 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Bildefremviser"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Øretelefoner"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Inndata fra ytre utstyrsenheter"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Høreapparater"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi er av."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi er frakoblet."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Fargekorrigering kan være nyttig når du vil&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;se farger mer nøyaktig&lt;/li&gt; &lt;li&gt;&amp;nbsp;fjerne farger for å gjøre det enklere å fokusere&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladingen er satt på vent for å beskytte batteriet"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Sjekker ladetilbehøret"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen basert på bruken din"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Lader trådløst"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Lader"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Lader ikke"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Tilkoblet, men lader ikke"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Ladet"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fulladet"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Ladingen er satt på vent"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrollert av administratoren"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrollert av en begrenset innstilling"</string>
     <string name="disabled" msgid="8017887509554714950">"Slått av"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 3a7da74..377078d 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"छवि सम्बन्धी"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"हेडफोन"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"इनपुट सम्बन्धी बाह्य यन्त्र"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"श्रवण यन्त्रहरू"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ब्लुटुथ"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi बन्द।"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi जडान विच्छेद भयो।"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"तपाईं रङ सच्याउने सुविधाका सहायताले निम्न कार्य गर्न सक्नुहुन्छ:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;अझ सटीक तरिकाले रङहरू हेर्न&lt;/li&gt; &lt;li&gt;&amp;nbsp;फोकस गर्नका लागि रङहरू हटाउन&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ब्याट्री जोगाउन चार्जिङ होल्ड गरिएको छ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिङ एक्सेसरीको जाँच गरिँदै छ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"तपाईंको प्रयोगको आधारमा लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस तरिकाले चार्ज गरिँदै छ"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"चार्ज हुँदै छ"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज भइरहेको छैन"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"जोडिएको छ तर चार्ज गरिराखिएको छैन"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"चार्ज भयो"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"पूर्ण रूपमा चार्ज भएको छ"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"चार्जिङ होल्ड गरिएको छ"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"प्रशासकद्वारा नियन्त्रित"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"प्रतिबन्धित सेटिङले नियन्त्रण गरेको"</string>
     <string name="disabled" msgid="8017887509554714950">"असक्षम पारियो"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ea245c48..30bb050 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ଇମେଜିଙ୍ଗ"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ହେଡ୍‌ଫୋନ୍‌"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ଇନ୍‌ପୁଟ୍‌ ଉପକରଣ"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ବ୍ଲୁଟୁଥ"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"ୱାଇ-ଫାଇ ବନ୍ଦ।"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"ୱାଇଫାଇ ବିଚ୍ଛିନ୍ନ କରାଗଲା।"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"ଆପଣ ଏସବୁ କରିବାକୁ ଚାହିଁଲେ ରଙ୍ଗ ସଂଶୋଧନ ଉପଯୋଗୀ ହୋଇପାରିବ:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ଆହୁରି ସଠିକ୍ ଭାବେ ରଙ୍ଗଗୁଡ଼ିକ ଦେଖିବା&lt;/li&gt; &lt;li&gt;&amp;nbsp;ଆପଣଙ୍କୁ ଫୋକସ କରିବାରେ ସାହାଯ୍ୟ କରିବା ପାଇଁ ରଙ୍ଗଗୁଡ଼ିକୁ କାଢ଼ିବା&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍‌ରାଇଡ୍‌ କରାଯାଇଛି"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ବେଟେରୀକୁ ସୁରକ୍ଷିତ ରଖିବା ପାଇଁ ଚାର୍ଜିଂ ହୋଲ୍ଡରେ ଅଛି"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂ ଆକସେସୋରୀକୁ ଯାଞ୍ଚ କରାଯାଉଛି"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ପାଇଁ (<xliff:g id="LEVEL">%2$s</xliff:g>) ବଳକା ଅଛି"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ଆପଣଙ୍କ ବ୍ୟବହାରକୁ ଆଧାର କରି ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ୱେୟରଲେସ ଭାବେ ଚାର୍ଜିଂ"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ଚାର୍ଜ ହେଉଛି"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"ଚାର୍ଜ ହେଉନାହିଁ"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"କନେକ୍ଟ ହୋଇଛି, କିନ୍ତୁ ଚାର୍ଜ ହେଉନାହିଁ"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"ଚାର୍ଜ ହୋଇଯାଇଛି"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"ସମ୍ପୂର୍ଣ୍ଣ ଭାବରେ ଚାର୍ଜ ହୋଇଛି"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ଚାର୍ଜିଂ ହୋଲ୍ଡରେ ଅଛି"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ଆଡ୍‌ମିନ୍‌ ଦ୍ୱାରା ନିୟନ୍ତ୍ରିତ"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ପ୍ରତିବନ୍ଧିତ ସେଟିଂ ଦ୍ୱାରା ନିୟନ୍ତ୍ରଣ କରାଯାଇଛି"</string>
     <string name="disabled" msgid="8017887509554714950">"ଅକ୍ଷମ ହୋଇଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 47c0f8a..d25b921 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ਇਮੇਜਿੰਗ"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ਹੈੱਡਫੋਨ"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ਇਨਪੁੱਟ ਪੈਰਿਫੈਰਲ"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ਬਲੂਟੁੱਥ"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi ਬੰਦ।"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi ਡਿਸਕਨੈਕਟ ਕੀਤਾ।"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"ਰੰਗ ਸੁਧਾਈ ਉਦੋਂ ਲਾਹੇਵੰਦ ਹੋ ਸਕਦੀ ਹੈ, ਜਦੋਂ ਤੁਸੀਂ:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ਰੰਗਾਂ ਨੂੰ ਹੋਰ ਸਹੀ ਢੰਗ ਨਾਲ ਦੇਖਣਾ ਚਾਹੋ&lt;/li&gt; &lt;li&gt;&amp;nbsp;ਫੋਕਸ ਕਰਨ ਵਿੱਚ ਮਦਦ ਲਈ ਰੰਗ ਹਟਾਉਣਾ ਚਾਹੋ&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਦੀ ਸੁਰੱਖਿਆ ਲਈ ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜਿੰਗ ਐਕਸੈਸਰੀ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ਤੁਹਾਡੀ ਵਰਤੋਂ ਦੇ ਆਧਾਰ \'ਤੇ ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ਬਿਨਾਂ ਤਾਰ ਤੋਂ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"ਕਨੈਕਟ ਹੋ ਗਿਆ, ਪਰ ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"ਚਾਰਜ ਹੋ ਗਈ"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"ਪੂਰੀ ਚਾਰਜ ਹੋ ਗਈ ਹੈ"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ਪ੍ਰਤਿਬੰਧਿਤ ਸੈਟਿੰਗ ਰਾਹੀਂ ਕੰਟਰੋਲ ਕੀਤੀ ਜਾਂਦੀ ਹੈ"</string>
     <string name="disabled" msgid="8017887509554714950">"ਅਯੋਗ ਬਣਾਇਆ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index a8ba18d..72a1b2c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Obrazowanie"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Słuchawki"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Peryferyjne urządzenie wejściowe"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Aparaty słuchowe"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi wyłączone."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi odłączone."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korekcja kolorów może być pomocna, gdy:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;chcesz wyraźniej widzieć kolory;&lt;/li&gt; &lt;li&gt;&amp;nbsp;chcesz usunąć kolory, aby łatwiej było się skupić.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – wstrzymano ładowanie, aby chronić baterię"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – sprawdzam akcesoria do ładowania"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (na podstawie Twojego sposobu korzystania)"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ładowanie bezprzewodowe"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Ładowanie"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nie podłączony"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Podłączono, ale nie ładuje się"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Naładowana"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Bateria w pełni naładowana"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Ładowanie wstrzymane"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolowane przez administratora"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolowane przez ograniczone ustawienia"</string>
     <string name="disabled" msgid="8017887509554714950">"Wyłączone"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index fef4378..def9d89 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Dispozitiv pentru imagini"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Căști"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Dispozitiv periferic de intrare"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Aparate auditive"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi dezactivat."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi deconectat."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Corecția culorii poate fi utilă dacă vrei:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;să vezi mai precis culorile;&lt;/li&gt; &lt;li&gt;&amp;nbsp;să elimini culorile pentru a te concentra mai bine.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Încărcarea s-a întrerupt pentru a proteja bateria"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Se verifică accesoriul de încărcare"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"În baza utilizării, timpul rămas este de aproximativ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Se încarcă wireless"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Se încarcă"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nu se încarcă"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectat, dar nu se încarcă"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Încărcată"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Complet încărcată"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Încărcare întreruptă"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlată de administrator"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlată de setarea restricționată"</string>
     <string name="disabled" msgid="8017887509554714950">"Dezactivată"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 5989e2a..5cc1a5b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Камера"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Наушники"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферийное устройство ввода"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слуховые аппараты"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi выключен"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi отключен"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Используйте коррекцию цвета, чтобы:&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Добиться нужной цветопередачи.&lt;/li&gt; &lt;li&gt; Убрать цвета, которые мешают сосредоточиться.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>, зарядка приостановлена для защиты батареи"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>, проверяется зарядное устройство"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Заряда (<xliff:g id="LEVEL">%2$s</xliff:g>) хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g> при текущем уровне расхода"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Беспроводная зарядка"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Зарядка"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряжается"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Устройство подключено, но не заряжается"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Батарея заряжена"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Батарея заряжена"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Зарядка приостановлена"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролируется администратором"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролируется настройками с ограниченным доступом"</string>
     <string name="disabled" msgid="8017887509554714950">"Отключено"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 5c3243b..0d9ca37 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"නිරූපණය"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"හෙඩ්ෆෝන්"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ආදාන උපාංග"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"ශ්‍රවණාධාරක"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"බ්ලූටූත්"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi අක්‍රියයි."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi සම්බන්ධ කර නොමැත."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"ඔබට පහත දේවල් සිදු කිරීම අවශ්‍ය විට වර්ණ නිවැරදි කිරීම ප්‍රයෝජනවත් විය හැකිය:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;වඩාත් නිවැරදිව වර්ණ දැකීම&lt;/li&gt; &lt;li&gt;ඔබට අවධානය යොමු කිරීම‍ට උදවු වීමට වර්ණ ඉවත් කිරීම&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - බැටරිය ආරක්ෂා කිරීම සඳහා ආරෝපණය රඳවා තබා ඇත"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණ ආයිත්තම පරීක්ෂා කිරීම"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ඔබේ භාවිතය මත පදනම්ව <xliff:g id="TIME_REMAINING">%1$s</xliff:g> පමණ ඉතිරිව ඇත"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"නොරැහැන්ව ආරෝපණය වේ"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ආරෝපණය වේ"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"ආරෝපණය නොවේ"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"සම්බන්ධයි, නමුත් ආරෝපණය නොවේ"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"අරෝපිතයි"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"සම්පූර්ණයෙන් ආරෝපණ වී ඇත"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ආරෝපණය රදවාගෙන ඇත"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"පරිපාලක විසින් පාලනය කරන ලදී"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"සීමා කළ සැකසීම මගින් පාලනය වේ"</string>
     <string name="disabled" msgid="8017887509554714950">"අබල කර ඇත"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index d9fe738..a722ad1 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imazhe"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Kufje"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Hyrje periferike"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Aparatet e dëgjimit"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth-i"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi është çaktivizuar."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi është i shkëputur."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korrigjimi i ngjyrës mund të jetë i dobishëm kur dëshiron:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Të shohësh ngjyrat më saktë&lt;/li&gt; &lt;li&gt;&amp;nbsp;Të heqësh ngjyrat për të të ndihmuar të fokusohesh&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi është vendosur në pritje për të mbrojtur baterinë"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Po kontrollohet aksesori i karikimit"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura bazuar në përdorimin tënd"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Po karikohet wireless"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Po karikohet"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nuk po karikohet"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Është lidhur, por nuk po karikohet"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Karikuar"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Karikuar plotësisht"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Karikimi në pritje"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolluar nga administratori"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrollohet nga \"Cilësimet e kufizuara\""</string>
     <string name="disabled" msgid="8017887509554714950">"Çaktivizuar"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 042fc34..66e448b 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Обрада слика"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Слушалице"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферни уређај за унос"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слушни апарати"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"WiFi је искључен."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"WiFi веза је прекинута."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Корекција боја може да буде корисна када желите:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Прецизније да видите боје&lt;/li&gt; &lt;li&gt;&amp;nbsp;Да уклоните боје како бисте се фокусирали&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – пуњење је на чекању да би се заштитила батерија"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – провера додатне опреме за пуњење"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g> на основу коришћења"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бежично пуњење"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Пуњење"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Не пуни се"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Уређај је повезан, али се не пуни"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Напуњено"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Напуњено до краја"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Пуњење је на чекању"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролише администратор"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролишу ограничена подешавања"</string>
     <string name="disabled" msgid="8017887509554714950">"Онемогућено"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 1f103e8ad..82567bf 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Bild"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Hörlur"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Inmatning från kringutrustning"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Hörapparater"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi är inaktiverat."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Ingen wifi-anslutning."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Färgkorrigering kan vara bra för att&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;urskilja färger bättre&lt;/li&gt; &lt;li&gt;&amp;nbsp;ta bort färger som distraherar&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Laddningen har pausats för att skydda batteriet"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kontrollerar laddningstillbehöret"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar utifrån din användning"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laddas trådlöst"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Laddas"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Laddar inte"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ansluten men laddas inte"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Laddat"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fulladdad"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Laddningen har pausats"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Strys av administratören"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Styrs av spärrad inställning"</string>
     <string name="disabled" msgid="8017887509554714950">"Inaktiverad"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 21e7bf3..a5ce169 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"இமேஜிங்"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ஹெட்ஃபோன்"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"இன்புட் பெரிபெரல்"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"செவித்துணைக் கருவிகள்"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"புளூடூத்"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"வைஃபை முடக்கப்பட்டது."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"வைஃபை துண்டிக்கப்பட்டது."</string>
@@ -180,7 +179,7 @@
     <string name="running_process_item_user_label" msgid="3988506293099805796">"பயனர்: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="launch_defaults_some" msgid="3631650616557252926">"சில இயல்புநிலைகள் அமைக்கப்பட்டன"</string>
     <string name="launch_defaults_none" msgid="8049374306261262709">"இயல்புநிலைகள் எதுவும் அமைக்கப்படவில்லை"</string>
-    <string name="tts_settings" msgid="8130616705989351312">"உரை வடிவத்திலிருந்து பேச்சுக்கான அமைப்பு"</string>
+    <string name="tts_settings" msgid="8130616705989351312">"\'எழுத்திலிருந்து பேச்சு\' அமைப்புகள்"</string>
     <string name="tts_settings_title" msgid="7602210956640483039">"உரையிலிருந்து பேச்சாக மாற்றுதல்"</string>
     <string name="tts_default_rate_title" msgid="3964187817364304022">"பேச்சு வீதம்"</string>
     <string name="tts_default_rate_summary" msgid="3781937042151716987">"பேசப்படும் உரையின் வேகம்"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"நீங்கள் இவற்றைச் செய்ய விரும்பும்போது கலர் கரெக்‌ஷன் உதவும்:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;வண்ணங்களை மிகத் துல்லியமாகப் பார்த்தல்&lt;/li&gt; &lt;li&gt;&amp;nbsp;கவனம் செலுத்துவதற்கு உதவ வண்ணங்களை அகற்றுதல்&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - பேட்டரியைப் பாதுகாப்பதற்காகச் சார்ஜிங் இடைநிறுத்தப்பட்டுள்ளது"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜிங் துணைக்கருவியைச் சரிபார்க்கிறது"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"உபயோகத்தின் அடிப்படையில் கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"வயரின்றி சார்ஜாகிறது"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"சார்ஜாகிறது"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"சார்ஜ் செய்யப்படவில்லை"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"இணைக்கப்பட்டது. ஆனால் சார்ஜ் ஆகவில்லை"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"சார்ஜாகிவிட்டது"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"முழுவதும் சார்ஜாகிவிட்டது"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"சார்ஜிங் இடைநிறுத்தப்பட்டுள்ளது"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"நிர்வாகி கட்டுப்படுத்துகிறார்"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"வரையறுக்கப்பட்ட அமைப்பால் கட்டுப்படுத்தப்படுகிறது"</string>
     <string name="disabled" msgid="8017887509554714950">"முடக்கப்பட்டது"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index f32a14a..53f75cb 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imaging"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Input Peripheral"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Mga Hearing Aid"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Naka-off ang Wifi."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Nakadiskonekta ang Wifi."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Puwedeng makatulong ang pagtatama ng kulay kapag gusto mong:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Makita nang mas tumpak ang mga kulay&lt;/li&gt; &lt;li&gt;&amp;nbsp;Alisin ang mga kulay para matulungan kang tumuon&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Naka-hold ang pag-charge para protektahan ang baterya"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Sinusuri ang accessory sa pag-charge"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira batay sa iyong paggamit"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Wireless na nagcha-charge"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Nagcha-charge"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Hindi nagcha-charge"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Nakakonekta, pero hindi nagcha-charge"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Puno ang Baterya"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Naka-hold ang pag-charge"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Pinapamahalaan ng admin"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kinokontrol ng Pinaghihigpitang Setting"</string>
     <string name="disabled" msgid="8017887509554714950">"Naka-disable"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 06e9729..8e491a1 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Görüntüleme"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Kulaklık"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Giriş Çevre Birimi"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"İşitme Cihazları"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Kablosuz kapalı."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Kablosuz bağlantı kesildi."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Renk düzeltme aşağıdaki durumlarda faydalı olabilir:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Renkleri daha doğru görmek istediğinizde&lt;/li&gt; &lt;li&gt;&amp;nbsp;Odaklanmak için renkleri kaldırmak istediğinizde&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pili korumak için şarj beklemede"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj aksesuarı kontrol ediliyor"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Kullanımınıza dayalı olarak yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kablosuz şarj oluyor"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Şarj Etme"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Şarj olmuyor"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Bağlı ancak şarj olmuyor"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Şarj oldu"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Pilin Şarjı Tam"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Şarj işlemi beklemede"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Yönetici tarafından denetleniyor"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kısıtlanmış ayar tarafından kontrol ediliyor"</string>
     <string name="disabled" msgid="8017887509554714950">"Devre dışı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cd00e17..45ed508 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Візуалізація"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Навушники"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферійне введення"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слухові апарати"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi вимкнено."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi від’єднано."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Корекція кольору корисна, якщо ви хочете:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;точніше бачити кольори;&lt;/li&gt; &lt;li&gt;&amp;nbsp;вилучити кольори, щоб легше зосереджуватися.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – заряджання призупинено, щоб захистити акумулятор"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – перевірка зарядного пристрою"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Згідно з даними про використання залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бездротове заряджання"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Заряджання"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряджається"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Пристрій підключено, але він не заряджається"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Заряджено"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Повністю заряджено"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Заряджання призупинено"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Керується адміністратором"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Керується налаштуваннями з обмеженнями"</string>
     <string name="disabled" msgid="8017887509554714950">"Вимкнено"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 3acb9cd..b46fca5 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Kamera"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Quloqchin"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Kiritish qurilmasi"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Eshitish moslamalari"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi o‘chiq."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi o‘chiq."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Ranglarni tuzatishning foydasi:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ranglar yanada aniqroq koʻrinadi&lt;/li&gt; &lt;li&gt;&amp;nbsp;Diqqatni qaratish uchun ortiqcha ranglarni olib tashlash imkonini beradi&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batareyani himoyalash uchun quvvatlash toʻxtatildi"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quvvatlash aksessuari tekshirilmoqda"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Quvvati tugashiga taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Simsiz quvvat olmoqda"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Quvvat olmoqda"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Quvvat olmayapti"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ulangan, lekin quvvat olmayapti"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Quvvat oldi"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Toʻliq quvvatlandi"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Quvvatlash toʻxtatildi"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Administrator tomonidan boshqariladi"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Cheklangan sozlama tomonidan boshqariladi"</string>
     <string name="disabled" msgid="8017887509554714950">"Oʻchiq"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index fcc049d..c471546 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Tạo ảnh"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Tai nghe"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Thiết bị ngoại vi vào"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Thiết bị trợ thính"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Đã tắt Wi-Fi."</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Đã ngắt kết nối Wi-Fi."</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Tính năng chỉnh màu có thể giúp ích khi bạn muốn:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Thấy màu sắc chính xác hơn&lt;/li&gt; &lt;li&gt;&amp;nbsp;Loại bỏ bớt màu để tập trung&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đang tạm ngưng sạc để bảo vệ pin"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đang kiểm tra phụ kiện sạc"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g> dựa trên mức sử dụng của bạn"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Đang sạc không dây"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Đang sạc"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Hiện không sạc"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Đã kết nối, nhưng không sạc"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Đã sạc"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Đã sạc đầy"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Đang tạm ngưng sạc"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Do quản trị viên kiểm soát"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Do chế độ Cài đặt hạn chế kiểm soát"</string>
     <string name="disabled" msgid="8017887509554714950">"Đã tắt"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index babcc07..e9774e1 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -456,7 +456,7 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"“色彩校正”功能适用于以下情况:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;您想更准确地查看颜色&lt;/li&gt; &lt;li&gt;您想移除颜色以提高专注程度&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 为保护电池,充电已暂停"</string>
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 为保护电池,已暂停充电"</string>
     <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在检查充电配件"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"大约还可使用<xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"大约还可使用<xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -489,7 +489,7 @@
     <string name="battery_info_status_not_charging" msgid="1103084691314264664">"已连接,但未充电"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"已充满电"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"已充满电"</string>
-    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"目前暂停充电"</string>
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"充电已暂停"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"由管理员控制"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由受限设置控制"</string>
     <string name="disabled" msgid="8017887509554714950">"已停用"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 390ae37..1e3394d 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"映像設備"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"耳機"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"輸入周邊設備"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"助聽器"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"藍牙"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi 已關閉。"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi 連線已中斷。"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"「色彩校正」功能適用於以下情況::&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;你想讓裝置顯示更準確的色彩&lt;/li&gt; &lt;li&gt;&amp;nbsp;你想移除色彩以提高專注力&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 為保護電池,目前暫停充電"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在檢查充電配件"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"根據你的使用情況,還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"無線充電中"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"正在充電"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"已連接,但未充電"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"已充滿電"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"充電完成"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"目前暫停充電"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"已由管理員停用"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由「受限設定」控制"</string>
     <string name="disabled" msgid="8017887509554714950">"已停用"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 5f4b9ed..8643fde 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -154,8 +154,7 @@
     <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"顯像裝置"</string>
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"頭戴式耳機"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"周邊輸入裝置"</string>
-    <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
-    <skip />
+    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"助聽器"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"藍牙"</string>
     <string name="accessibility_wifi_off" msgid="1195445715254137155">"已關閉 Wi-Fi。"</string>
     <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi 連線已中斷。"</string>
@@ -457,10 +456,8 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"「色彩校正」功能適用於以下情況:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;你想讓裝置顯示更準確的色彩&lt;/li&gt; &lt;li&gt;&amp;nbsp;你想移除色彩以提升專注力&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
-    <skip />
-    <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
-    <skip />
+    <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 為保護電池,目前暫停充電"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在檢查充電配件"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"目前電量為 <xliff:g id="LEVEL">%2$s</xliff:g>,還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"根據你的使用情形,還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"正在進行無線充電"</string>
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"充電中"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
-    <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
-    <skip />
+    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"已連接,但未充電"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"充電完成"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"充電完成"</string>
-    <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
-    <skip />
+    <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"目前暫停充電"</string>
     <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"已由管理員停用"</string>
     <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由限制設定控管"</string>
     <string name="disabled" msgid="8017887509554714950">"已停用"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HapClientProfile.java
index cf4d6be..0613676 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HapClientProfile.java
@@ -99,6 +99,8 @@
                 device.refresh();
             }
 
+            // Check current list of CachedDevices to see if any are hearing aid devices.
+            mDeviceManager.updateHearingAidsDevices();
             mIsProfileReady = true;
             mProfileManager.callServiceConnectedListeners();
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index 3a15b71..9fd174d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -15,8 +15,8 @@
  */
 package com.android.settingslib.bluetooth;
 
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.le.ScanFilter;
@@ -68,14 +68,9 @@
 
     void initHearingAidDeviceIfNeeded(CachedBluetoothDevice newDevice,
             List<ScanFilter> leScanFilters) {
-        long hiSyncId = getHiSyncId(newDevice.getDevice());
-        if (isValidHiSyncId(hiSyncId)) {
-            // Once hiSyncId is valid, assign hearing aid info
-            final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
-                    .setAshaDeviceSide(getDeviceSide(newDevice.getDevice()))
-                    .setAshaDeviceMode(getDeviceMode(newDevice.getDevice()))
-                    .setHiSyncId(hiSyncId);
-            newDevice.setHearingAidInfo(infoBuilder.build());
+        HearingAidInfo info = generateHearingAidInfo(newDevice);
+        if (info != null) {
+            newDevice.setHearingAidInfo(info);
         } else if (leScanFilters != null && !newDevice.isHearingAidDevice()) {
             // If the device is added with hearing aid scan filter during pairing, set an empty
             // hearing aid info to indicate it's a hearing aid device. The info will be updated
@@ -94,38 +89,6 @@
         }
     }
 
-    private long getHiSyncId(BluetoothDevice device) {
-        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
-        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
-        if (profileProxy == null) {
-            return BluetoothHearingAid.HI_SYNC_ID_INVALID;
-        }
-
-        return profileProxy.getHiSyncId(device);
-    }
-
-    private int getDeviceSide(BluetoothDevice device) {
-        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
-        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
-        if (profileProxy == null) {
-            Log.w(TAG, "HearingAidProfile is not supported and not ready to fetch device side");
-            return HearingAidProfile.DeviceSide.SIDE_INVALID;
-        }
-
-        return profileProxy.getDeviceSide(device);
-    }
-
-    private int getDeviceMode(BluetoothDevice device) {
-        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
-        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
-        if (profileProxy == null) {
-            Log.w(TAG, "HearingAidProfile is not supported and not ready to fetch device mode");
-            return HearingAidProfile.DeviceMode.MODE_INVALID;
-        }
-
-        return profileProxy.getDeviceMode(device);
-    }
-
     boolean setSubDeviceIfNeeded(CachedBluetoothDevice newDevice) {
         final long hiSyncId = newDevice.getHiSyncId();
         if (isValidHiSyncId(hiSyncId)) {
@@ -157,21 +120,17 @@
 
     // To collect all HearingAid devices and call #onHiSyncIdChanged to group device by HiSyncId
     void updateHearingAidsDevices() {
-        final Set<Long> newSyncIdSet = new HashSet<Long>();
+        final Set<Long> newSyncIdSet = new HashSet<>();
         for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
             // Do nothing if HiSyncId has been assigned
-            if (!isValidHiSyncId(cachedDevice.getHiSyncId())) {
-                final long newHiSyncId = getHiSyncId(cachedDevice.getDevice());
-                // Do nothing if there is no HiSyncId on Bluetooth device
-                if (isValidHiSyncId(newHiSyncId)) {
-                    // Once hiSyncId is valid, assign hearing aid info
-                    final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
-                            .setAshaDeviceSide(getDeviceSide(cachedDevice.getDevice()))
-                            .setAshaDeviceMode(getDeviceMode(cachedDevice.getDevice()))
-                            .setHiSyncId(newHiSyncId);
-                    cachedDevice.setHearingAidInfo(infoBuilder.build());
-
-                    newSyncIdSet.add(newHiSyncId);
+            if (isValidHiSyncId(cachedDevice.getHiSyncId())) {
+                continue;
+            }
+            HearingAidInfo info = generateHearingAidInfo(cachedDevice);
+            if (info != null) {
+                cachedDevice.setHearingAidInfo(info);
+                if (isValidHiSyncId(info.getHiSyncId())) {
+                    newSyncIdSet.add(info.getHiSyncId());
                 }
             }
         }
@@ -378,6 +337,54 @@
         return null;
     }
 
+    private boolean isLeAudioHearingAid(CachedBluetoothDevice cachedDevice) {
+        List<LocalBluetoothProfile> profiles = cachedDevice.getProfiles();
+        boolean supportLeAudio = profiles.stream().anyMatch(p -> p instanceof LeAudioProfile);
+        boolean supportHapClient = profiles.stream().anyMatch(p -> p instanceof HapClientProfile);
+        return supportLeAudio && supportHapClient;
+    }
+
+    private boolean isAshaHearingAid(CachedBluetoothDevice cachedDevice) {
+        return cachedDevice.getProfiles().stream().anyMatch(p -> p instanceof HearingAidProfile);
+    }
+
+    private HearingAidInfo generateHearingAidInfo(CachedBluetoothDevice cachedDevice) {
+        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+        if (isAshaHearingAid(cachedDevice)) {
+            final HearingAidProfile asha = profileManager.getHearingAidProfile();
+            if (asha == null) {
+                Log.w(TAG, "HearingAidProfile is not supported on this device");
+            } else {
+                long hiSyncId = asha.getHiSyncId(cachedDevice.getDevice());
+                if (isValidHiSyncId(hiSyncId)) {
+                    final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+                            .setAshaDeviceSide(asha.getDeviceSide(cachedDevice.getDevice()))
+                            .setAshaDeviceMode(asha.getDeviceMode(cachedDevice.getDevice()))
+                            .setHiSyncId(hiSyncId);
+                    return infoBuilder.build();
+                }
+            }
+        }
+        if (isLeAudioHearingAid(cachedDevice)) {
+            final HapClientProfile hapClientProfile = profileManager.getHapClientProfile();
+            final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
+            if (hapClientProfile == null || leAudioProfile == null) {
+                Log.w(TAG, "HapClientProfile or LeAudioProfile is not supported on this device");
+            } else {
+                int audioLocation = leAudioProfile.getAudioLocation(cachedDevice.getDevice());
+                int hearingAidType = hapClientProfile.getHearingAidType(cachedDevice.getDevice());
+                if (audioLocation != BluetoothLeAudio.AUDIO_LOCATION_INVALID
+                        && hearingAidType != HapClientProfile.HearingAidType.TYPE_INVALID) {
+                    final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+                            .setLeAudioLocation(audioLocation)
+                            .setHapDeviceType(hearingAidType);
+                    return infoBuilder.build();
+                }
+            }
+        }
+        return null;
+    }
+
     private void log(String msg) {
         if (DEBUG) {
             Log.d(TAG, msg);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 14fab16..f2450de 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -109,7 +109,7 @@
                 device.refresh();
             }
 
-            // Check current list of CachedDevices to see if any are Hearing Aid devices.
+            // Check current list of CachedDevices to see if any are hearing aid devices.
             mDeviceManager.updateHearingAidsDevices();
             mIsProfileReady = true;
             mProfileManager.callServiceConnectedListeners();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index 931a6f1..6be4336 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -83,6 +83,8 @@
                 device.refresh();
             }
 
+            // Check current list of CachedDevices to see if any are hearing aid devices.
+            mDeviceManager.updateHearingAidsDevices();
             mProfileManager.callServiceConnectedListeners();
             mIsProfileReady = true;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 9348705..1d2f790 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -759,6 +759,20 @@
     }
 
     /**
+     * Update the LE Broadcast by calling {@link BluetoothLeBroadcast#updateBroadcast(int,
+     * BluetoothLeAudioContentMetadata)}, currently only updates programInfo.
+     */
+    public void updateBroadcast() {
+        if (mServiceBroadcast == null) {
+            Log.d(TAG, "The BluetoothLeBroadcast is null when updating the broadcast.");
+            return;
+        }
+        String programInfo = getProgramInfo();
+        mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(programInfo).build();
+        mServiceBroadcast.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
+    }
+
+    /**
      * Register Broadcast Callbacks to track its state and receivers
      *
      * @param executor Executor object for callback
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
index cf224dc..3de4933 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
@@ -71,15 +71,15 @@
                         new Device(
                                 AudioDeviceInfo.TYPE_HDMI,
                                 MediaRoute2Info.TYPE_HDMI,
-                                mIsTv ? R.drawable.ic_tv : R.drawable.ic_headphone),
+                                mIsTv ? R.drawable.ic_tv : R.drawable.ic_external_display),
                         new Device(
                                 AudioDeviceInfo.TYPE_HDMI_ARC,
                                 MediaRoute2Info.TYPE_HDMI_ARC,
-                                mIsTv ? R.drawable.ic_hdmi : R.drawable.ic_headphone),
+                                mIsTv ? R.drawable.ic_hdmi : R.drawable.ic_external_display),
                         new Device(
                                 AudioDeviceInfo.TYPE_HDMI_EARC,
                                 MediaRoute2Info.TYPE_HDMI_EARC,
-                                mIsTv ? R.drawable.ic_hdmi : R.drawable.ic_headphone),
+                                mIsTv ? R.drawable.ic_hdmi : R.drawable.ic_external_display),
                         new Device(
                                 AudioDeviceInfo.TYPE_WIRED_HEADSET,
                                 MediaRoute2Info.TYPE_WIRED_HEADSET,
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
index 8a122fc..aef09ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
@@ -26,11 +26,13 @@
 import android.media.RouteDiscoveryPreference;
 import android.media.RouteListingPreference;
 import android.media.RoutingSessionInfo;
+import android.os.Process;
 import android.text.TextUtils;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.media.flags.Flags;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import java.util.ArrayList;
@@ -62,21 +64,33 @@
                 refreshDevices();
             };
 
-    // TODO: b/192657812 - Create factory method in InfoMediaManager to return
-    //      RouterInfoMediaManager or ManagerInfoMediaManager based on flag.
+    // TODO (b/321969740): Plumb target UserHandle between UMO and RouterInfoMediaManager.
     public RouterInfoMediaManager(
             Context context,
             String packageName,
             Notification notification,
-            LocalBluetoothManager localBluetoothManager) throws PackageNotAvailableException {
+            LocalBluetoothManager localBluetoothManager)
+            throws PackageNotAvailableException {
         super(context, packageName, notification, localBluetoothManager);
 
-        mRouter = MediaRouter2.getInstance(context, packageName);
+        MediaRouter2 router = null;
 
-        if (mRouter == null) {
+        if (Flags.enableCrossUserRoutingInMediaRouter2()) {
+            try {
+                router = MediaRouter2.getInstance(context, packageName, Process.myUserHandle());
+            } catch (IllegalArgumentException ex) {
+                // Do nothing
+            }
+        } else {
+            router = MediaRouter2.getInstance(context, packageName);
+        }
+        if (router == null) {
             throw new PackageNotAvailableException(
                     "Package name " + packageName + " does not exist.");
         }
+        // We have to defer initialization because mRouter is final.
+        mRouter = router;
+
         mRouterManager = MediaRouter2Manager.getInstance(context);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
new file mode 100644
index 0000000..3355fb3
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.volume.data.repository
+
+import android.media.AudioManager
+import com.android.internal.util.ConcurrentUtils
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/** Provides audio managing functionality and data. */
+interface AudioRepository {
+
+    /** Current [AudioManager.getMode]. */
+    val mode: StateFlow<Int>
+}
+
+class AudioRepositoryImpl(
+    private val audioManager: AudioManager,
+    backgroundCoroutineContext: CoroutineContext,
+    coroutineScope: CoroutineScope,
+) : AudioRepository {
+
+    override val mode: StateFlow<Int> =
+        callbackFlow {
+                val listener =
+                    AudioManager.OnModeChangedListener { newMode -> launch { send(newMode) } }
+                audioManager.addOnModeChangedListener(ConcurrentUtils.DIRECT_EXECUTOR, listener)
+                awaitClose { audioManager.removeOnModeChangedListener(listener) }
+            }
+            .flowOn(backgroundCoroutineContext)
+            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), audioManager.mode)
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractor.kt
new file mode 100644
index 0000000..053c59b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractor.kt
@@ -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 com.android.settingslib.volume.domain.interactor
+
+import android.media.AudioManager
+import com.android.settingslib.volume.data.repository.AudioRepository
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+class AudioModeInteractor(repository: AudioRepository) {
+
+    private val ongoingCallModes =
+        setOf(
+            AudioManager.MODE_RINGTONE,
+            AudioManager.MODE_IN_CALL,
+            AudioManager.MODE_IN_COMMUNICATION,
+        )
+
+    /** Returns if current [AudioManager.getMode] call is an ongoing call */
+    val isOngoingCall: Flow<Boolean> = repository.mode.map { it in ongoingCallModes }
+}
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index 644b72c..ce3a7ba 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -57,6 +57,7 @@
         "SettingsLibSettingsSpinner",
         "SettingsLibUsageProgressBarPreference",
         "settingslib_media_flags_lib",
+        "kotlinx_coroutines_test",
     ],
 
     dxflags: ["--multi-dex"],
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepository.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepository.kt
new file mode 100644
index 0000000..686362f
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepository.kt
@@ -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.settingslib.volume.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeAudioRepository : AudioRepository {
+
+    private val mutableMode = MutableStateFlow(0)
+    override val mode: StateFlow<Int>
+        get() = mutableMode.asStateFlow()
+
+    fun setMode(newMode: Int) {
+        mutableMode.value = newMode
+    }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractorTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractorTest.kt
new file mode 100644
index 0000000..3bc1edc
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractorTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.volume.domain.interactor
+
+import android.media.AudioManager
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.settingslib.volume.data.repository.FakeAudioRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class AudioModeInteractorTest {
+
+    private val testScope = TestScope()
+    private val fakeAudioRepository = FakeAudioRepository()
+
+    private val underTest = AudioModeInteractor(fakeAudioRepository)
+
+    @Test
+    fun ongoingCallModes_isOnGoingCall() {
+        testScope.runTest {
+            for (mode in ongoingCallModes) {
+                var isOngoingCall = false
+                underTest.isOngoingCall.onEach { isOngoingCall = it }.launchIn(backgroundScope)
+
+                fakeAudioRepository.setMode(mode)
+                runCurrent()
+
+                assertThat(isOngoingCall).isTrue()
+            }
+        }
+    }
+
+    @Test
+    fun notOngoingCallModes_isNotOnGoingCall() {
+        testScope.runTest {
+            var isOngoingCall = true
+            underTest.isOngoingCall.onEach { isOngoingCall = it }.launchIn(backgroundScope)
+
+            fakeAudioRepository.setMode(AudioManager.MODE_CURRENT)
+            runCurrent()
+
+            assertThat(isOngoingCall).isFalse()
+        }
+    }
+
+    private companion object {
+        private val ongoingCallModes =
+            setOf(
+                AudioManager.MODE_RINGTONE,
+                AudioManager.MODE_IN_CALL,
+                AudioManager.MODE_IN_COMMUNICATION,
+            )
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index e7487e8..aa5a298 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -15,6 +15,15 @@
  */
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothHearingAid.HI_SYNC_ID_INVALID;
+import static android.bluetooth.BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT;
+import static android.bluetooth.BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+
+import static com.android.settingslib.bluetooth.HapClientProfile.HearingAidType.TYPE_BINAURAL;
+import static com.android.settingslib.bluetooth.HapClientProfile.HearingAidType.TYPE_INVALID;
+import static com.android.settingslib.bluetooth.HearingAidProfile.DeviceMode.MODE_BINAURAL;
+import static com.android.settingslib.bluetooth.HearingAidProfile.DeviceSide.SIDE_RIGHT;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -32,7 +41,6 @@
 
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.le.ScanFilter;
@@ -92,6 +100,10 @@
     @Mock
     private HearingAidProfile mHearingAidProfile;
     @Mock
+    private LeAudioProfile mLeAudioProfile;
+    @Mock
+    private HapClientProfile mHapClientProfile;
+    @Mock
     private AudioProductStrategy mAudioStrategy;
     @Mock
     private BluetoothDevice mDevice1;
@@ -123,6 +135,8 @@
         when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
         when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager);
         when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+        when(mLocalProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
+        when(mLocalProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
         when(mAudioStrategy.getAudioAttributesForLegacyStreamType(
                 AudioManager.STREAM_MUSIC))
                 .thenReturn((new AudioAttributes.Builder()).build());
@@ -140,34 +154,43 @@
     }
 
     /**
-     * Test initHearingAidDeviceIfNeeded, set HearingAid's information, including HiSyncId,
-     * deviceSide, deviceMode.
+     * Test initHearingAidDeviceIfNeeded
+     *
+     * Conditions:
+     *      1) ASHA hearing aid
+     *      2) Valid HiSyncId
+     * Result:
+     *      Set hearing aid info to the device.
      */
     @Test
-    public void initHearingAidDeviceIfNeeded_validHiSyncId_setHearingAidInfo() {
+    public void initHearingAidDeviceIfNeeded_asha_validHiSyncId_setHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
-        when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(MODE_BINAURAL);
+        when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(SIDE_RIGHT);
 
         assertThat(mCachedDevice1.getHiSyncId()).isNotEqualTo(HISYNCID1);
         mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1, null);
 
         assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
+        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_RIGHT);
         assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
                 HearingAidInfo.DeviceMode.MODE_BINAURAL);
-        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
-                HearingAidInfo.DeviceSide.SIDE_RIGHT);
     }
 
     /**
-     * Test initHearingAidDeviceIfNeeded, an invalid HiSyncId will not be assigned
+     * Test initHearingAidDeviceIfNeeded
+     *
+     * Conditions:
+     *      1) ASHA hearing aid
+     *      2) Invalid HiSyncId
+     * Result:
+     *      Do not set hearing aid info to the device.
      */
     @Test
-    public void initHearingAidDeviceIfNeeded_invalidHiSyncId_notToSetHearingAidInfo() {
-        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(
-                BluetoothHearingAid.HI_SYNC_ID_INVALID);
+    public void initHearingAidDeviceIfNeeded_asha_invalidHiSyncId_notToSetHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HI_SYNC_ID_INVALID);
 
         mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1, null);
 
@@ -175,34 +198,89 @@
     }
 
     /**
-     * Test initHearingAidDeviceIfNeeded, an invalid HiSyncId and hearing aid scan filter, set an
-     * empty hearing aid info on the device.
+     * Test initHearingAidDeviceIfNeeded
+     *
+     * Conditions:
+     *      1) ASHA hearing aid
+     *      2) Invalid HiSyncId
+     *      3) ASHA uuid scan filter
+     * Result:
+     *      Set an empty hearing aid info to the device.
      */
     @Test
-    public void initHearingAidDeviceIfNeeded_hearingAidScanFilter_setHearingAidInfo() {
-        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(
-                BluetoothHearingAid.HI_SYNC_ID_INVALID);
+    public void initHearingAidDeviceIfNeeded_asha_scanFilterNotNull_setEmptyHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HI_SYNC_ID_INVALID);
         final ScanFilter scanFilter = new ScanFilter.Builder()
                 .setServiceData(BluetoothUuid.HEARING_AID, new byte[]{0}).build();
 
         mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1, List.of(scanFilter));
 
-        assertThat(mCachedDevice1.isHearingAidDevice()).isTrue();
+        verify(mCachedDevice1).setHearingAidInfo(new HearingAidInfo.Builder().build());
     }
 
     /**
-     * Test initHearingAidDeviceIfNeeded, an invalid HiSyncId and random scan filter, not to set
-     * hearing aid info on the device.
+     * Test initHearingAidDeviceIfNeeded
+     *
+     * Conditions:
+     *      1) Asha hearing aid
+     *      2) Invalid HiSyncId
+     *      3) Random scan filter
+     * Result:
+     *      Do not set hearing aid info to the device.
      */
     @Test
-    public void initHearingAidDeviceIfNeeded_randomScanFilter_setHearingAidInfo() {
-        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(
-                BluetoothHearingAid.HI_SYNC_ID_INVALID);
+    public void initHearingAidDeviceIfNeeded_asha_randomScanFilter_notToSetHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HI_SYNC_ID_INVALID);
         final ScanFilter scanFilter = new ScanFilter.Builder().build();
 
         mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1, List.of(scanFilter));
 
-        assertThat(mCachedDevice1.isHearingAidDevice()).isFalse();
+        verify(mCachedDevice1, never()).setHearingAidInfo(any(HearingAidInfo.class));
+    }
+
+    /**
+     * Test initHearingAidDeviceIfNeeded
+     *
+     * Conditions:
+     *      1) LeAudio hearing aid
+     *      2) Valid audio location and device type
+     * Result:
+     *      Set hearing aid info to the device.
+     */
+    @Test
+    public void initHearingAidDeviceIfNeeded_leAudio_validInfo_setHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mLeAudioProfile, mHapClientProfile));
+        when(mLeAudioProfile.getAudioLocation(mDevice1)).thenReturn(AUDIO_LOCATION_FRONT_LEFT);
+        when(mHapClientProfile.getHearingAidType(mDevice1)).thenReturn(TYPE_BINAURAL);
+
+        mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1, null);
+
+        verify(mCachedDevice1).setHearingAidInfo(any(HearingAidInfo.class));
+        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_LEFT);
+        assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
+    }
+
+    /**
+     * Test initHearingAidDeviceIfNeeded
+     *
+     * Conditions:
+     *      1) LeAudio hearing aid
+     *      2) Invalid audio location and device type
+     * Result:
+     *      Do not set hearing aid info to the device.
+     */
+    @Test
+    public void initHearingAidDeviceIfNeeded_leAudio_invalidInfo_notToSetHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mLeAudioProfile, mHapClientProfile));
+        when(mLeAudioProfile.getAudioLocation(mDevice1)).thenReturn(AUDIO_LOCATION_INVALID);
+        when(mHapClientProfile.getHearingAidType(mDevice1)).thenReturn(TYPE_INVALID);
+
+        mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1, null);
+
+        verify(mCachedDevice1, never()).setHearingAidInfo(any(HearingAidInfo.class));
     }
 
     /**
@@ -234,13 +312,20 @@
     }
 
     /**
-     * Test updateHearingAidsDevices, to link two devices with the same HiSyncId.
-     * When first paired devices is connected and second paired device is disconnected, first
-     * paired device would be set as main device and second device will be removed from
-     * CachedDevices list.
+     * Test updateHearingAidsDevices
+     *
+     * Conditions:
+     *      1) Two ASHA hearing aids with the same HiSyncId
+     *      2) First paired devices is connected
+     *      3) Second paired device is disconnected
+     * Result:
+     *      First paired device would be set as main device and second paired device will be set
+     *      as sub device and removed from CachedDevices list.
      */
     @Test
-    public void updateHearingAidsDevices_firstPairedDevicesConnected_verifySubDevice() {
+    public void updateHearingAidsDevices_asha_firstPairedDevicesConnected_verifySubDevice() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mCachedDevice2.getProfiles()).thenReturn(List.of(mHearingAidProfile));
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
         when(mHearingAidProfile.getHiSyncId(mDevice2)).thenReturn(HISYNCID1);
         when(mCachedDevice1.isConnected()).thenReturn(true);
@@ -257,13 +342,20 @@
     }
 
     /**
-     * Test updateHearingAidsDevices, to link two devices with the same HiSyncId.
-     * When second paired devices is connected and first paired device is disconnected, second
-     * paired device would be set as main device and first device will be removed from
-     * CachedDevices list.
+     * Test updateHearingAidsDevices
+     *
+     * Conditions:
+     *      1) Two ASHA hearing aids with the same HiSyncId
+     *      2) First paired devices is disconnected
+     *      3) Second paired device is connected
+     * Result:
+     *      Second paired device would be set as main device and first paired device will be set
+     *      as sub device and removed from CachedDevices list.
      */
     @Test
-    public void updateHearingAidsDevices_secondPairedDeviceConnected_verifySubDevice() {
+    public void updateHearingAidsDevices_asha_secondPairedDeviceConnected_verifySubDevice() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mCachedDevice2.getProfiles()).thenReturn(List.of(mHearingAidProfile));
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
         when(mHearingAidProfile.getHiSyncId(mDevice2)).thenReturn(HISYNCID1);
         when(mCachedDevice1.isConnected()).thenReturn(false);
@@ -280,12 +372,20 @@
     }
 
     /**
-     * Test updateHearingAidsDevices, to link two devices with the same HiSyncId.
-     * When both devices are connected, to build up main and sub relationship and to remove sub
-     * device from CachedDevices list.
+     * Test updateHearingAidsDevices
+     *
+     * Conditions:
+     *      1) Two ASHA hearing aids with the same HiSyncId
+     *      2) First paired devices is connected
+     *      3) Second paired device is connected
+     * Result:
+     *      First paired device would be set as main device and second paired device will be set
+     *      as sub device and removed from CachedDevices list.
      */
     @Test
-    public void updateHearingAidsDevices_BothConnected_verifySubDevice() {
+    public void updateHearingAidsDevices_asha_bothConnected_verifySubDevice() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mCachedDevice2.getProfiles()).thenReturn(List.of(mHearingAidProfile));
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
         when(mHearingAidProfile.getHiSyncId(mDevice2)).thenReturn(HISYNCID1);
         when(mCachedDevice1.isConnected()).thenReturn(true);
@@ -302,46 +402,64 @@
     }
 
     /**
-     * Test updateHearingAidsDevices, dispatch callback
+     * Test updateHearingAidsDevices
+     *
+     * Conditions:
+     *      1) Two ASHA hearing aids with the same HiSyncId
+     * Result:
+     *      Dispatch device removed callback
      */
     @Test
-    public void updateHearingAidsDevices_dispatchDeviceRemovedCallback() {
+    public void updateHearingAidsDevices_asha_dispatchDeviceRemovedCallback() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mCachedDevice2.getProfiles()).thenReturn(List.of(mHearingAidProfile));
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
         when(mHearingAidProfile.getHiSyncId(mDevice2)).thenReturn(HISYNCID1);
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice2);
+
         mHearingAidDeviceManager.updateHearingAidsDevices();
 
         verify(mBluetoothEventManager).dispatchDeviceRemoved(mCachedDevice1);
     }
 
     /**
-     * Test updateHearingAidsDevices, do nothing when HiSyncId is invalid
+     * Test updateHearingAidsDevices
+     *
+     * Conditions:
+     *      1) Two ASHA hearing aids with invalid HiSyncId
+     * Result:
+     *      Do nothing
      */
     @Test
-    public void updateHearingAidsDevices_invalidHiSyncId_doNothing() {
-        when(mHearingAidProfile.getHiSyncId(mDevice1)).
-                thenReturn(BluetoothHearingAid.HI_SYNC_ID_INVALID);
-        when(mHearingAidProfile.getHiSyncId(mDevice2)).
-                thenReturn(BluetoothHearingAid.HI_SYNC_ID_INVALID);
+    public void updateHearingAidsDevices_asha_invalidHiSyncId_doNothing() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mCachedDevice2.getProfiles()).thenReturn(List.of(mHearingAidProfile));
+        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HI_SYNC_ID_INVALID);
+        when(mHearingAidProfile.getHiSyncId(mDevice2)).thenReturn(HI_SYNC_ID_INVALID);
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice2);
+
         mHearingAidDeviceManager.updateHearingAidsDevices();
 
         verify(mHearingAidDeviceManager, never()).onHiSyncIdChanged(anyLong());
     }
 
     /**
-     * Test updateHearingAidsDevices, set HearingAid's information, including HiSyncId, deviceSide,
-     * deviceMode.
+     * Test updateHearingAidsDevices
+     *
+     * Conditions:
+     *      1) ASHA hearing aids
+     *      2) Valid HiSync Id
+     * Result:
+     *      Set hearing aid info to the device.
      */
     @Test
-    public void updateHearingAidsDevices_validHiSyncId_setHearingAidInfos() {
+    public void updateHearingAidsDevices_asha_validHiSyncId_setHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHearingAidProfile));
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
-        when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(MODE_BINAURAL);
+        when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(SIDE_RIGHT);
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
 
         mHearingAidDeviceManager.updateHearingAidsDevices();
@@ -355,6 +473,51 @@
     }
 
     /**
+     * Test updateHearingAidsDevices
+     *
+     * Conditions:
+     *      1) LeAudio hearing aid
+     *      2) Valid audio location and device type
+     * Result:
+     *      Set hearing aid info to the device.
+     */
+    @Test
+    public void updateHearingAidsDevices_leAudio_validInfo_setHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mLeAudioProfile, mHapClientProfile));
+        when(mLeAudioProfile.getAudioLocation(mDevice1)).thenReturn(AUDIO_LOCATION_FRONT_LEFT);
+        when(mHapClientProfile.getHearingAidType(mDevice1)).thenReturn(TYPE_BINAURAL);
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+        mHearingAidDeviceManager.updateHearingAidsDevices();
+
+        verify(mCachedDevice1).setHearingAidInfo(any(HearingAidInfo.class));
+        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_LEFT);
+        assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
+    }
+
+    /**
+     * Test updateHearingAidsDevices
+     *
+     * Conditions:
+     *      1) LeAudio hearing aid
+     *      2) Invalid audio location and device type
+     * Result:
+     *      Do not set hearing aid info to the device.
+     */
+    @Test
+    public void updateHearingAidsDevices_leAudio_invalidInfo_notToSetHearingAidInfo() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mLeAudioProfile, mHapClientProfile));
+        when(mLeAudioProfile.getAudioLocation(mDevice1)).thenReturn(AUDIO_LOCATION_INVALID);
+        when(mHapClientProfile.getHearingAidType(mDevice1)).thenReturn(TYPE_INVALID);
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+        mHearingAidDeviceManager.updateHearingAidsDevices();
+
+        verify(mCachedDevice1, never()).setHearingAidInfo(any(HearingAidInfo.class));
+    }
+
+    /**
      * Test onProfileConnectionStateChangedIfProcessed.
      * When first hearing aid device is connected, to process it same as other generic devices.
      * No need to process it.
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 89a8dd9..17d9f1b 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -335,4 +335,7 @@
     <!-- Default for Settings.BATTERY_CHARGING_STATE_ENFORCE_LEVEL.
         -1 means system internal default value is used. -->
     <integer name="def_battery_charging_state_enforce_level">-1</integer>
+
+    <!-- Value to use as default scale for fonts -->
+    <item name="def_device_font_scale" format="float" type="dimen">1.0</item>
 </resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 8ae50eb..8ad5f24 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -74,6 +74,7 @@
         Settings.Secure.TTS_DEFAULT_LOCALE,
         Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
         Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS,
+        Settings.Secure.ACCESSIBILITY_SLOW_KEYS,
         Settings.Secure.ACCESSIBILITY_STICKY_KEYS,
         Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,            // moved to global
         Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,               // moved to global
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index e7d7bb0..38ec931 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -48,6 +48,7 @@
                 Settings.System.WIFI_STATIC_DNS2,
                 Settings.System.BLUETOOTH_DISCOVERABILITY,
                 Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+                Settings.System.DEFAULT_DEVICE_FONT_SCALE,
                 Settings.System.FONT_SCALE,
                 Settings.System.DIM_SCREEN,
                 Settings.System.SCREEN_OFF_TIMEOUT,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 285c8c9..d854df38 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -120,6 +120,7 @@
         VALIDATORS.put(Secure.TTS_DEFAULT_LOCALE, TTS_LIST_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_IME_WITH_HARD_KEYBOARD, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_BOUNCE_KEYS, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_SLOW_KEYS, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_STICKY_KEYS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, NON_NEGATIVE_INTEGER_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index a8a659e..677c81a 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -45,6 +45,9 @@
         }
     };
 
+    public static final Validator FONT_SCALE_VALIDATOR = new InclusiveFloatRangeValidator(0.25f,
+            5.0f);
+
     public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
         @Override
         public boolean validate(@Nullable String value) {
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 572303a..98941c7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -20,6 +20,7 @@
 import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.FONT_SCALE_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_FLOAT_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
@@ -31,7 +32,6 @@
 import android.content.ComponentName;
 import android.hardware.display.ColorDisplayManager;
 import android.os.BatteryManager;
-import android.provider.Settings.Global;
 import android.provider.Settings.System;
 import android.util.ArrayMap;
 
@@ -93,7 +93,8 @@
                         return value == null || value.length() < MAX_LENGTH;
                     }
                 });
-        VALIDATORS.put(System.FONT_SCALE, new InclusiveFloatRangeValidator(0.25f, 5.0f));
+        VALIDATORS.put(System.DEFAULT_DEVICE_FONT_SCALE, FONT_SCALE_VALIDATOR);
+        VALIDATORS.put(System.FONT_SCALE, FONT_SCALE_VALIDATOR);
         VALIDATORS.put(System.DIM_SCREEN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 System.DISPLAY_COLOR_MODE,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3a46f4e..febce97 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3812,7 +3812,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 224;
+            private static final int SETTINGS_VERSION = 225;
 
             private final int mUserId;
 
@@ -6004,6 +6004,13 @@
                     currentVersion = 224;
                 }
 
+                // Version 224: Update the default font scale depending on the
+                //              R.dimen.def_device_font_scale configuration property.
+                if (currentVersion == 224) {
+                    handleDefaultFontScale(getSystemSettingsLocked(userId));
+                    currentVersion = 225;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
@@ -6021,6 +6028,32 @@
                 return currentVersion;
             }
 
+            @SuppressWarnings("GuardedBy")
+            @GuardedBy("mLock")
+            private void handleDefaultFontScale(@NonNull SettingsState systemSettings) {
+                final float defaultFontScale = getContext().getResources()
+                        .getFloat(R.dimen.def_device_font_scale);
+                // Persist the value for future use (e.g. Reset Settings option)
+                systemSettings.insertSettingLocked(
+                        Settings.System.DEFAULT_DEVICE_FONT_SCALE,
+                        String.valueOf(defaultFontScale),
+                        /* tag= */ null,
+                        /* makeDefault= */ false,
+                        SettingsState.SYSTEM_PACKAGE_NAME);
+                // We verify if there is a pre existing value for font_scale.
+                final Setting existingFontScale = systemSettings.getSettingLocked(
+                        Settings.System.FONT_SCALE);
+                if (existingFontScale == null || existingFontScale.isNull()) {
+                    // Set the default value only if it didn't exist before
+                    systemSettings.insertSettingLocked(
+                            Settings.System.FONT_SCALE,
+                            String.valueOf(defaultFontScale),
+                            /* tag= */ null,
+                            /* makeDefault= */ false,
+                            SettingsState.SYSTEM_PACKAGE_NAME);
+                }
+            }
+
             @GuardedBy("mLock")
             private void initGlobalSettingsDefaultValLocked(String key, boolean val) {
                 initGlobalSettingsDefaultValLocked(key, val ? "1" : "0");
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d384542..95e0e1b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -561,7 +561,7 @@
     <uses-permission android:name="android.permission.TEST_BIOMETRIC" />
 
     <!-- Permission required for CTS test - android.server.biometrics -->
-    <uses-permission android:name="android.permission.MANAGE_BIOMETRIC_DIALOG" />
+    <uses-permission android:name="android.permission.SET_BIOMETRIC_DIALOG_LOGO" />
 
     <!-- Permission required for CTS test - android.server.biometrics -->
     <uses-permission android:name="android.permission.USE_BACKGROUND_FACE_AUTHENTICATION" />
@@ -899,9 +899,15 @@
     <!-- Permission required for Cts test - CtsNotificationTestCases -->
     <uses-permission android:name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" />
 
+    <!-- Permission required for Cts test - CtsWindowManagerJetpackTestCases -->
+    <uses-permission android:name="android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE" />
+
     <!-- Permission required for BinaryTransparencyService shell API and host test -->
     <uses-permission android:name="android.permission.GET_BACKGROUND_INSTALLED_PACKAGES" />
 
+    <!-- Permissions required for CTS test - CtsPermissionUiTestCases -->
+    <uses-permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" />
+
     <application
         android:label="@string/app_label"
         android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 80656e9..900a2f8 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -214,6 +214,8 @@
 
     javacflags: [
         "-Adagger.fastInit=enabled",
+        "-Adagger.explicitBindingConflictsWithInject=ERROR",
+        "-Adagger.strictMultibindingValidation=enabled",
         "-Aroom.schemaLocation=frameworks/base/packages/SystemUI/schemas",
     ],
     kotlincflags: ["-Xjvm-default=all"],
@@ -330,6 +332,7 @@
         "androidx.core_core-animation-testing-nodeps",
         "androidx.compose.ui_ui",
         "flag-junit",
+        "ravenwood-junit",
         "platform-test-annotations",
         "notification_flags_lib",
     ],
@@ -386,7 +389,8 @@
 
 android_app {
     name: "SystemUIRobo-stub",
-    use_resource_processor: true,
+    // SystemUiRavenTests references the .aapt.srcjar
+    use_resource_processor: false,
     defaults: [
         "platform_app_defaults",
         "SystemUI_optimized_defaults",
@@ -458,6 +462,34 @@
     ],
 }
 
+android_ravenwood_test {
+    name: "SystemUiRavenTests",
+    srcs: [
+        ":SystemUI-tests-utils",
+        ":SystemUI-tests-multivalent",
+        // TODO(b/294256649): pivot to using {.aapt.jar} and re-enable
+        // use_resource_processor: true when better supported by soong
+        ":SystemUIRobo-stub{.aapt.srcjar}",
+    ],
+    static_libs: [
+        "SystemUI-core",
+        "SystemUI-res",
+        "SystemUI-tests-base",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.core_core-animation-testing",
+        "androidx.test.ext.junit",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+    ],
+    auto_gen_config: true,
+    plugins: [
+        "dagger2-compiler",
+    ],
+}
+
 // Opt-out config for optimizing the SystemUI target using R8.
 // Disabled via `export SYSTEMUI_OPTIMIZE_JAVA=false`, or explicitly in Make via
 // `SYSTEMUI_OPTIMIZE_JAVA := false`.
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index 7ba889b..866aa89 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -17,6 +17,13 @@
 }
 
 flag {
+    name: "floating_menu_drag_to_edit"
+    namespace: "accessibility"
+    description: "adds a second drag button to allow the user edit the shortcut."
+    bug: "297583708"
+}
+
+flag {
     name: "floating_menu_ime_displacement_animation"
     namespace: "accessibility"
     description: "Adds an animation for when the FAB is displaced by an IME becoming visible."
diff --git a/packages/SystemUI/aconfig/biometrics_framework.aconfig b/packages/SystemUI/aconfig/biometrics_framework.aconfig
index 5fd3b48..7cc0c83 100644
--- a/packages/SystemUI/aconfig/biometrics_framework.aconfig
+++ b/packages/SystemUI/aconfig/biometrics_framework.aconfig
@@ -7,4 +7,11 @@
     namespace: "biometrics_framework"
     description: "Adds talkback directional guidance when using UDFPS with biometric prompt"
     bug: "310044658"
+}
+
+flag {
+    name: "constraint_bp"
+    namespace: "biometrics_framework"
+    description: "Refactors Biometric Prompt to use a ConstraintLayout"
+    bug: "288175072"
 }
\ No newline at end of file
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 7eca04a..0ea2b1f 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -59,14 +59,6 @@
 }
 
 flag {
-    name: "notification_lifetime_extension_refactor"
-    namespace: "systemui"
-    description: "Enables moving notification lifetime extension management from SystemUI to "
-        "Notification Manager Service"
-    bug: "299448097"
-}
-
-flag {
     name: "notifications_live_data_store_refactor"
     namespace: "systemui"
     description: "Replaces NotifLiveDataStore with ActiveNotificationListRepository, and updates consumers. "
@@ -366,8 +358,15 @@
 }
 
 flag {
-   name: "enable_notif_linearlayout_optimized"
+    name: "keyguard_wm_state_refactor"
+    namespace: "systemui"
+    description: "Enables refactored logic for SysUI+WM unlock/occlusion code paths"
+    bug: "278086361"
+}
+
+flag {
+   name: "enable_keyguard_compose"
    namespace: "systemui"
-   description: "Enables notification specific LinearLayout optimization"
-   bug: "316110233"
+   description: "Enables the compose version of keyguard."
+   bug: "301968149"
 }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 9c46ebdc..8194055 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -644,7 +644,7 @@
             var candidate: RemoteAnimationTarget? = null
             for (it in apps) {
                 if (it.mode == RemoteAnimationTarget.MODE_OPENING) {
-                    if (it.taskInfo != null && !it.hasAnimatingParent) {
+                    if (!it.hasAnimatingParent) {
                         return it
                     }
                     if (candidate == null) {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
index bb2fbf7..a18b460 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
@@ -17,6 +17,7 @@
 
 package com.android.compose
 
+import androidx.annotation.DrawableRes
 import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.RowScope
@@ -24,8 +25,13 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material3.ButtonColors
 import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.IconButtonColors
+import androidx.compose.material3.IconButtonDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import com.android.compose.theme.LocalAndroidColorScheme
@@ -89,6 +95,29 @@
     )
 }
 
+@Composable
+fun PlatformIconButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    colors: IconButtonColors = iconButtonColors(),
+    @DrawableRes iconResource: Int,
+    contentDescription: String?,
+) {
+    IconButton(
+        modifier = modifier,
+        onClick = onClick,
+        enabled = enabled,
+        colors = colors,
+    ) {
+        Icon(
+            painter = painterResource(id = iconResource),
+            contentDescription = contentDescription,
+            tint = colors.contentColor,
+        )
+    }
+}
+
 private val DefaultPlatformButtonVerticalPadding = 6.dp
 private val ButtonPaddings = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
 
@@ -109,6 +138,13 @@
 }
 
 @Composable
+private fun iconButtonColors(): IconButtonColors {
+    return IconButtonDefaults.filledIconButtonColors(
+        contentColor = LocalAndroidColorScheme.current.onSurface,
+    )
+}
+
+@Composable
 private fun outlineButtonBorder(): BorderStroke {
     return BorderStroke(
         width = 1.dp,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
index 0960811..f9b91cf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalComposeUiApi::class)
+
 package com.android.systemui.bouncer.ui.composable
 
-import android.view.ViewTreeObserver
 import androidx.compose.foundation.text.KeyboardActions
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.material3.LocalTextStyle
@@ -25,25 +26,25 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.produceState
 import androidx.compose.runtime.remember
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawBehind
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.key.onInterceptKeyBeforeSoftKeyboard
 import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.KeyboardType
 import androidx.compose.ui.text.input.PasswordVisualTransformation
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
-import androidx.core.view.WindowInsetsCompat
 import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
 
 /** UI for the input part of a password-requiring version of the bouncer. */
@@ -64,9 +65,6 @@
     val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
     val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
 
-    val isImeVisible by isSoftwareKeyboardVisible()
-    LaunchedEffect(isImeVisible) { viewModel.onImeVisibilityChanged(isImeVisible) }
-
     DisposableEffect(Unit) {
         viewModel.onShown()
         onDispose { viewModel.onHidden() }
@@ -109,27 +107,14 @@
                         end = Offset(size.width, y = size.height - lineWidthPx),
                         strokeWidth = lineWidthPx,
                     )
+                }
+                .onInterceptKeyBeforeSoftKeyboard { keyEvent ->
+                    if (keyEvent.key == Key.Back) {
+                        viewModel.onImeDismissed()
+                        true
+                    } else {
+                        false
+                    }
                 },
     )
 }
-
-/** Returns a [State] with `true` when the IME/keyboard is visible and `false` when it's not. */
-@Composable
-fun isSoftwareKeyboardVisible(): State<Boolean> {
-    val view = LocalView.current
-    val viewTreeObserver = view.viewTreeObserver
-
-    return produceState(
-        initialValue = false,
-        key1 = viewTreeObserver,
-    ) {
-        val listener =
-            ViewTreeObserver.OnGlobalLayoutListener {
-                value = view.rootWindowInsets?.isVisible(WindowInsetsCompat.Type.ime()) ?: false
-            }
-
-        viewTreeObserver.addOnGlobalLayoutListener(listener)
-
-        awaitDispose { viewTreeObserver.removeOnGlobalLayoutListener(listener) }
-    }
-}
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 a22fecf..92bc1f1 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
@@ -64,14 +64,6 @@
             transitions = sceneTransitions,
         )
 
-    // Don't show hub mode UI if communal is not available. Communal is only available if it has
-    // been enabled via settings and either keyguard is showing, or, the device is currently
-    // dreaming.
-    val isCommunalAvailable by viewModel.isCommunalAvailable.collectAsState()
-    if (!isCommunalAvailable) {
-        return
-    }
-
     // This effect exposes the SceneTransitionLayout's observable transition state to the rest of
     // the system, and unsets it when the view is disposed to avoid a memory leak.
     DisposableEffect(viewModel, sceneTransitionLayoutState) {
@@ -84,13 +76,14 @@
     SceneTransitionLayout(
         state = sceneTransitionLayoutState,
         modifier = modifier.fillMaxSize(),
-        edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize),
+        swipeSourceDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize),
     ) {
         scene(
             TransitionSceneKey.Blank,
             userActions =
                 mapOf(
-                    Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to TransitionSceneKey.Communal
+                    Swipe(SwipeDirection.Left, fromSource = Edge.Right) to
+                        TransitionSceneKey.Communal
                 )
         ) {
             // This scene shows nothing only allowing for transitions to the communal scene.
@@ -101,7 +94,7 @@
             TransitionSceneKey.Communal,
             userActions =
                 mapOf(
-                    Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to TransitionSceneKey.Blank
+                    Swipe(SwipeDirection.Right, fromSource = Edge.Left) to TransitionSceneKey.Blank
                 ),
         ) {
             CommunalScene(viewModel, modifier = modifier)
@@ -131,7 +124,7 @@
 
 // TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
 fun CommunalSceneKey.toTransitionSceneKey(): SceneKey {
-    return SceneKey(name = toString(), identity = this)
+    return SceneKey(debugName = toString(), identity = this)
 }
 
 /**
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 761e74e..576596f 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
@@ -48,7 +48,6 @@
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Add
-import androidx.compose.material.icons.filled.Edit
 import androidx.compose.material.icons.outlined.Delete
 import androidx.compose.material.icons.outlined.Edit
 import androidx.compose.material.icons.outlined.TouchApp
@@ -60,7 +59,6 @@
 import androidx.compose.material3.CardDefaults
 import androidx.compose.material3.FilledIconButton
 import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
 import androidx.compose.material3.IconButtonColors
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
@@ -130,12 +128,11 @@
     val gridState = rememberLazyGridState()
     val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel)
     val reorderingWidgets by viewModel.reorderingWidgets.collectAsState()
-    val selectedIndex = viewModel.selectedIndex.collectAsState()
+    val selectedKey = viewModel.selectedKey.collectAsState()
     val removeButtonEnabled by remember {
-        derivedStateOf { selectedIndex.value != null || reorderingWidgets }
+        derivedStateOf { selectedKey.value != null || reorderingWidgets }
     }
-    val (isButtonToEditWidgetsShowing, setIsButtonToEditWidgetsShowing) =
-        remember { mutableStateOf(false) }
+    var isButtonToEditWidgetsShowing by remember { mutableStateOf(false) }
 
     val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
     val contentOffset = beforeContentPadding(contentPadding).toOffset()
@@ -150,22 +147,30 @@
                     if (!viewModel.isEditMode) return@pointerInput
                     observeTapsWithoutConsuming { offset ->
                         val adjustedOffset = offset - contentOffset
-                        val index =
-                            gridState.layoutInfo.visibleItemsInfo
-                                .firstItemAtOffset(adjustedOffset)
-                                ?.index
-                        val newIndex =
-                            if (index?.let(contentListState::isItemEditable) == true) {
-                                index
-                            } else {
-                                null
-                            }
-                        viewModel.setSelectedIndex(newIndex)
+                        val index = firstIndexAtOffset(gridState, adjustedOffset)
+                        val key = index?.let { keyAtIndexIfEditable(contentListState.list, index) }
+                        viewModel.setSelectedKey(key)
                     }
                 }
                 .thenIf(!viewModel.isEditMode) {
-                    Modifier.pointerInput(Unit) {
-                        detectLongPressGesture { offset -> setIsButtonToEditWidgetsShowing(true) }
+                    Modifier.pointerInput(
+                        gridState,
+                        contentOffset,
+                        communalContent,
+                        gridCoordinates
+                    ) {
+                        detectLongPressGesture { offset ->
+                            isButtonToEditWidgetsShowing = true
+
+                            // Deduct both grid offset relative to its container and content offset.
+                            val adjustedOffset =
+                                gridCoordinates?.let {
+                                    offset - it.positionInWindow() - contentOffset
+                                }
+                            val index = adjustedOffset?.let { firstIndexAtOffset(gridState, it) }
+                            val key = index?.let { keyAtIndexIfEditable(communalContent, index) }
+                            viewModel.setSelectedKey(key)
+                        }
                     }
                 },
     ) {
@@ -186,7 +191,7 @@
             onOpenWidgetPicker = onOpenWidgetPicker,
             gridState = gridState,
             contentListState = contentListState,
-            selectedIndex = selectedIndex,
+            selectedKey = selectedKey,
             widgetConfigurator = widgetConfigurator,
         )
 
@@ -198,18 +203,18 @@
                 onEditDone = onEditDone,
                 onOpenWidgetPicker = onOpenWidgetPicker,
                 onRemoveClicked = {
-                    selectedIndex.value?.let { index ->
-                        contentListState.onRemove(index)
+                    val index =
+                        selectedKey.value?.let { key ->
+                            contentListState.list.indexOfFirst { it.key == key }
+                        }
+                    index?.let {
+                        contentListState.onRemove(it)
                         contentListState.onSaveList()
-                        viewModel.setSelectedIndex(null)
+                        viewModel.setSelectedKey(null)
                     }
                 },
                 removeEnabled = removeButtonEnabled
             )
-        } else {
-            IconButton(onClick = viewModel::onOpenWidgetEditor) {
-                Icon(Icons.Default.Edit, stringResource(R.string.button_to_open_widget_editor))
-            }
         }
 
         if (isPopupOnDismissCtaShowing) {
@@ -219,10 +224,10 @@
         if (isButtonToEditWidgetsShowing) {
             ButtonToEditWidgets(
                 onClick = {
-                    setIsButtonToEditWidgetsShowing(false)
-                    viewModel.onOpenWidgetEditor()
+                    isButtonToEditWidgetsShowing = false
+                    viewModel.onOpenWidgetEditor(selectedKey.value)
                 },
-                onHide = { setIsButtonToEditWidgetsShowing(false) },
+                onHide = { isButtonToEditWidgetsShowing = false },
             )
         }
 
@@ -244,7 +249,7 @@
     communalContent: List<CommunalContentModel>,
     viewModel: BaseCommunalViewModel,
     contentPadding: PaddingValues,
-    selectedIndex: State<Int?>,
+    selectedKey: State<String?>,
     contentOffset: Offset,
     gridState: LazyGridState,
     contentListState: ContentListState,
@@ -253,7 +258,8 @@
     onOpenWidgetPicker: (() -> Unit)? = null,
     widgetConfigurator: WidgetConfigurator?,
 ) {
-    var gridModifier = Modifier.align(Alignment.CenterStart)
+    var gridModifier =
+        Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) }
     var list = communalContent
     var dragDropState: GridDragDropState? = null
     if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) {
@@ -266,10 +272,7 @@
                 updateDragPositionForRemove = updateDragPositionForRemove
             )
         gridModifier =
-            gridModifier
-                .fillMaxSize()
-                .dragContainer(dragDropState, contentOffset, viewModel)
-                .onGloballyPositioned { setGridCoordinates(it) }
+            gridModifier.fillMaxSize().dragContainer(dragDropState, contentOffset, viewModel)
         // for widgets dropped from other activities
         val dragAndDropTargetState =
             rememberDragAndDropTargetState(
@@ -307,7 +310,8 @@
                     list[index].size.dp().value,
                 )
             if (viewModel.isEditMode && dragDropState != null) {
-                val selected by remember(index) { derivedStateOf { index == selectedIndex.value } }
+                val selected by
+                    remember(index) { derivedStateOf { list[index].key == selectedKey.value } }
                 DraggableItem(
                     dragDropState = dragDropState,
                     selected = selected,
@@ -378,7 +382,7 @@
             colors = filledButtonColors(),
             contentPadding = Dimensions.ButtonPadding
         ) {
-            Icon(Icons.Default.Add, stringResource(R.string.button_to_open_widget_editor))
+            Icon(Icons.Default.Add, stringResource(R.string.hub_mode_add_widget_button_text))
             Spacer(spacerModifier)
             Text(
                 text = stringResource(R.string.hub_mode_add_widget_button_text),
@@ -832,6 +836,13 @@
     }
 }
 
+private fun firstIndexAtOffset(gridState: LazyGridState, offset: Offset): Int? =
+    gridState.layoutInfo.visibleItemsInfo.firstItemAtOffset(offset)?.index
+
+/** Returns the key of item if it's editable at the given index. Only widget is editable. */
+private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? =
+    if (index in list.indices && list[index].isWidget()) list[index].key else null
+
 data class ContentPaddingInPx(val start: Float, val top: Float) {
     fun toOffset(): Offset = Offset(start, top)
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index 2a6bea7..be6f022 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -33,6 +33,7 @@
 import com.android.keyguard.LockIconViewController
 import com.android.systemui.Flags.keyguardBottomAreaRefactor
 import com.android.systemui.biometrics.AuthController
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
@@ -47,10 +48,12 @@
 import com.android.systemui.statusbar.VibratorHelper
 import dagger.Lazy
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 
 class LockSection
 @Inject
 constructor(
+    @Application private val applicationScope: CoroutineScope,
     private val windowManager: WindowManager,
     private val authController: AuthController,
     private val featureFlags: FeatureFlagsClassic,
@@ -76,6 +79,7 @@
                         DeviceEntryIconView(context, null).apply {
                             id = R.id.device_entry_icon_view
                             DeviceEntryIconViewBinder.bind(
+                                applicationScope,
                                 this,
                                 deviceEntryIconViewModel.get(),
                                 deviceEntryForegroundViewModel.get(),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index 42fcd13..5e27d82 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -21,19 +21,27 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
 import com.android.systemui.notifications.ui.composable.NotificationStack
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
 import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationStackAppearanceViewBinder
+import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 
+@SysUISingleton
 class NotificationSection
 @Inject
 constructor(
@@ -42,22 +50,41 @@
     controller: NotificationStackScrollLayoutController,
     sceneContainerFlags: SceneContainerFlags,
     sharedNotificationContainer: SharedNotificationContainer,
+    sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
     stackScrollLayout: NotificationStackScrollLayout,
     notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
     ambientState: AmbientState,
+    notificationStackSizeCalculator: NotificationStackSizeCalculator,
+    @Main mainDispatcher: CoroutineDispatcher,
 ) {
     init {
-        if (sceneContainerFlags.flexiNotifsEnabled()) {
+        if (!KeyguardShadeMigrationNssl.isUnexpectedlyInLegacyMode()) {
+            // This scene container section moves the NSSL to the SharedNotificationContainer. This
+            //  also requires that SharedNotificationContainer gets moved to the SceneWindowRootView
+            //  by the SceneWindowRootViewBinder.
+            // Prior to Scene Container, but when the KeyguardShadeMigrationNssl flag is enabled,
+            //  NSSL is moved into this container by the NotificationStackScrollLayoutSection.
             (stackScrollLayout.parent as? ViewGroup)?.removeView(stackScrollLayout)
             sharedNotificationContainer.addNotificationStackScrollLayout(stackScrollLayout)
 
-            NotificationStackAppearanceViewBinder.bind(
-                context,
+            SharedNotificationContainerBinder.bind(
                 sharedNotificationContainer,
-                notificationStackAppearanceViewModel,
-                ambientState,
+                sharedNotificationContainerViewModel,
+                sceneContainerFlags,
                 controller,
+                notificationStackSizeCalculator,
+                mainDispatcher,
             )
+
+            if (sceneContainerFlags.flexiNotifsEnabled()) {
+                NotificationStackAppearanceViewBinder.bind(
+                    context,
+                    sharedNotificationContainer,
+                    notificationStackAppearanceViewModel,
+                    ambientState,
+                    controller,
+                )
+            }
         }
     }
 
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 c35202c..9f9e1f5 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
@@ -183,7 +183,7 @@
         is UserAction.Swipe ->
             Swipe(
                 pointerCount = pointerCount,
-                fromEdge =
+                fromSource =
                     when (this.fromEdge) {
                         null -> null
                         Edge.LEFT -> SceneTransitionEdge.Left
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt
index 5336bf6..0c66701 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt
@@ -12,5 +12,5 @@
 
 // TODO(b/293899074): Remove this file once we can use the scene keys from SceneTransitionLayout.
 fun SceneKey.toTransitionSceneKey(): SceneTransitionSceneKey {
-    return SceneTransitionSceneKey(name = toString(), identity = this)
+    return SceneTransitionSceneKey(debugName = toString(), identity = this)
 }
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 e2beaee..b11edf7 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
@@ -58,6 +58,8 @@
 import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
 import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
 import com.android.systemui.res.R
+import com.android.systemui.scene.ui.composable.QuickSettings
+import com.android.systemui.scene.ui.composable.Shade as ShadeKey
 import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
@@ -348,7 +350,7 @@
 }
 
 @Composable
-private fun StatusIcons(
+private fun SceneScope.StatusIcons(
     viewModel: ShadeHeaderViewModel,
     createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
     statusBarIconController: StatusBarIconController,
@@ -358,7 +360,6 @@
     val carrierIconSlots =
         listOf(stringResource(id = com.android.internal.R.string.status_bar_mobile))
     val isSingleCarrier by viewModel.isSingleCarrier.collectAsState()
-    val isTransitioning by viewModel.isTransitioning.collectAsState()
 
     AndroidView(
         factory = { context ->
@@ -373,7 +374,9 @@
             iconContainer
         },
         update = { iconContainer ->
-            iconContainer.setQsExpansionTransitioning(isTransitioning)
+            iconContainer.setQsExpansionTransitioning(
+                layoutState.isTransitioningBetween(ShadeKey, QuickSettings)
+            )
             if (isSingleCarrier || !useExpandedFormat) {
                 iconContainer.removeIgnoredSlots(carrierIconSlots)
             } else {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 7d3b0fb..7057545 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -61,7 +61,7 @@
                     // The transition is already finished (progress ~= 1): no need to animate. We
                     // finish the current transition early to make sure that the current state
                     // change is committed.
-                    layoutState.finishTransition(transitionState, transitionState.currentScene)
+                    layoutState.finishTransition(transitionState, target)
                     null
                 } else {
                     // The transition is in progress: start the canned animation at the same
@@ -78,7 +78,7 @@
                 if (progress.absoluteValue < ProgressVisibilityThreshold) {
                     // The transition is at progress ~= 0: no need to animate.We finish the current
                     // transition early to make sure that the current state change is committed.
-                    layoutState.finishTransition(transitionState, transitionState.currentScene)
+                    layoutState.finishTransition(transitionState, target)
                     null
                 } else {
                     // TODO(b/290184746): Also take the current velocity into account.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
index 82d4239..b0dc3a1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
@@ -23,24 +23,19 @@
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 
-interface EdgeDetector {
-    /**
-     * Return the [Edge] associated to [position] inside a layout of size [layoutSize], given
-     * [density] and [orientation].
-     */
-    fun edge(
-        layoutSize: IntSize,
-        position: IntOffset,
-        density: Density,
-        orientation: Orientation,
-    ): Edge?
+/** The edge of a [SceneTransitionLayout]. */
+enum class Edge : SwipeSource {
+    Left,
+    Right,
+    Top,
+    Bottom,
 }
 
 val DefaultEdgeDetector = FixedSizeEdgeDetector(40.dp)
 
-/** An [EdgeDetector] that detects edges assuming a fixed edge size of [size]. */
-class FixedSizeEdgeDetector(val size: Dp) : EdgeDetector {
-    override fun edge(
+/** An [SwipeSourceDetector] that detects edges assuming a fixed edge size of [size]. */
+class FixedSizeEdgeDetector(val size: Dp) : SwipeSourceDetector {
+    override fun source(
         layoutSize: IntSize,
         position: IntOffset,
         density: Density,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
index 90f46bd..c6851954 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
@@ -42,16 +42,20 @@
 
 /** Key for a scene. */
 class SceneKey(
-    name: String,
+    debugName: String,
     identity: Any = Object(),
-) : Key(name, identity) {
+) : Key(debugName, identity), UserActionResult {
     @VisibleForTesting
     // TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can
     // access internal members.
-    val testTag: String = "scene:$name"
+    val testTag: String = "scene:$debugName"
 
     /** The unique [ElementKey] identifying this scene's root element. */
-    val rootElementKey = ElementKey(name, identity)
+    val rootElementKey = ElementKey(debugName, identity)
+
+    // Implementation of [UserActionResult].
+    override val toScene: SceneKey = this
+    override val distance: UserActionDistance? = null
 
     override fun toString(): String {
         return "SceneKey(debugName=$debugName)"
@@ -60,7 +64,7 @@
 
 /** Key for an element. */
 class ElementKey(
-    name: String,
+    debugName: String,
     identity: Any = Object(),
 
     /**
@@ -68,11 +72,11 @@
      * or compose MovableElements.
      */
     val scenePicker: ElementScenePicker = DefaultElementScenePicker,
-) : Key(name, identity), ElementMatcher {
+) : Key(debugName, identity), ElementMatcher {
     @VisibleForTesting
     // TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can
     // access internal members.
-    val testTag: String = "element:$name"
+    val testTag: String = "element:$debugName"
 
     override fun matches(key: ElementKey, scene: SceneKey): Boolean {
         return key == this
@@ -95,7 +99,7 @@
 }
 
 /** Key for a shared value of an element. */
-class ValueKey(name: String, identity: Any = Object()) : Key(name, identity) {
+class ValueKey(debugName: String, identity: Any = Object()) : Key(debugName, identity) {
     override fun toString(): String {
         return "ValueKey(debugName=$debugName)"
     }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index 3873878..529fc03 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -40,12 +40,15 @@
 import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
 import androidx.compose.ui.node.DelegatingNode
 import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.ObserverModifierNode
 import androidx.compose.ui.node.PointerInputModifierNode
 import androidx.compose.ui.node.currentValueOf
+import androidx.compose.ui.node.observeReads
 import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.util.fastForEach
+import kotlin.math.sign
 
 /**
  * Make an element draggable in the given [orientation].
@@ -64,8 +67,8 @@
 @Stable
 internal fun Modifier.multiPointerDraggable(
     orientation: Orientation,
-    enabled: Boolean,
-    startDragImmediately: Boolean,
+    enabled: () -> Boolean,
+    startDragImmediately: (startedPosition: Offset) -> Boolean,
     onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
     onDragDelta: (delta: Float) -> Unit,
     onDragStopped: (velocity: Float) -> Unit,
@@ -83,8 +86,8 @@
 
 private data class MultiPointerDraggableElement(
     private val orientation: Orientation,
-    private val enabled: Boolean,
-    private val startDragImmediately: Boolean,
+    private val enabled: () -> Boolean,
+    private val startDragImmediately: (startedPosition: Offset) -> Boolean,
     private val onDragStarted:
         (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
     private val onDragDelta: (Float) -> Unit,
@@ -110,19 +113,24 @@
     }
 }
 
-private class MultiPointerDraggableNode(
+internal class MultiPointerDraggableNode(
     orientation: Orientation,
-    enabled: Boolean,
-    var startDragImmediately: Boolean,
+    enabled: () -> Boolean,
+    var startDragImmediately: (startedPosition: Offset) -> Boolean,
     var onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
     var onDragDelta: (Float) -> Unit,
     var onDragStopped: (velocity: Float) -> Unit,
-) : PointerInputModifierNode, DelegatingNode(), CompositionLocalConsumerModifierNode {
+) :
+    PointerInputModifierNode,
+    DelegatingNode(),
+    CompositionLocalConsumerModifierNode,
+    ObserverModifierNode {
     private val pointerInputHandler: suspend PointerInputScope.() -> Unit = { pointerInput() }
     private val delegate = delegate(SuspendingPointerInputModifierNode(pointerInputHandler))
     private val velocityTracker = VelocityTracker()
+    private var previousEnabled: Boolean = false
 
-    var enabled: Boolean = enabled
+    var enabled: () -> Boolean = enabled
         set(value) {
             // Reset the pointer input whenever enabled changed.
             if (value != field) {
@@ -133,13 +141,28 @@
 
     var orientation: Orientation = orientation
         set(value) {
-            // Reset the pointer input whenever enabled orientation.
+            // Reset the pointer input whenever orientation changed.
             if (value != field) {
                 field = value
                 delegate.resetPointerInputHandler()
             }
         }
 
+    override fun onAttach() {
+        previousEnabled = enabled()
+        onObservedReadsChanged()
+    }
+
+    override fun onObservedReadsChanged() {
+        observeReads {
+            val newEnabled = enabled()
+            if (newEnabled != previousEnabled) {
+                delegate.resetPointerInputHandler()
+            }
+            previousEnabled = newEnabled
+        }
+    }
+
     override fun onCancelPointerInput() = delegate.onCancelPointerInput()
 
     override fun onPointerEvent(
@@ -149,7 +172,7 @@
     ) = delegate.onPointerEvent(pointerEvent, pass, bounds)
 
     private suspend fun PointerInputScope.pointerInput() {
-        if (!enabled) {
+        if (!enabled()) {
             return
         }
 
@@ -163,8 +186,7 @@
         val onDragEnd: () -> Unit = {
             val maxFlingVelocity =
                 currentValueOf(LocalViewConfiguration).maximumFlingVelocity.let { max ->
-                    val maxF = max.toFloat()
-                    Velocity(maxF, maxF)
+                    Velocity(max, max)
                 }
 
             val velocity = velocityTracker.calculateVelocity(maxFlingVelocity)
@@ -183,7 +205,7 @@
 
         detectDragGestures(
             orientation = orientation,
-            startDragImmediately = { startDragImmediately },
+            startDragImmediately = startDragImmediately,
             onDragStart = onDragStart,
             onDragEnd = onDragEnd,
             onDragCancel = onDragCancel,
@@ -202,7 +224,7 @@
  */
 private suspend fun PointerInputScope.detectDragGestures(
     orientation: Orientation,
-    startDragImmediately: () -> Boolean,
+    startDragImmediately: (startedPosition: Offset) -> Boolean,
     onDragStart: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
     onDragEnd: () -> Unit,
     onDragCancel: () -> Unit,
@@ -212,7 +234,7 @@
         val initialDown = awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial)
         var overSlop = 0f
         val drag =
-            if (startDragImmediately()) {
+            if (startDragImmediately(initialDown.position)) {
                 initialDown.consume()
                 initialDown
             } else {
@@ -224,12 +246,31 @@
 
                 // TODO(b/291055080): Replace by await[Orientation]PointerSlopOrCancellation once
                 // it is public.
-                when (orientation) {
-                    Orientation.Horizontal ->
-                        awaitHorizontalTouchSlopOrCancellation(down.id, onSlopReached)
-                    Orientation.Vertical ->
-                        awaitVerticalTouchSlopOrCancellation(down.id, onSlopReached)
+                val drag =
+                    when (orientation) {
+                        Orientation.Horizontal ->
+                            awaitHorizontalTouchSlopOrCancellation(down.id, onSlopReached)
+                        Orientation.Vertical ->
+                            awaitVerticalTouchSlopOrCancellation(down.id, onSlopReached)
+                    }
+
+                // Make sure that overSlop is not 0f. This can happen when the user drags by exactly
+                // the touch slop. However, the overSlop we pass to onDragStarted() is used to
+                // compute the direction we are dragging in, so overSlop should never be 0f unless
+                // we intercept an ongoing swipe transition (i.e. startDragImmediately() returned
+                // true).
+                if (drag != null && overSlop == 0f) {
+                    val deltaOffset = drag.position - initialDown.position
+                    val delta =
+                        when (orientation) {
+                            Orientation.Horizontal -> deltaOffset.x
+                            Orientation.Vertical -> deltaOffset.y
+                        }
+                    check(delta != 0f) { "delta is equal to 0" }
+                    overSlop = delta.sign
                 }
+
+                drag
             }
 
         if (drag != null) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
index f67df54..af51cee 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
@@ -38,7 +38,7 @@
     val key: SceneKey,
     layoutImpl: SceneTransitionLayoutImpl,
     content: @Composable SceneScope.() -> Unit,
-    actions: Map<UserAction, SceneKey>,
+    actions: Map<UserAction, UserActionResult>,
     zIndex: Float,
 ) {
     internal val scope = SceneScopeImpl(layoutImpl, this)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index ff05478..35754d6 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -20,14 +20,15 @@
 
 import android.util.Log
 import androidx.compose.animation.core.Animatable
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.SpringSpec
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.round
 import com.android.compose.nestedscroll.PriorityNestedScrollConnection
@@ -52,7 +53,20 @@
         }
 
     private fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
-        if (isDrivingTransition || force) layoutState.startTransition(newTransition)
+        if (isDrivingTransition || force) {
+            layoutState.startTransition(newTransition)
+
+            // Initialize SwipeTransition.swipeSpec. Note that this must be called right after
+            // layoutState.startTransition() is called, because it computes the
+            // layoutState.transformationSpec().
+            newTransition.swipeSpec =
+                layoutState.transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec
+        } else {
+            // We were not driving the transition and we don't force the update, so the spec won't
+            // be used and it doesn't matter which one we set here.
+            newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec
+        }
+
         swipeTransition = newTransition
     }
 
@@ -75,20 +89,46 @@
 
     internal var currentSource: Any? = null
 
-    /** The [UserAction]s associated to the current swipe. */
-    private var actionUpOrLeft: UserAction? = null
-    private var actionDownOrRight: UserAction? = null
-    private var actionUpOrLeftNoEdge: UserAction? = null
-    private var actionDownOrRightNoEdge: UserAction? = null
-    private var upOrLeftScene: SceneKey? = null
-    private var downOrRightScene: SceneKey? = null
+    /** The [Swipes] associated to the current gesture. */
+    private var swipes: Swipes? = null
+
+    /** The [UserActionResult] associated to up and down swipes. */
+    private var upOrLeftResult: UserActionResult? = null
+    private var downOrRightResult: UserActionResult? = null
+
+    /**
+     * Whether we should immediately intercept a gesture.
+     *
+     * Note: if this returns true, then [onDragStarted] will be called with overSlop equal to 0f,
+     * indicating that the transition should be intercepted.
+     */
+    internal fun shouldImmediatelyIntercept(startedPosition: Offset?): Boolean {
+        // We don't intercept the touch if we are not currently driving the transition.
+        if (!isDrivingTransition) {
+            return false
+        }
+
+        // Only intercept the current transition if one of the 2 swipes results is also a transition
+        // between the same pair of scenes.
+        val fromScene = swipeTransition._currentScene
+        val swipes = computeSwipes(fromScene, startedPosition, pointersDown = 1)
+        val (upOrLeft, downOrRight) = computeSwipesResults(fromScene, swipes)
+        return (upOrLeft != null &&
+            swipeTransition.isTransitioningBetween(fromScene.key, upOrLeft.toScene)) ||
+            (downOrRight != null &&
+                swipeTransition.isTransitioningBetween(fromScene.key, downOrRight.toScene))
+    }
 
     internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?, overSlop: Float) {
-        if (isDrivingTransition) {
+        if (overSlop == 0f) {
+            check(isDrivingTransition) {
+                "onDragStarted() called while isDrivingTransition=false overSlop=0f"
+            }
+
             // This [transition] was already driving the animation: simply take over it.
             // Stop animating and start from where the current offset.
             swipeTransition.cancelOffsetAnimation()
-            updateTargetScenes(swipeTransition._fromScene)
+            updateSwipesResults(swipeTransition._fromScene)
             return
         }
 
@@ -104,18 +144,26 @@
         }
 
         val fromScene = layoutImpl.scene(transitionState.currentScene)
-        setCurrentActions(fromScene, startedPosition, pointersDown)
+        updateSwipes(fromScene, startedPosition, pointersDown)
 
-        val (targetScene, distance) =
-            findTargetSceneAndDistance(fromScene, overSlop, updateScenes = true) ?: return
-
-        updateTransition(SwipeTransition(fromScene, targetScene, distance), force = true)
+        val result =
+            findUserActionResult(fromScene, directionOffset = overSlop, updateSwipesResults = true)
+                ?: return
+        updateTransition(SwipeTransition(fromScene, result), force = true)
     }
 
-    private fun setCurrentActions(fromScene: Scene, startedPosition: Offset?, pointersDown: Int) {
-        val fromEdge =
+    private fun updateSwipes(fromScene: Scene, startedPosition: Offset?, pointersDown: Int) {
+        this.swipes = computeSwipes(fromScene, startedPosition, pointersDown)
+    }
+
+    private fun computeSwipes(
+        fromScene: Scene,
+        startedPosition: Offset?,
+        pointersDown: Int
+    ): Swipes {
+        val fromSource =
             startedPosition?.let { position ->
-                layoutImpl.edgeDetector.edge(
+                layoutImpl.swipeSourceDetector.source(
                     fromScene.targetSize,
                     position.round(),
                     layoutImpl.density,
@@ -131,7 +179,7 @@
                         Orientation.Vertical -> SwipeDirection.Up
                     },
                 pointerCount = pointersDown,
-                fromEdge = fromEdge,
+                fromSource = fromSource,
             )
 
         val downOrRight =
@@ -142,33 +190,31 @@
                         Orientation.Vertical -> SwipeDirection.Down
                     },
                 pointerCount = pointersDown,
-                fromEdge = fromEdge,
+                fromSource = fromSource,
             )
 
-        if (fromEdge == null) {
-            actionUpOrLeft = null
-            actionDownOrRight = null
-            actionUpOrLeftNoEdge = upOrLeft
-            actionDownOrRightNoEdge = downOrRight
+        return if (fromSource == null) {
+            Swipes(
+                upOrLeft = null,
+                downOrRight = null,
+                upOrLeftNoSource = upOrLeft,
+                downOrRightNoSource = downOrRight,
+            )
         } else {
-            actionUpOrLeft = upOrLeft
-            actionDownOrRight = downOrRight
-            actionUpOrLeftNoEdge = upOrLeft.copy(fromEdge = null)
-            actionDownOrRightNoEdge = downOrRight.copy(fromEdge = null)
+            Swipes(
+                upOrLeft = upOrLeft,
+                downOrRight = downOrRight,
+                upOrLeftNoSource = upOrLeft.copy(fromSource = null),
+                downOrRightNoSource = downOrRight.copy(fromSource = null),
+            )
         }
     }
 
-    /**
-     * Use the layout size in the swipe orientation for swipe distance.
-     *
-     * TODO(b/290184746): Also handle custom distances for transitions. With smaller distances, we
-     *   will also have to make sure that we correctly handle overscroll.
-     */
-    private fun Scene.getAbsoluteDistance(): Float {
-        return when (orientation) {
-            Orientation.Horizontal -> targetSize.width
-            Orientation.Vertical -> targetSize.height
-        }.toFloat()
+    private fun Scene.getAbsoluteDistance(distance: UserActionDistance?): Float {
+        val targetSize = this.targetSize
+        return with(distance ?: DefaultSwipeDistance) {
+            layoutImpl.density.absoluteDistance(targetSize, orientation)
+        }
     }
 
     internal fun onDrag(delta: Float) {
@@ -179,11 +225,11 @@
             computeFromSceneConsideringAcceleratedSwipe(swipeTransition)
 
         val isNewFromScene = fromScene.key != swipeTransition.fromScene
-        val (targetScene, distance) =
-            findTargetSceneAndDistance(
+        val result =
+            findUserActionResult(
                 fromScene,
                 swipeTransition.dragOffset,
-                updateScenes = isNewFromScene,
+                updateSwipesResults = isNewFromScene,
             )
                 ?: run {
                     onDragStopped(delta, true)
@@ -191,18 +237,40 @@
                 }
         swipeTransition.dragOffset += acceleratedOffset
 
-        if (isNewFromScene || targetScene.key != swipeTransition.toScene) {
+        if (isNewFromScene || result.toScene != swipeTransition.toScene) {
             updateTransition(
-                SwipeTransition(fromScene, targetScene, distance).apply {
+                SwipeTransition(fromScene, result).apply {
                     this.dragOffset = swipeTransition.dragOffset
                 }
             )
         }
     }
 
-    private fun updateTargetScenes(fromScene: Scene) {
-        upOrLeftScene = fromScene.upOrLeft()
-        downOrRightScene = fromScene.downOrRight()
+    private fun updateSwipesResults(fromScene: Scene) {
+        val (upOrLeftResult, downOrRightResult) =
+            computeSwipesResults(
+                fromScene,
+                this.swipes ?: error("updateSwipes() should be called before updateSwipesResults()")
+            )
+
+        this.upOrLeftResult = upOrLeftResult
+        this.downOrRightResult = downOrRightResult
+    }
+
+    private fun computeSwipesResults(
+        fromScene: Scene,
+        swipes: Swipes
+    ): Pair<UserActionResult?, UserActionResult?> {
+        val userActions = fromScene.userActions
+        fun sceneToSwipePair(swipe: Swipe?): UserActionResult? {
+            return userActions[swipe ?: return null]
+        }
+
+        val upOrLeftResult =
+            sceneToSwipePair(swipes.upOrLeft) ?: sceneToSwipePair(swipes.upOrLeftNoSource)
+        val downOrRightResult =
+            sceneToSwipePair(swipes.downOrRight) ?: sceneToSwipePair(swipes.downOrRightNoSource)
+        return Pair(upOrLeftResult, downOrRightResult)
     }
 
     /**
@@ -229,9 +297,9 @@
         // If the offset is past the distance then let's change fromScene so that the user can swipe
         // to the next screen or go back to the previous one.
         val offset = swipeTransition.dragOffset
-        return if (offset <= -absoluteDistance && upOrLeftScene == toScene.key) {
+        return if (offset <= -absoluteDistance && upOrLeftResult?.toScene == toScene.key) {
             Pair(toScene, absoluteDistance)
-        } else if (offset >= absoluteDistance && downOrRightScene == toScene.key) {
+        } else if (offset >= absoluteDistance && downOrRightResult?.toScene == toScene.key) {
             Pair(toScene, -absoluteDistance)
         } else {
             Pair(fromScene, 0f)
@@ -239,63 +307,59 @@
     }
 
     /**
-     * Returns the target scene and distance from [fromScene] in the direction [directionOffset].
+     * Returns the [UserActionResult] from [fromScene] in the direction of [directionOffset].
      *
      * @param fromScene the scene from which we look for the target
      * @param directionOffset signed float that indicates the direction. Positive is down or right
      *   negative is up or left.
-     * @param updateScenes whether the target scenes should be updated to the current values held in
-     *   the Scenes map. Usually we don't want to update them while doing a drag, because this could
-     *   change the target scene (jump cutting) to a different scene, when some system state changed
-     *   the targets the background. However, an update is needed any time we calculate the targets
-     *   for a new fromScene.
+     * @param updateSwipesResults whether the target scenes should be updated to the current values
+     *   held in the Scenes map. Usually we don't want to update them while doing a drag, because
+     *   this could change the target scene (jump cutting) to a different scene, when some system
+     *   state changed the targets the background. However, an update is needed any time we
+     *   calculate the targets for a new fromScene.
      * @return null when there are no targets in either direction. If one direction is null and you
      *   drag into the null direction this function will return the opposite direction, assuming
      *   that the users intention is to start the drag into the other direction eventually. If
      *   [directionOffset] is 0f and both direction are available, it will default to
-     *   [upOrLeftScene].
+     *   [upOrLeftResult].
      */
-    private inline fun findTargetSceneAndDistance(
+    private fun findUserActionResult(
         fromScene: Scene,
         directionOffset: Float,
-        updateScenes: Boolean,
-    ): Pair<Scene, Float>? {
-        if (updateScenes) updateTargetScenes(fromScene)
-        val absoluteDistance = fromScene.getAbsoluteDistance()
+        updateSwipesResults: Boolean,
+    ): UserActionResult? {
+        if (updateSwipesResults) updateSwipesResults(fromScene)
 
-        // Compute the target scene depending on the current offset.
         return when {
-            upOrLeftScene == null && downOrRightScene == null -> null
-            (directionOffset < 0f && upOrLeftScene != null) || downOrRightScene == null ->
-                Pair(layoutImpl.scene(upOrLeftScene!!), -absoluteDistance)
-            else -> Pair(layoutImpl.scene(downOrRightScene!!), absoluteDistance)
+            upOrLeftResult == null && downOrRightResult == null -> null
+            (directionOffset < 0f && upOrLeftResult != null) || downOrRightResult == null ->
+                upOrLeftResult
+            else -> downOrRightResult
         }
     }
 
     /**
-     * A strict version of [findTargetSceneAndDistance] that will return null when there is no Scene
-     * in [directionOffset] direction
+     * A strict version of [findUserActionResult] that will return null when there is no Scene in
+     * [directionOffset] direction
      */
-    private inline fun findTargetSceneAndDistanceStrict(
-        fromScene: Scene,
-        directionOffset: Float,
-    ): Pair<Scene, Float>? {
-        val absoluteDistance = fromScene.getAbsoluteDistance()
+    private fun findUserActionResultStrict(directionOffset: Float): UserActionResult? {
         return when {
-            directionOffset > 0f ->
-                upOrLeftScene?.let { Pair(layoutImpl.scene(it), -absoluteDistance) }
-            directionOffset < 0f ->
-                downOrRightScene?.let { Pair(layoutImpl.scene(it), absoluteDistance) }
+            directionOffset > 0f -> upOrLeftResult
+            directionOffset < 0f -> downOrRightResult
             else -> null
         }
     }
 
-    private fun Scene.upOrLeft(): SceneKey? {
-        return userActions[actionUpOrLeft] ?: userActions[actionUpOrLeftNoEdge]
-    }
-
-    private fun Scene.downOrRight(): SceneKey? {
-        return userActions[actionDownOrRight] ?: userActions[actionDownOrRightNoEdge]
+    private fun computeAbsoluteDistance(
+        fromScene: Scene,
+        result: UserActionResult,
+    ): Float {
+        return if (result == upOrLeftResult) {
+            -fromScene.getAbsoluteDistance(result.distance)
+        } else {
+            check(result == downOrRightResult)
+            fromScene.getAbsoluteDistance(result.distance)
+        }
     }
 
     internal fun onDragStopped(velocity: Float, canChangeScene: Boolean) {
@@ -304,6 +368,11 @@
             return
         }
 
+        // Important: Make sure that all the code here references the current transition when
+        // [onDragStopped] is called, otherwise the callbacks (like onAnimationCompleted()) might
+        // incorrectly finish a new transition that replaced this one.
+        val swipeTransition = this.swipeTransition
+
         fun animateTo(targetScene: Scene, targetOffset: Float) {
             // If the effective current scene changed, it should be reflected right now in the
             // current scene state, even before the settle animation is ongoing. That way all the
@@ -357,8 +426,8 @@
 
             if (startFromIdlePosition) {
                 // If there is a target scene, we start the overscroll animation.
-                val (targetScene, distance) =
-                    findTargetSceneAndDistanceStrict(fromScene, velocity)
+                val result =
+                    findUserActionResultStrict(velocity)
                         ?: run {
                             // We will not animate
                             layoutState.finishTransition(swipeTransition, idleScene = fromScene.key)
@@ -366,7 +435,7 @@
                         }
 
                 updateTransition(
-                    SwipeTransition(fromScene, targetScene, distance).apply {
+                    SwipeTransition(fromScene, result).apply {
                         _currentScene = swipeTransition._currentScene
                     }
                 )
@@ -413,6 +482,14 @@
         }
     }
 
+    private fun SwipeTransition(fromScene: Scene, result: UserActionResult): SwipeTransition {
+        return SwipeTransition(
+            fromScene,
+            layoutImpl.scene(result.toScene),
+            computeAbsoluteDistance(fromScene, result),
+        )
+    }
+
     internal class SwipeTransition(
         val _fromScene: Scene,
         val _toScene: Scene,
@@ -420,7 +497,7 @@
          * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is
          * above or to the left of [toScene].
          */
-        val distance: Float
+        val distance: Float,
     ) : TransitionState.Transition(_fromScene.key, _toScene.key) {
         var _currentScene by mutableStateOf(_fromScene)
         override val currentScene: SceneKey
@@ -453,6 +530,9 @@
         /** Job to check that there is at most one offset animation in progress. */
         private var offsetAnimationJob: Job? = null
 
+        /** The spec to use when animating this transition to either [fromScene] or [toScene]. */
+        lateinit var swipeSpec: SpringSpec<Float>
+
         /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
         private fun startOffsetAnimation(job: () -> Job) {
             cancelOffsetAnimation()
@@ -474,13 +554,6 @@
             }
         }
 
-        // TODO(b/290184746): Make this spring spec configurable.
-        private val animationSpec =
-            spring(
-                stiffness = Spring.StiffnessMediumLow,
-                visibilityThreshold = OffsetVisibilityThreshold
-            )
-
         fun animateOffset(
             // TODO(b/317063114) The CoroutineScope should be removed.
             coroutineScope: CoroutineScope,
@@ -504,7 +577,7 @@
 
             offsetAnimatable.animateTo(
                 targetValue = targetOffset,
-                animationSpec = animationSpec,
+                animationSpec = swipeSpec,
                 initialVelocity = initialVelocity,
             )
 
@@ -515,6 +588,26 @@
     companion object {
         private const val TAG = "SceneGestureHandler"
     }
+
+    private object DefaultSwipeDistance : UserActionDistance {
+        override fun Density.absoluteDistance(
+            fromSceneSize: IntSize,
+            orientation: Orientation,
+        ): Float {
+            return when (orientation) {
+                Orientation.Horizontal -> fromSceneSize.width
+                Orientation.Vertical -> fromSceneSize.height
+            }.toFloat()
+        }
+    }
+
+    /** The [Swipe] associated to a given fromScene, startedPosition and pointersDown. */
+    private class Swipes(
+        val upOrLeft: Swipe?,
+        val downOrRight: Swipe?,
+        val upOrLeftNoSource: Swipe?,
+        val downOrRightNoSource: Swipe?,
+    )
 }
 
 private class SceneDraggableHandler(
@@ -589,6 +682,7 @@
         }
 
         val source = this
+        var isIntercepting = false
 
         return PriorityNestedScrollConnection(
             orientation = orientation,
@@ -596,7 +690,9 @@
                 canChangeScene = offsetBeforeStart == 0f
 
                 val canInterceptSwipeTransition =
-                    canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable != 0f
+                    canChangeScene &&
+                        offsetAvailable != 0f &&
+                        gestureHandler.shouldImmediatelyIntercept(startedPosition = null)
                 if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
 
                 val swipeTransition = gestureHandler.swipeTransition
@@ -614,7 +710,12 @@
                 }
 
                 // Start only if we cannot consume this event
-                !shouldSnapToIdle
+                val canStart = !shouldSnapToIdle
+                if (canStart) {
+                    isIntercepting = true
+                }
+
+                canStart
             },
             canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
                 val behavior: NestedScrollBehavior =
@@ -626,24 +727,31 @@
 
                 val isZeroOffset = offsetBeforeStart == 0f
 
-                when (behavior) {
-                    NestedScrollBehavior.DuringTransitionBetweenScenes -> {
-                        canChangeScene = false // unused: added for consistency
-                        false
+                val canStart =
+                    when (behavior) {
+                        NestedScrollBehavior.DuringTransitionBetweenScenes -> {
+                            canChangeScene = false // unused: added for consistency
+                            false
+                        }
+                        NestedScrollBehavior.EdgeNoPreview -> {
+                            canChangeScene = isZeroOffset
+                            isZeroOffset && hasNextScene(offsetAvailable)
+                        }
+                        NestedScrollBehavior.EdgeWithPreview -> {
+                            canChangeScene = isZeroOffset
+                            hasNextScene(offsetAvailable)
+                        }
+                        NestedScrollBehavior.EdgeAlways -> {
+                            canChangeScene = true
+                            hasNextScene(offsetAvailable)
+                        }
                     }
-                    NestedScrollBehavior.EdgeNoPreview -> {
-                        canChangeScene = isZeroOffset
-                        isZeroOffset && hasNextScene(offsetAvailable)
-                    }
-                    NestedScrollBehavior.EdgeWithPreview -> {
-                        canChangeScene = isZeroOffset
-                        hasNextScene(offsetAvailable)
-                    }
-                    NestedScrollBehavior.EdgeAlways -> {
-                        canChangeScene = true
-                        hasNextScene(offsetAvailable)
-                    }
+
+                if (canStart) {
+                    isIntercepting = false
                 }
+
+                canStart
             },
             canStartPostFling = { velocityAvailable ->
                 val behavior: NestedScrollBehavior =
@@ -655,7 +763,13 @@
 
                 // We could start an overscroll animation
                 canChangeScene = false
-                behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
+
+                val canStart = behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
+                if (canStart) {
+                    isIntercepting = false
+                }
+
+                canStart
             },
             canContinueScroll = { true },
             canScrollOnFling = false,
@@ -664,7 +778,7 @@
                 gestureHandler.onDragStarted(
                     pointersDown = 1,
                     startedPosition = null,
-                    overSlop = offsetAvailable,
+                    overSlop = if (isIntercepting) 0f else offsetAvailable,
                 )
             },
             onScroll = { offsetAvailable ->
@@ -699,4 +813,6 @@
  * The number of pixels below which there won't be a visible difference in the transition and from
  * which the animation can stop.
  */
-private const val OffsetVisibilityThreshold = 0.5f
+// TODO(b/290184746): Have a better default visibility threshold which takes the swipe distance into
+// account instead.
+internal const val OffsetVisibilityThreshold = 0.5f
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 80f8c1c..7e0aa9c3 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
@@ -27,6 +27,10 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntSize
 
 /**
  * [SceneTransitionLayout] is a container that automatically animates its content whenever its state
@@ -38,7 +42,8 @@
  * UI code.
  *
  * @param state the state of this layout.
- * @param edgeDetector the edge detector used to detect which edge a swipe is started from, if any.
+ * @param swipeSourceDetector the edge detector used to detect which edge a swipe is started from,
+ *   if any.
  * @param transitionInterceptionThreshold used during a scene transition. For the scene to be
  *   intercepted, the progress value must be above the threshold, and below (1 - threshold).
  * @param scenes the configuration of the different scenes of this layout.
@@ -48,14 +53,14 @@
 fun SceneTransitionLayout(
     state: SceneTransitionLayoutState,
     modifier: Modifier = Modifier,
-    edgeDetector: EdgeDetector = DefaultEdgeDetector,
+    swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
     @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f,
     scenes: SceneTransitionLayoutScope.() -> Unit,
 ) {
     SceneTransitionLayoutForTesting(
         state,
         modifier,
-        edgeDetector,
+        swipeSourceDetector,
         transitionInterceptionThreshold,
         onLayoutImpl = null,
         scenes,
@@ -76,7 +81,8 @@
  *   This is called when the user commits a transition to a new scene because of a [UserAction], for
  *   instance by triggering back navigation or by swiping to a new scene.
  * @param transitions the definition of the transitions used to animate a change of scene.
- * @param edgeDetector the edge detector used to detect which edge a swipe is started from, if any.
+ * @param swipeSourceDetector the source detector used to detect which source a swipe is started
+ *   from, if any.
  * @param transitionInterceptionThreshold used during a scene transition. For the scene to be
  *   intercepted, the progress value must be above the threshold, and below (1 - threshold).
  * @param scenes the configuration of the different scenes of this layout.
@@ -87,7 +93,7 @@
     onChangeScene: (SceneKey) -> Unit,
     transitions: SceneTransitions,
     modifier: Modifier = Modifier,
-    edgeDetector: EdgeDetector = DefaultEdgeDetector,
+    swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
     @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f,
     scenes: SceneTransitionLayoutScope.() -> Unit,
 ) {
@@ -95,7 +101,7 @@
     SceneTransitionLayout(
         state,
         modifier,
-        edgeDetector,
+        swipeSourceDetector,
         transitionInterceptionThreshold,
         scenes,
     )
@@ -113,7 +119,7 @@
      */
     fun scene(
         key: SceneKey,
-        userActions: Map<UserAction, SceneKey> = emptyMap(),
+        userActions: Map<UserAction, UserActionResult> = emptyMap(),
         content: @Composable SceneScope.() -> Unit,
     )
 }
@@ -335,7 +341,7 @@
 data class Swipe(
     val direction: SwipeDirection,
     val pointerCount: Int = 1,
-    val fromEdge: Edge? = null,
+    val fromSource: SwipeSource? = null,
 ) : UserAction {
     companion object {
         val Left = Swipe(SwipeDirection.Left)
@@ -353,6 +359,95 @@
 }
 
 /**
+ * The source of a Swipe.
+ *
+ * Important: This can be anything that can be returned by any [SwipeSourceDetector], but this must
+ * implement [equals] and [hashCode]. Note that those can be trivially implemented using data
+ * classes.
+ */
+interface SwipeSource {
+    // Require equals() and hashCode() to be implemented.
+    override fun equals(other: Any?): Boolean
+
+    override fun hashCode(): Int
+}
+
+interface SwipeSourceDetector {
+    /**
+     * Return the [SwipeSource] associated to [position] inside a layout of size [layoutSize], given
+     * [density] and [orientation].
+     */
+    fun source(
+        layoutSize: IntSize,
+        position: IntOffset,
+        density: Density,
+        orientation: Orientation,
+    ): SwipeSource?
+}
+
+/**
+ * The result of performing a [UserAction].
+ *
+ * Note: [UserActionResult] is implemented by [SceneKey], and you can also use [withDistance] to
+ * easily create a [UserActionResult] with a fixed distance:
+ * ```
+ * SceneTransitionLayout(...) {
+ *     scene(
+ *         Scenes.Foo,
+ *         userActions =
+ *             mapOf(
+ *                 Swipe.Right to Scene.Bar,
+ *                 Swipe.Down to Scene.Doe withDistance 100.dp,
+ *             )
+ *         )
+ *     ) { ... }
+ * }
+ * ```
+ */
+interface UserActionResult {
+    /** The scene we should be transitioning to during the [UserAction]. */
+    val toScene: SceneKey
+
+    /**
+     * The distance the action takes to animate from 0% to 100%.
+     *
+     * If `null`, a default distance will be used that depends on the [UserAction] performed.
+     */
+    val distance: UserActionDistance?
+}
+
+interface UserActionDistance {
+    /**
+     * Return the **absolute** distance of the user action given the size of the scene we are
+     * animating from and the [orientation].
+     */
+    fun Density.absoluteDistance(fromSceneSize: IntSize, orientation: Orientation): Float
+}
+
+/**
+ * A utility function to make it possible to define user actions with a distance using the syntax
+ * `Swipe.Up to Scene.foo withDistance 100.dp`
+ */
+infix fun Pair<UserAction, SceneKey>.withDistance(
+    distance: Dp
+): Pair<UserAction, UserActionResult> {
+    val scene = second
+    val distance = FixedDistance(distance)
+    return first to
+        object : UserActionResult {
+            override val toScene: SceneKey = scene
+            override val distance: UserActionDistance = distance
+        }
+}
+
+/** The user action has a fixed [absoluteDistance]. */
+private class FixedDistance(private val distance: Dp) : UserActionDistance {
+    override fun Density.absoluteDistance(fromSceneSize: IntSize, orientation: Orientation): Float {
+        return distance.toPx()
+    }
+}
+
+/**
  * An internal version of [SceneTransitionLayout] to be used for tests.
  *
  * Important: You should use this only in tests and if you need to access the underlying
@@ -362,7 +457,7 @@
 internal fun SceneTransitionLayoutForTesting(
     state: SceneTransitionLayoutState,
     modifier: Modifier = Modifier,
-    edgeDetector: EdgeDetector = DefaultEdgeDetector,
+    swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
     transitionInterceptionThreshold: Float = 0f,
     onLayoutImpl: ((SceneTransitionLayoutImpl) -> Unit)? = null,
     scenes: SceneTransitionLayoutScope.() -> Unit,
@@ -373,7 +468,7 @@
         SceneTransitionLayoutImpl(
                 state = state as BaseSceneTransitionLayoutState,
                 density = density,
-                edgeDetector = edgeDetector,
+                swipeSourceDetector = swipeSourceDetector,
                 transitionInterceptionThreshold = transitionInterceptionThreshold,
                 builder = scenes,
                 coroutineScope = coroutineScope,
@@ -394,7 +489,7 @@
         }
 
         layoutImpl.density = density
-        layoutImpl.edgeDetector = edgeDetector
+        layoutImpl.swipeSourceDetector = swipeSourceDetector
     }
 
     layoutImpl.Content(modifier)
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 7cc9d26..8c5a472 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
@@ -47,7 +47,7 @@
 internal class SceneTransitionLayoutImpl(
     internal val state: BaseSceneTransitionLayoutState,
     internal var density: Density,
-    internal var edgeDetector: EdgeDetector,
+    internal var swipeSourceDetector: SwipeSourceDetector,
     internal var transitionInterceptionThreshold: Float,
     builder: SceneTransitionLayoutScope.() -> Unit,
     private val coroutineScope: CoroutineScope,
@@ -140,7 +140,7 @@
         object : SceneTransitionLayoutScope {
                 override fun scene(
                     key: SceneKey,
-                    userActions: Map<UserAction, SceneKey>,
+                    userActions: Map<UserAction, UserActionResult>,
                     content: @Composable SceneScope.() -> Unit,
                 ) {
                     scenesToRemove.remove(key)
@@ -229,8 +229,10 @@
                 // Handle back events.
                 // TODO(b/290184746): Make sure that this works with SystemUI once we use
                 // SceneTransitionLayout in Flexiglass.
-                scene(state.transitionState.currentScene).userActions[Back]?.let { backScene ->
-                    BackHandler { with(state) { coroutineScope.onChangeScene(backScene) } }
+                scene(state.transitionState.currentScene).userActions[Back]?.let { result ->
+                    // TODO(b/290184746): Handle predictive back and use result.distance if
+                    // specified.
+                    BackHandler { with(state) { coroutineScope.onChangeScene(result.toScene) } }
                 }
 
                 Box {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index 3a55567..ac423b7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -17,7 +17,10 @@
 package com.android.compose.animation.scene
 
 import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.SpringSpec
 import androidx.compose.animation.core.snap
+import androidx.compose.animation.core.spring
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.util.fastForEach
@@ -36,6 +39,7 @@
 /** The transitions configuration of a [SceneTransitionLayout]. */
 class SceneTransitions
 internal constructor(
+    internal val defaultSwipeSpec: SpringSpec<Float>,
     internal val transitionSpecs: List<TransitionSpecImpl>,
 ) {
     private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpecImpl>>()
@@ -91,7 +95,13 @@
         TransitionSpecImpl(from, to, TransformationSpec.EmptyProvider)
 
     companion object {
-        val Empty = SceneTransitions(transitionSpecs = emptyList())
+        internal val DefaultSwipeSpec =
+            spring(
+                stiffness = Spring.StiffnessMediumLow,
+                visibilityThreshold = OffsetVisibilityThreshold,
+            )
+
+        val Empty = SceneTransitions(DefaultSwipeSpec, transitionSpecs = emptyList())
     }
 }
 
@@ -125,15 +135,30 @@
 }
 
 interface TransformationSpec {
-    /** The [AnimationSpec] used to animate the associated transition progress. */
+    /**
+     * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
+     * the transition is triggered (i.e. it is not gesture-based).
+     */
     val progressSpec: AnimationSpec<Float>
 
+    /**
+     * The [SpringSpec] used to animate the associated transition progress when the transition was
+     * started by a swipe and is now animating back to a scene because the user lifted their finger.
+     *
+     * If `null`, then the [SceneTransitions.defaultSwipeSpec] will be used.
+     */
+    val swipeSpec: SpringSpec<Float>?
+
     /** The list of [Transformation] applied to elements during this transition. */
     val transformations: List<Transformation>
 
     companion object {
         internal val Empty =
-            TransformationSpecImpl(progressSpec = snap(), transformations = emptyList())
+            TransformationSpecImpl(
+                progressSpec = snap(),
+                swipeSpec = null,
+                transformations = emptyList(),
+            )
         internal val EmptyProvider = { Empty }
     }
 }
@@ -151,6 +176,7 @@
                 val reverse = transformationSpec.invoke()
                 TransformationSpecImpl(
                     progressSpec = reverse.progressSpec,
+                    swipeSpec = reverse.swipeSpec,
                     transformations = reverse.transformations.map { it.reversed() }
                 )
             }
@@ -166,6 +192,7 @@
  */
 internal class TransformationSpecImpl(
     override val progressSpec: AnimationSpec<Float>,
+    override val swipeSpec: SpringSpec<Float>?,
     override val transformations: List<Transformation>,
 ) : TransformationSpec {
     private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 0d3bc7d..61f4978 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -17,40 +17,96 @@
 package com.android.compose.animation.scene
 
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.runtime.Stable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.pointer.PointerEvent
+import androidx.compose.ui.input.pointer.PointerEventPass
+import androidx.compose.ui.node.DelegatingNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.PointerInputModifierNode
+import androidx.compose.ui.unit.IntSize
 
 /**
  * Configures the swipeable behavior of a [SceneTransitionLayout] depending on the current state.
  */
+@Stable
 internal fun Modifier.swipeToScene(gestureHandler: SceneGestureHandler): Modifier {
-    /** Whether swipe should be enabled in the given [orientation]. */
-    fun Scene.shouldEnableSwipes(orientation: Orientation): Boolean =
-        userActions.keys.any { it is Swipe && it.direction.orientation == orientation }
+    return this.then(SwipeToSceneElement(gestureHandler))
+}
 
-    val layoutImpl = gestureHandler.layoutImpl
-    val currentScene = layoutImpl.scene(layoutImpl.state.transitionState.currentScene)
-    val orientation = gestureHandler.orientation
-    val canSwipe = currentScene.shouldEnableSwipes(orientation)
-    val canOppositeSwipe =
-        currentScene.shouldEnableSwipes(
-            when (orientation) {
+private data class SwipeToSceneElement(
+    val gestureHandler: SceneGestureHandler,
+) : ModifierNodeElement<SwipeToSceneNode>() {
+    override fun create(): SwipeToSceneNode = SwipeToSceneNode(gestureHandler)
+
+    override fun update(node: SwipeToSceneNode) {
+        node.gestureHandler = gestureHandler
+    }
+}
+
+private class SwipeToSceneNode(
+    gestureHandler: SceneGestureHandler,
+) : DelegatingNode(), PointerInputModifierNode {
+    private val delegate =
+        delegate(
+            MultiPointerDraggableNode(
+                orientation = gestureHandler.orientation,
+                enabled = ::enabled,
+                startDragImmediately = ::startDragImmediately,
+                onDragStarted = gestureHandler.draggable::onDragStarted,
+                onDragDelta = gestureHandler.draggable::onDelta,
+                onDragStopped = gestureHandler.draggable::onDragStopped,
+            )
+        )
+
+    var gestureHandler: SceneGestureHandler = gestureHandler
+        set(value) {
+            if (value != field) {
+                field = value
+
+                // Make sure to update the delegate orientation. Note that this will automatically
+                // reset the underlying pointer input handler, so previous gestures will be
+                // cancelled.
+                delegate.orientation = value.orientation
+            }
+        }
+
+    override fun onPointerEvent(
+        pointerEvent: PointerEvent,
+        pass: PointerEventPass,
+        bounds: IntSize,
+    ) = delegate.onPointerEvent(pointerEvent, pass, bounds)
+
+    override fun onCancelPointerInput() = delegate.onCancelPointerInput()
+
+    private fun enabled(): Boolean {
+        return gestureHandler.isDrivingTransition ||
+            currentScene().shouldEnableSwipes(gestureHandler.orientation)
+    }
+
+    private fun currentScene(): Scene {
+        val layoutImpl = gestureHandler.layoutImpl
+        return layoutImpl.scene(layoutImpl.state.transitionState.currentScene)
+    }
+
+    /** Whether swipe should be enabled in the given [orientation]. */
+    private fun Scene.shouldEnableSwipes(orientation: Orientation): Boolean {
+        return userActions.keys.any { it is Swipe && it.direction.orientation == orientation }
+    }
+
+    private fun startDragImmediately(startedPosition: Offset): Boolean {
+        // Immediately start the drag if the user can't swipe in the other direction and the gesture
+        // handler can intercept it.
+        return !canOppositeSwipe() && gestureHandler.shouldImmediatelyIntercept(startedPosition)
+    }
+
+    private fun canOppositeSwipe(): Boolean {
+        val oppositeOrientation =
+            when (gestureHandler.orientation) {
                 Orientation.Vertical -> Orientation.Horizontal
                 Orientation.Horizontal -> Orientation.Vertical
             }
-        )
-
-    return multiPointerDraggable(
-        orientation = orientation,
-        enabled = gestureHandler.isDrivingTransition || canSwipe,
-        // Immediately start the drag if this our [transition] is currently animating to a scene
-        // (i.e. the user released their input pointer after swiping in this orientation) and the
-        // user can't swipe in the other direction.
-        startDragImmediately =
-            gestureHandler.isDrivingTransition &&
-                gestureHandler.swipeTransition.isAnimatingOffset &&
-                !canOppositeSwipe,
-        onDragStarted = gestureHandler.draggable::onDragStarted,
-        onDragDelta = gestureHandler.draggable::onDelta,
-        onDragStopped = gestureHandler.draggable::onDragStopped,
-    )
+        return currentScene().shouldEnableSwipes(oppositeOrientation)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index dc8505c..04e0937 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -17,6 +17,7 @@
 package com.android.compose.animation.scene
 
 import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.SpringSpec
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
@@ -31,6 +32,12 @@
 @TransitionDsl
 interface SceneTransitionsBuilder {
     /**
+     * The default [AnimationSpec] used when after the user lifts their finger after starting a
+     * swipe to transition, to animate back into one of the 2 scenes we are transitioning to.
+     */
+    var defaultSwipeSpec: SpringSpec<Float>
+
+    /**
      * Define the default animation to be played when transitioning [to] the specified scene, from
      * any scene. For the animation specification to apply only when transitioning between two
      * specific scenes, use [from] instead.
@@ -64,12 +71,20 @@
 @TransitionDsl
 interface TransitionBuilder : PropertyTransformationBuilder {
     /**
-     * The [AnimationSpec] used to animate the progress of this transition from `0` to `1` when
-     * performing programmatic (not input pointer tracking) animations.
+     * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
+     * the transition is triggered (i.e. it is not gesture-based).
      */
     var spec: AnimationSpec<Float>
 
     /**
+     * The [SpringSpec] used to animate the associated transition progress when the transition was
+     * started by a swipe and is now animating back to a scene because the user lifted their finger.
+     *
+     * If `null`, then the [SceneTransitionsBuilder.defaultSwipeSpec] will be used.
+     */
+    var swipeSpec: SpringSpec<Float>?
+
+    /**
      * Define a progress-based range for the transformations inside [builder].
      *
      * For instance, the following will fade `Foo` during the first half of the transition then it
@@ -320,11 +335,3 @@
         anchorHeight: Boolean = true,
     )
 }
-
-/** The edge of a [SceneTransitionLayout]. */
-enum class Edge {
-    Left,
-    Right,
-    Top,
-    Bottom,
-}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index b96f9be..df186a1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -19,6 +19,7 @@
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.DurationBasedAnimationSpec
 import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.SpringSpec
 import androidx.compose.animation.core.VectorConverter
 import androidx.compose.animation.core.spring
 import androidx.compose.ui.geometry.Offset
@@ -40,10 +41,12 @@
     builder: SceneTransitionsBuilder.() -> Unit,
 ): SceneTransitions {
     val impl = SceneTransitionsBuilderImpl().apply(builder)
-    return SceneTransitions(impl.transitionSpecs)
+    return SceneTransitions(impl.defaultSwipeSpec, impl.transitionSpecs)
 }
 
 private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
+    override var defaultSwipeSpec: SpringSpec<Float> = SceneTransitions.DefaultSwipeSpec
+
     val transitionSpecs = mutableListOf<TransitionSpecImpl>()
 
     override fun to(to: SceneKey, builder: TransitionBuilder.() -> Unit): TransitionSpec {
@@ -67,6 +70,7 @@
             val impl = TransitionBuilderImpl().apply(builder)
             return TransformationSpecImpl(
                 progressSpec = impl.spec,
+                swipeSpec = impl.swipeSpec,
                 transformations = impl.transformations,
             )
         }
@@ -80,6 +84,7 @@
 internal class TransitionBuilderImpl : TransitionBuilder {
     val transformations = mutableListOf<Transformation>()
     override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
+    override var swipeSpec: SpringSpec<Float>? = null
 
     private var range: TransformationRange? = null
     private var reversed = false
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index 2841bcf..ac11d30 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -22,6 +22,7 @@
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.unit.Velocity
 import com.android.compose.ui.util.SpaceVectorConverter
+import kotlin.math.sign
 
 /**
  * This [NestedScrollConnection] waits for a child to scroll ([onPreScroll] or [onPostScroll]), and
@@ -117,7 +118,12 @@
             return Velocity.Zero
         }
 
-        onPriorityStart(available = Offset.Zero)
+        // The offset passed to onPriorityStart() must be != 0f, so we create a small offset of 1px
+        // given the available velocity.
+        // TODO(b/291053278): Remove canStartPostFling() and instead make it possible to define the
+        // overscroll behavior on the Scene level.
+        val smallOffset = Offset(available.x.sign, available.y.sign)
+        onPriorityStart(available = smallOffset)
 
         // This is the last event of a scroll gesture.
         return onPriorityStop(available)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
index a68282a..cceaf57 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
@@ -35,7 +35,7 @@
     @Test
     fun horizontalEdges() {
         fun horizontalEdge(position: Int): Edge? =
-            detector.edge(
+            detector.source(
                 layoutSize,
                 position = IntOffset(position, 0),
                 density,
@@ -53,7 +53,7 @@
     @Test
     fun verticalEdges() {
         fun verticalEdge(position: Int): Edge? =
-            detector.edge(
+            detector.source(
                 layoutSize,
                 position = IntOffset(0, position),
                 density,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index 066a3e4..e8cc0ec 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -21,7 +21,6 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.Velocity
@@ -77,7 +76,7 @@
                 userActions =
                     mapOf(
                         Swipe.Up to SceneB,
-                        Swipe(SwipeDirection.Up, fromEdge = Edge.Bottom) to SceneA
+                        Swipe(SwipeDirection.Up, fromSource = Edge.Bottom) to SceneA
                     ),
             ) {
                 Text("SceneC")
@@ -90,7 +89,7 @@
             SceneTransitionLayoutImpl(
                     state = layoutState,
                     density = Density(1f),
-                    edgeDetector = DefaultEdgeDetector,
+                    swipeSourceDetector = DefaultEdgeDetector,
                     transitionInterceptionThreshold = transitionInterceptionThreshold,
                     builder = scenesBuilder,
                     coroutineScope = coroutineScope,
@@ -118,9 +117,6 @@
         fun up(fractionOfScreen: Float) =
             if (fractionOfScreen < 0f) error("use down()") else -down(fractionOfScreen)
 
-        // Float tolerance for comparisons
-        val tolerance = 0.00001f
-
         // Offset y: 10% of the screen
         val offsetY10 = Offset(x = 0f, y = down(0.1f))
 
@@ -150,31 +146,42 @@
             fromScene: SceneKey? = null,
             toScene: SceneKey? = null,
             progress: Float? = null,
+            isUserInputOngoing: Boolean? = null
         ) {
+            val transition = transitionState
             assertWithMessage("transitionState must be Transition")
-                .that(transitionState is Transition)
+                .that(transition is Transition)
                 .isTrue()
+            transition as Transition
+
             if (currentScene != null)
                 assertWithMessage("currentScene does not match")
-                    .that(transitionState.currentScene)
+                    .that(transition.currentScene)
                     .isEqualTo(currentScene)
+
             if (fromScene != null)
                 assertWithMessage("fromScene does not match")
-                    .that((transitionState as? Transition)?.fromScene)
+                    .that(transition.fromScene)
                     .isEqualTo(fromScene)
+
             if (toScene != null)
                 assertWithMessage("toScene does not match")
-                    .that((transitionState as? Transition)?.toScene)
+                    .that(transition.toScene)
                     .isEqualTo(toScene)
+
             if (progress != null)
                 assertWithMessage("progress does not match")
-                    .that((transitionState as? Transition)?.progress)
-                    .isWithin(tolerance)
+                    .that(transition.progress)
+                    .isWithin(0f) // returns true when comparing 0.0f with -0.0f
                     .of(progress)
+
+            if (isUserInputOngoing != null)
+                assertWithMessage("isUserInputOngoing does not match")
+                    .that(transition.isUserInputOngoing)
+                    .isEqualTo(isUserInputOngoing)
         }
     }
 
-    @OptIn(ExperimentalTestApi::class)
     private fun runGestureTest(block: suspend TestGestureScope.() -> Unit) {
         runMonotonicClockTest { TestGestureScope(coroutineScope = this).block() }
     }
@@ -192,16 +199,14 @@
 
     @Test
     fun onDragStarted_shouldStartATransition() = runGestureTest {
-        draggable.onDragStarted()
+        draggable.onDragStarted(overSlop = down(0.1f))
         assertTransition(currentScene = SceneA)
     }
 
     @Test
     fun afterSceneTransitionIsStarted_interceptDragEvents() = runGestureTest {
-        draggable.onDragStarted()
+        draggable.onDragStarted(overSlop = down(0.1f))
         assertTransition(currentScene = SceneA)
-
-        draggable.onDelta(pixels = down(0.1f))
         assertThat(progress).isEqualTo(0.1f)
 
         draggable.onDelta(pixels = down(0.1f))
@@ -210,10 +215,7 @@
 
     @Test
     fun onDragStoppedAfterDrag_velocityLowerThanThreshold_remainSameScene() = runGestureTest {
-        draggable.onDragStarted()
-        assertTransition(currentScene = SceneA)
-
-        draggable.onDelta(pixels = down(0.1f))
+        draggable.onDragStarted(overSlop = down(0.1f))
         assertTransition(currentScene = SceneA)
 
         draggable.onDragStopped(
@@ -228,10 +230,7 @@
 
     @Test
     fun onDragStoppedAfterDrag_velocityAtLeastThreshold_goToNextScene() = runGestureTest {
-        draggable.onDragStarted()
-        assertTransition(currentScene = SceneA)
-
-        draggable.onDelta(pixels = down(0.1f))
+        draggable.onDragStarted(overSlop = down(0.1f))
         assertTransition(currentScene = SceneA)
 
         draggable.onDragStopped(velocity = velocityThreshold)
@@ -245,7 +244,7 @@
 
     @Test
     fun onDragStoppedAfterStarted_returnToIdle() = runGestureTest {
-        draggable.onDragStarted()
+        draggable.onDragStarted(overSlop = down(0.1f))
         assertTransition(currentScene = SceneA)
 
         draggable.onDragStopped(velocity = 0f)
@@ -256,8 +255,7 @@
     @Test
     fun onDragReversedDirection_changeToScene() = runGestureTest {
         // Drag A -> B with progress 0.6
-        draggable.onDragStarted()
-        draggable.onDelta(up(0.6f))
+        draggable.onDragStarted(overSlop = -60f)
         assertTransition(
             currentScene = SceneA,
             fromScene = SceneA,
@@ -266,7 +264,7 @@
         )
 
         // Reverse direction such that A -> C now with 0.4
-        draggable.onDelta(down(1f))
+        draggable.onDelta(100f)
         assertTransition(
             currentScene = SceneA,
             fromScene = SceneA,
@@ -296,7 +294,7 @@
         navigateToSceneC()
 
         // We are on SceneC which has no action in Down direction
-        draggable.onDragStarted(down(0.1f))
+        draggable.onDragStarted(10f)
         assertTransition(
             currentScene = SceneC,
             fromScene = SceneC,
@@ -305,7 +303,7 @@
         )
 
         // Reverse drag direction, it will consume the previous drag
-        draggable.onDelta(up(0.1f))
+        draggable.onDelta(-10f)
         assertTransition(
             currentScene = SceneC,
             fromScene = SceneC,
@@ -314,7 +312,7 @@
         )
 
         // Continue reverse drag direction, it should record progress to Scene B
-        draggable.onDelta(up(0.1f))
+        draggable.onDelta(-10f)
         assertTransition(
             currentScene = SceneC,
             fromScene = SceneC,
@@ -366,8 +364,7 @@
     @Test
     fun onAccelaratedScroll_scrollToThirdScene() = runGestureTest {
         // Drag A -> B with progress 0.2
-        draggable.onDragStarted()
-        draggable.onDelta(up(0.2f))
+        draggable.onDragStarted(overSlop = up(0.2f))
         assertTransition(
             currentScene = SceneA,
             fromScene = SceneA,
@@ -401,9 +398,7 @@
 
     @Test
     fun onAccelaratedScrollBothTargetsBecomeNull_settlesToIdle() = runGestureTest {
-        draggable.onDragStarted()
-        draggable.onDelta(up(0.2f))
-
+        draggable.onDragStarted(overSlop = up(0.2f))
         draggable.onDelta(up(0.2f))
         draggable.onDragStopped(velocity = -velocityThreshold)
         assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB)
@@ -459,16 +454,14 @@
         draggable.onDragStopped(down(0.1f))
 
         // now target changed to C for new drag that started before previous drag settled to Idle
-        draggable.onDragStarted(up(0.1f))
+        draggable.onDragStarted(overSlop = 0f)
+        draggable.onDelta(up(0.1f))
         assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0.3f)
     }
 
     @Test
     fun startGestureDuringAnimatingOffset_shouldImmediatelyStopTheAnimation() = runGestureTest {
-        draggable.onDragStarted()
-        assertTransition(currentScene = SceneA)
-
-        draggable.onDelta(pixels = down(0.1f))
+        draggable.onDragStarted(overSlop = down(0.1f))
         assertTransition(currentScene = SceneA)
 
         draggable.onDragStopped(
@@ -571,53 +564,53 @@
     ) {
         val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview)
         // start scene transition
-        nestedScroll.scroll(available = Offset(0f, SCREEN_SIZE * firstScroll))
+        nestedScroll.scroll(available = Offset(0f, firstScroll))
 
         // stop scene transition (start the "stop animation")
         nestedScroll.onPreFling(available = Velocity.Zero)
 
         // a pre scroll event, that could be intercepted by SceneGestureHandler
-        nestedScroll.onPreScroll(Offset(0f, SCREEN_SIZE * secondScroll), NestedScrollSource.Drag)
+        nestedScroll.onPreScroll(Offset(0f, secondScroll), NestedScrollSource.Drag)
     }
 
     @Test
     fun scrollAndFling_scrollLessThanInterceptable_goToIdleOnCurrentScene() = runGestureTest {
-        val first = transitionInterceptionThreshold - tolerance
-        val second = 0.01f
+        val firstScroll = (transitionInterceptionThreshold - 0.0001f) * SCREEN_SIZE
+        val secondScroll = 1f
 
-        preScrollAfterSceneTransition(firstScroll = first, secondScroll = second)
+        preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll)
 
         assertIdle(SceneA)
     }
 
     @Test
     fun scrollAndFling_scrollMinInterceptable_interceptPreScrollEvents() = runGestureTest {
-        val first = transitionInterceptionThreshold + tolerance
-        val second = 0.01f
+        val firstScroll = (transitionInterceptionThreshold + 0.0001f) * SCREEN_SIZE
+        val secondScroll = 1f
 
-        preScrollAfterSceneTransition(firstScroll = first, secondScroll = second)
+        preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll)
 
-        assertTransition(progress = first + second)
+        assertTransition(progress = (firstScroll + secondScroll) / SCREEN_SIZE)
     }
 
     @Test
     fun scrollAndFling_scrollMaxInterceptable_interceptPreScrollEvents() = runGestureTest {
-        val first = 1f - transitionInterceptionThreshold - tolerance
-        val second = 0.01f
+        val firstScroll = -(1f - transitionInterceptionThreshold - 0.0001f) * SCREEN_SIZE
+        val secondScroll = -1f
 
-        preScrollAfterSceneTransition(firstScroll = first, secondScroll = second)
+        preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll)
 
-        assertTransition(progress = first + second)
+        assertTransition(progress = -(firstScroll + secondScroll) / SCREEN_SIZE)
     }
 
     @Test
     fun scrollAndFling_scrollMoreThanInterceptable_goToIdleOnNextScene() = runGestureTest {
-        val first = 1f - transitionInterceptionThreshold + tolerance
-        val second = 0.01f
+        val firstScroll = -(1f - transitionInterceptionThreshold + 0.0001f) * SCREEN_SIZE
+        val secondScroll = -0.01f
 
-        preScrollAfterSceneTransition(firstScroll = first, secondScroll = second)
+        preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll)
 
-        assertIdle(SceneC)
+        assertIdle(SceneB)
     }
 
     @Test
@@ -759,31 +752,75 @@
     @Test
     fun startNestedScrollWhileDragging() = runGestureTest {
         val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
-        draggable.onDragStarted()
-        assertTransition(currentScene = SceneA)
 
-        draggable.onDelta(down(0.1f))
+        // Start a drag and then stop it, given that
+        draggable.onDragStarted(overSlop = up(0.1f))
+
+        assertTransition(currentScene = SceneA)
         assertThat(progress).isEqualTo(0.1f)
 
         // now we can intercept the scroll events
-        nestedScroll.scroll(available = offsetY10)
+        nestedScroll.scroll(available = -offsetY10)
         assertThat(progress).isEqualTo(0.2f)
 
         // this should be ignored, we are scrolling now!
-        draggable.onDragStopped(velocityThreshold)
+        draggable.onDragStopped(-velocityThreshold)
         assertTransition(currentScene = SceneA)
 
-        nestedScroll.scroll(available = offsetY10)
+        nestedScroll.scroll(available = -offsetY10)
         assertThat(progress).isEqualTo(0.3f)
 
-        nestedScroll.scroll(available = offsetY10)
+        nestedScroll.scroll(available = -offsetY10)
         assertThat(progress).isEqualTo(0.4f)
 
-        nestedScroll.onPreFling(available = Velocity(0f, velocityThreshold))
-        assertTransition(currentScene = SceneC)
+        nestedScroll.onPreFling(available = Velocity(0f, -velocityThreshold))
+        assertTransition(currentScene = SceneB)
 
         // wait for the stop animation
         advanceUntilIdle()
-        assertIdle(currentScene = SceneC)
+        assertIdle(currentScene = SceneB)
+    }
+
+    @Test
+    fun interceptTransition() = runGestureTest {
+        // Start at scene C.
+        navigateToSceneC()
+
+        // Swipe up from the middle to transition to scene B.
+        val middle = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)
+        draggable.onDragStarted(startedPosition = middle, overSlop = up(0.1f))
+        assertTransition(
+            currentScene = SceneC,
+            fromScene = SceneC,
+            toScene = SceneB,
+            isUserInputOngoing = true,
+        )
+
+        val firstTransition = transitionState
+
+        // During the current gesture, start a new gesture, still in the middle of the screen. We
+        // should intercept it. Because it is intercepted, the overSlop passed to onDragStarted()
+        // should be 0f.
+        assertThat(sceneGestureHandler.shouldImmediatelyIntercept(middle)).isTrue()
+        draggable.onDragStarted(startedPosition = middle, overSlop = 0f)
+
+        // We should have intercepted the transition, so the transition should be the same object.
+        assertTransition(currentScene = SceneC, fromScene = SceneC, toScene = SceneB)
+        assertThat(transitionState).isSameInstanceAs(firstTransition)
+
+        // Start a new gesture from the bottom of the screen. Because swiping up from the bottom of
+        // C leads to scene A (and not B), the previous transitions is *not* intercepted and we
+        // instead animate from C to A.
+        val bottom = Offset(SCREEN_SIZE / 2, SCREEN_SIZE)
+        assertThat(sceneGestureHandler.shouldImmediatelyIntercept(bottom)).isFalse()
+        draggable.onDragStarted(startedPosition = bottom, overSlop = up(0.1f))
+
+        assertTransition(
+            currentScene = SceneC,
+            fromScene = SceneC,
+            toScene = SceneA,
+            isUserInputOngoing = true,
+        )
+        assertThat(transitionState).isNotSameInstanceAs(firstTransition)
     }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index 48825fb..9a25d43 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -91,6 +91,16 @@
     }
 
     @Test
+    fun setTargetScene_transitionToOriginalScene() = runMonotonicClockTest {
+        val state = MutableSceneTransitionLayoutState(TestScenes.SceneA)
+        assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNotNull()
+
+        // Progress is 0f, so we don't animate at all and directly snap back to A.
+        assertThat(state.setTargetScene(TestScenes.SceneA, coroutineScope = this)).isNull()
+        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneA))
+    }
+
+    @Test
     fun setTargetScene_coroutineScopeCancelled() = runMonotonicClockTest {
         val state = MutableSceneTransitionLayoutState(TestScenes.SceneA)
 
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 1ec3c8b..af1a5b8 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -17,9 +17,13 @@
 package com.android.compose.animation.scene
 
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.platform.LocalViewConfiguration
@@ -62,7 +66,10 @@
 
     /** The content under test. */
     @Composable
-    private fun TestContent(layoutState: SceneTransitionLayoutState) {
+    private fun TestContent(
+        layoutState: SceneTransitionLayoutState,
+        swipesEnabled: () -> Boolean = { true },
+    ) {
         SceneTransitionLayout(
             state = layoutState,
             modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.debugName),
@@ -70,28 +77,35 @@
             scene(
                 TestScenes.SceneA,
                 userActions =
-                    mapOf(
-                        Swipe.Left to TestScenes.SceneB,
-                        Swipe.Down to TestScenes.SceneC,
-                    ),
+                    if (swipesEnabled())
+                        mapOf(
+                            Swipe.Left to TestScenes.SceneB,
+                            Swipe.Down to TestScenes.SceneC,
+                            Swipe.Up to TestScenes.SceneB,
+                        )
+                    else emptyMap(),
             ) {
                 Box(Modifier.fillMaxSize())
             }
             scene(
                 TestScenes.SceneB,
-                userActions = mapOf(Swipe.Right to TestScenes.SceneA),
+                userActions =
+                    if (swipesEnabled()) mapOf(Swipe.Right to TestScenes.SceneA) else emptyMap(),
             ) {
                 Box(Modifier.fillMaxSize())
             }
             scene(
                 TestScenes.SceneC,
                 userActions =
-                    mapOf(
-                        Swipe.Down to TestScenes.SceneA,
-                        Swipe(SwipeDirection.Down, pointerCount = 2) to TestScenes.SceneB,
-                        Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to TestScenes.SceneB,
-                        Swipe(SwipeDirection.Down, fromEdge = Edge.Top) to TestScenes.SceneB,
-                    ),
+                    if (swipesEnabled())
+                        mapOf(
+                            Swipe.Down to TestScenes.SceneA,
+                            Swipe(SwipeDirection.Down, pointerCount = 2) to TestScenes.SceneB,
+                            Swipe(SwipeDirection.Right, fromSource = Edge.Left) to
+                                TestScenes.SceneB,
+                            Swipe(SwipeDirection.Down, fromSource = Edge.Top) to TestScenes.SceneB,
+                        )
+                    else emptyMap(),
             ) {
                 Box(Modifier.fillMaxSize())
             }
@@ -349,4 +363,133 @@
         assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
         assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
     }
+
+    @Test
+    fun swipeDistance() {
+        // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
+        // detected as a drag event.
+        var touchSlop = 0f
+
+        val layoutState = layoutState()
+        val verticalSwipeDistance = 50.dp
+        assertThat(verticalSwipeDistance).isNotEqualTo(LayoutHeight)
+
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+
+            SceneTransitionLayout(
+                state = layoutState,
+                modifier = Modifier.size(LayoutWidth, LayoutHeight)
+            ) {
+                scene(
+                    TestScenes.SceneA,
+                    userActions =
+                        mapOf(Swipe.Down to TestScenes.SceneB withDistance verticalSwipeDistance),
+                ) {
+                    Spacer(Modifier.fillMaxSize())
+                }
+                scene(TestScenes.SceneB) { Spacer(Modifier.fillMaxSize()) }
+            }
+        }
+
+        assertThat(layoutState.currentTransition).isNull()
+
+        // Swipe by half of verticalSwipeDistance.
+        rule.onRoot().performTouchInput {
+            down(middleTop)
+            moveBy(Offset(0f, touchSlop + (verticalSwipeDistance / 2).toPx()), delayMillis = 1_000)
+        }
+
+        // We should be at 50%
+        val transition = layoutState.currentTransition
+        assertThat(transition).isNotNull()
+        assertThat(transition!!.progress).isEqualTo(0.5f)
+    }
+
+    @Test
+    fun swipeByTouchSlop() {
+        val layoutState = layoutState()
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            TestContent(layoutState)
+        }
+
+        // Swipe down by exactly touchSlop, so that the drag overSlop is 0f.
+        rule.onRoot().performTouchInput {
+            down(middle)
+            moveBy(Offset(0f, touchSlop), delayMillis = 1_000)
+        }
+
+        // We should still correctly compute that we are swiping down to scene C.
+        var transition = layoutState.currentTransition
+        assertThat(transition).isNotNull()
+        assertThat(transition?.toScene).isEqualTo(TestScenes.SceneC)
+
+        // Release the finger, animating back to scene A.
+        rule.onRoot().performTouchInput { up() }
+        rule.waitForIdle()
+        assertThat(layoutState.currentTransition).isNull()
+        assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+
+        // Swipe up by exactly touchSlop, so that the drag overSlop is 0f.
+        rule.onRoot().performTouchInput {
+            down(middle)
+            moveBy(Offset(0f, -touchSlop), delayMillis = 1_000)
+        }
+
+        // We should still correctly compute that we are swiping up to scene B.
+        transition = layoutState.currentTransition
+        assertThat(transition).isNotNull()
+        assertThat(transition?.toScene).isEqualTo(TestScenes.SceneB)
+
+        // Release the finger, animating back to scene A.
+        rule.onRoot().performTouchInput { up() }
+        rule.waitForIdle()
+        assertThat(layoutState.currentTransition).isNull()
+        assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+
+        // Swipe left by exactly touchSlop, so that the drag overSlop is 0f.
+        rule.onRoot().performTouchInput {
+            down(middle)
+            moveBy(Offset(-touchSlop, 0f), delayMillis = 1_000)
+        }
+
+        // We should still correctly compute that we are swiping down to scene B.
+        transition = layoutState.currentTransition
+        assertThat(transition).isNotNull()
+        assertThat(transition?.toScene).isEqualTo(TestScenes.SceneB)
+    }
+
+    @Test
+    fun swipeEnabledLater() {
+        val layoutState = MutableSceneTransitionLayoutState(TestScenes.SceneA)
+        var swipesEnabled by mutableStateOf(false)
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            TestContent(layoutState, swipesEnabled = { swipesEnabled })
+        }
+
+        // Drag down from the middle. This should not do anything, because swipes are disabled.
+        rule.onRoot().performTouchInput {
+            down(middle)
+            moveBy(Offset(0f, touchSlop), delayMillis = 1_000)
+        }
+        assertThat(layoutState.currentTransition).isNull()
+
+        // Release finger.
+        rule.onRoot().performTouchInput { up() }
+
+        // Enable swipes.
+        swipesEnabled = true
+        rule.waitForIdle()
+
+        // Drag down from the middle. Now it should start a transition.
+        rule.onRoot().performTouchInput {
+            down(middle)
+            moveBy(Offset(0f, touchSlop), delayMillis = 1_000)
+        }
+        assertThat(layoutState.currentTransition).isNotNull()
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index ef72992..140baca 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.animation.core.SpringSpec
 import androidx.compose.animation.core.TweenSpec
+import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.compose.animation.scene.transformation.Transformation
@@ -188,6 +189,40 @@
             )
     }
 
+    @Test
+    fun springSpec() {
+        val defaultSpec = spring<Float>(stiffness = 1f)
+        val specFromAToC = spring<Float>(stiffness = 2f)
+        val transitions = transitions {
+            defaultSwipeSpec = defaultSpec
+
+            from(TestScenes.SceneA, to = TestScenes.SceneB) {
+                // Default swipe spec.
+            }
+            from(TestScenes.SceneA, to = TestScenes.SceneC) { swipeSpec = specFromAToC }
+        }
+
+        assertThat(transitions.defaultSwipeSpec).isSameInstanceAs(defaultSpec)
+
+        // A => B does not have a custom spec.
+        assertThat(
+                transitions
+                    .transitionSpec(from = TestScenes.SceneA, to = TestScenes.SceneB)
+                    .transformationSpec()
+                    .swipeSpec
+            )
+            .isNull()
+
+        // A => C has a custom swipe spec.
+        assertThat(
+                transitions
+                    .transitionSpec(from = TestScenes.SceneA, to = TestScenes.SceneC)
+                    .transformationSpec()
+                    .swipeSpec
+            )
+            .isSameInstanceAs(specFromAToC)
+    }
+
     companion object {
         private val TRANSFORMATION_RANGE =
             Correspondence.transforming<Transformation, TransformationRange?>(
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 e050604..34c4dfb 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
@@ -33,6 +33,7 @@
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.withContext
@@ -518,6 +519,7 @@
                 awaitClose { context.contentResolver.unregisterContentObserver(observer) }
             }
             .onStart { emit(Unit) }
+            .flowOn(backgroundDispatcher)
     }
 
     private fun String.toIntent(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 030d41d..c82688c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -203,11 +203,17 @@
         whenever(deviceProvisionedController.isUserSetup(anyInt())).thenReturn(true)
 
         featureFlags = FakeFeatureFlags()
-        featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
         featureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
         featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)
 
-        mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES)
+        mSetFlagsRule.enableFlags(
+            AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES,
+        )
+        mSetFlagsRule.disableFlags(
+            FLAG_SIDEFPS_CONTROLLER_REFACTOR,
+            AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR
+        )
+
         keyguardPasswordViewController =
             KeyguardPasswordViewController(
                 keyguardPasswordView,
@@ -238,7 +244,6 @@
         sceneInteractor.setTransitionState(sceneTransitionStateFlow)
         deviceEntryInteractor = kosmos.deviceEntryInteractor
 
-        mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
         underTest =
             KeyguardSecurityContainerController(
                 view,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index c6d612d..c193d14 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -208,45 +208,13 @@
         }
 
     @Test
-    fun onImeVisibilityChanged_false_doesNothing() =
+    fun onImeDismissed() =
         testScope.runTest {
             val events by collectValues(bouncerInteractor.onImeHiddenByUser)
             assertThat(events).isEmpty()
 
-            underTest.onImeVisibilityChanged(isVisible = false)
-            assertThat(events).isEmpty()
-        }
-
-    @Test
-    fun onImeVisibilityChanged_falseAfterTrue_emitsOnImeHiddenByUserEvent() =
-        testScope.runTest {
-            val events by collectValues(bouncerInteractor.onImeHiddenByUser)
-            assertThat(events).isEmpty()
-
-            underTest.onImeVisibilityChanged(isVisible = true)
-            assertThat(events).isEmpty()
-
-            underTest.onImeVisibilityChanged(isVisible = false)
+            underTest.onImeDismissed()
             assertThat(events).hasSize(1)
-
-            underTest.onImeVisibilityChanged(isVisible = true)
-            assertThat(events).hasSize(1)
-
-            underTest.onImeVisibilityChanged(isVisible = false)
-            assertThat(events).hasSize(2)
-        }
-
-    @Test
-    fun onImeVisibilityChanged_falseAfterTrue_whileLockedOut_doesNothing() =
-        testScope.runTest {
-            val events by collectValues(bouncerInteractor.onImeHiddenByUser)
-            assertThat(events).isEmpty()
-            underTest.onImeVisibilityChanged(isVisible = true)
-            setLockout(true)
-
-            underTest.onImeVisibilityChanged(isVisible = false)
-
-            assertThat(events).isEmpty()
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
new file mode 100644
index 0000000..a8fe16b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dock.DockManager
+import com.android.systemui.dock.dockManager
+import com.android.systemui.dock.fakeDockManager
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalSceneStartableTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private lateinit var underTest: CommunalSceneStartable
+
+    @Before
+    fun setUp() =
+        with(kosmos) {
+            underTest =
+                CommunalSceneStartable(
+                        dockManager = dockManager,
+                        communalInteractor = communalInteractor,
+                        keyguardTransitionInteractor = keyguardTransitionInteractor,
+                        applicationScope = applicationCoroutineScope,
+                        bgScope = applicationCoroutineScope,
+                    )
+                    .apply { start() }
+        }
+
+    @Test
+    fun keyguardGoesAway_forceBlankScene() =
+        with(kosmos) {
+            testScope.runTest {
+                val scene by collectLastValue(communalInteractor.desiredScene)
+
+                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.PRIMARY_BOUNCER,
+                    to = KeyguardState.GONE,
+                    testScope = this
+                )
+
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+            }
+        }
+
+    @Test
+    fun deviceDreaming_forceBlankScene() =
+        with(kosmos) {
+            testScope.runTest {
+                val scene by collectLastValue(communalInteractor.desiredScene)
+
+                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GLANCEABLE_HUB,
+                    to = KeyguardState.DREAMING,
+                    testScope = this
+                )
+
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+            }
+        }
+
+    @Test
+    fun deviceDocked_forceCommunalScene() =
+        with(kosmos) {
+            testScope.runTest {
+                val scene by collectLastValue(communalInteractor.desiredScene)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+
+                updateDocked(true)
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.LOCKSCREEN,
+                    testScope = this
+                )
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GLANCEABLE_HUB,
+                    to = KeyguardState.DREAMING,
+                    testScope = this
+                )
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+            }
+        }
+
+    @Test
+    fun deviceDocked_doesNotForceCommunalIfTransitioningFromCommunal() =
+        with(kosmos) {
+            testScope.runTest {
+                val scene by collectLastValue(communalInteractor.desiredScene)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+
+                updateDocked(true)
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GLANCEABLE_HUB,
+                    to = KeyguardState.LOCKSCREEN,
+                    testScope = this
+                )
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+            }
+        }
+
+    @Test
+    fun deviceAsleep_forceBlankSceneAfterTimeout() =
+        with(kosmos) {
+            testScope.runTest {
+                val scene by collectLastValue(communalInteractor.desiredScene)
+                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GLANCEABLE_HUB,
+                    to = KeyguardState.OFF,
+                    testScope = this
+                )
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+
+                advanceTimeBy(CommunalSceneStartable.AWAKE_DEBOUNCE_DELAY)
+
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+            }
+        }
+
+    @Test
+    fun deviceAsleep_wakesUpBeforeTimeout_noChangeInScene() =
+        with(kosmos) {
+            testScope.runTest {
+                val scene by collectLastValue(communalInteractor.desiredScene)
+                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GLANCEABLE_HUB,
+                    to = KeyguardState.OFF,
+                    testScope = this
+                )
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                advanceTimeBy(CommunalSceneStartable.AWAKE_DEBOUNCE_DELAY / 2)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.OFF,
+                    to = KeyguardState.GLANCEABLE_HUB,
+                    testScope = this
+                )
+
+                advanceTimeBy(CommunalSceneStartable.AWAKE_DEBOUNCE_DELAY)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+            }
+        }
+
+    @Test
+    fun dockingOnLockscreen_forcesCommunal() =
+        with(kosmos) {
+            testScope.runTest {
+                communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+                val scene by collectLastValue(communalInteractor.desiredScene)
+
+                // device is docked while on the lockscreen
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GLANCEABLE_HUB,
+                    to = KeyguardState.LOCKSCREEN,
+                    testScope = this
+                )
+                updateDocked(true)
+
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                advanceTimeBy(CommunalSceneStartable.DOCK_DEBOUNCE_DELAY)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+            }
+        }
+
+    @Test
+    fun dockingOnLockscreen_doesNotForceCommunalIfDreamStarts() =
+        with(kosmos) {
+            testScope.runTest {
+                communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+                val scene by collectLastValue(communalInteractor.desiredScene)
+
+                // device is docked while on the lockscreen
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GLANCEABLE_HUB,
+                    to = KeyguardState.LOCKSCREEN,
+                    testScope = this
+                )
+                updateDocked(true)
+
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                advanceTimeBy(CommunalSceneStartable.DOCK_DEBOUNCE_DELAY / 2)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+
+                // dream starts shortly after docking
+                fakeKeyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.DREAMING,
+                    testScope = this
+                )
+                advanceTimeBy(CommunalSceneStartable.DOCK_DEBOUNCE_DELAY)
+                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+            }
+        }
+
+    private fun TestScope.updateDocked(docked: Boolean) =
+        with(kosmos) {
+            runCurrent()
+            fakeDockManager.setIsDocked(docked)
+            fakeDockManager.setDockEvent(DockManager.STATE_DOCKED)
+            runCurrent()
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
index bb3429e..c979ca6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
@@ -30,7 +30,6 @@
 import com.android.systemui.communal.shared.CommunalWidgetHost
 import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
-import com.android.systemui.communal.widgets.WidgetConfigurator
 import com.android.systemui.communal.widgets.widgetConfiguratorFail
 import com.android.systemui.communal.widgets.widgetConfiguratorSuccess
 import com.android.systemui.coroutines.collectLastValue
@@ -45,8 +44,7 @@
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -62,24 +60,17 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
-    @Mock private lateinit var appWidgetManagerOptional: Optional<AppWidgetManager>
-
     @Mock private lateinit var appWidgetManager: AppWidgetManager
-
     @Mock private lateinit var appWidgetHost: CommunalAppWidgetHost
-
     @Mock private lateinit var stopwatchProviderInfo: AppWidgetProviderInfo
-
     @Mock private lateinit var providerInfoA: AppWidgetProviderInfo
-
     @Mock private lateinit var communalWidgetHost: CommunalWidgetHost
-
     @Mock private lateinit var communalWidgetDao: CommunalWidgetDao
 
     private lateinit var logBuffer: LogBuffer
+    private lateinit var fakeWidgets: MutableStateFlow<Map<CommunalItemRank, CommunalWidgetItem>>
 
     private val kosmos = testKosmos()
-    private val testDispatcher = kosmos.testDispatcher
     private val testScope = kosmos.testScope
 
     private val fakeAllowlist =
@@ -94,7 +85,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-
+        fakeWidgets = MutableStateFlow(emptyMap())
         logBuffer = logcatLogBuffer(name = "CommunalWidgetRepoImplTest")
 
         setAppWidgetIds(emptyList())
@@ -102,13 +93,11 @@
         overrideResource(R.array.config_communalWidgetAllowlist, fakeAllowlist.toTypedArray())
 
         whenever(stopwatchProviderInfo.loadLabel(any())).thenReturn("Stopwatch")
-        whenever(communalWidgetDao.getWidgets()).thenReturn(flowOf(emptyMap()))
-        whenever(appWidgetManagerOptional.isPresent).thenReturn(true)
-        whenever(appWidgetManagerOptional.get()).thenReturn(appWidgetManager)
+        whenever(communalWidgetDao.getWidgets()).thenReturn(fakeWidgets)
 
         underTest =
             CommunalWidgetRepositoryImpl(
-                appWidgetManagerOptional,
+                Optional.of(appWidgetManager),
                 appWidgetHost,
                 testScope.backgroundScope,
                 kosmos.testDispatcher,
@@ -119,30 +108,16 @@
     }
 
     @Test
-    fun neverQueryDbForWidgets_whenHostIsInactive() =
+    fun communalWidgets_queryWidgetsFromDb() =
         testScope.runTest {
-            underTest.updateAppWidgetHostActive(false)
-            underTest.communalWidgets.launchIn(testScope.backgroundScope)
-            runCurrent()
-
-            verify(communalWidgetDao, never()).getWidgets()
-        }
-
-    @Test
-    fun communalWidgets_whenHostIsActive_queryWidgetsFromDb() =
-        testScope.runTest {
-            underTest.updateAppWidgetHostActive(true)
-
             val communalItemRankEntry = CommunalItemRank(uid = 1L, rank = 1)
             val communalWidgetItemEntry = CommunalWidgetItem(uid = 1L, 1, "pk_name/cls_name", 1L)
-            whenever(communalWidgetDao.getWidgets())
-                .thenReturn(flowOf(mapOf(communalItemRankEntry to communalWidgetItemEntry)))
+            fakeWidgets.value = mapOf(communalItemRankEntry to communalWidgetItemEntry)
             whenever(appWidgetManager.getAppWidgetInfo(anyInt())).thenReturn(providerInfoA)
 
             installedProviders(listOf(stopwatchProviderInfo))
 
             val communalWidgets by collectLastValue(underTest.communalWidgets)
-            runCurrent()
             verify(communalWidgetDao).getWidgets()
             assertThat(communalWidgets)
                 .containsExactly(
@@ -157,8 +132,6 @@
     @Test
     fun addWidget_allocateId_bindWidget_andAddToDb() =
         testScope.runTest {
-            underTest.updateAppWidgetHostActive(true)
-
             val provider = ComponentName("pkg_name", "cls_name")
             val id = 1
             val priority = 1
@@ -176,8 +149,6 @@
     @Test
     fun addWidget_configurationFails_doNotAddWidgetToDb() =
         testScope.runTest {
-            underTest.updateAppWidgetHostActive(true)
-
             val provider = ComponentName("pkg_name", "cls_name")
             val id = 1
             val priority = 1
@@ -195,23 +166,13 @@
     @Test
     fun addWidget_configurationThrowsError_doNotAddWidgetToDb() =
         testScope.runTest {
-            underTest.updateAppWidgetHostActive(true)
-
             val provider = ComponentName("pkg_name", "cls_name")
             val id = 1
             val priority = 1
             whenever(communalWidgetHost.getAppWidgetInfo(id))
                 .thenReturn(PROVIDER_INFO_REQUIRES_CONFIGURATION)
             whenever(communalWidgetHost.allocateIdAndBindWidget(provider)).thenReturn(id)
-            underTest.addWidget(
-                provider,
-                priority,
-                object : WidgetConfigurator {
-                    override suspend fun configureWidget(appWidgetId: Int): Boolean {
-                        throw IllegalStateException("some error")
-                    }
-                }
-            )
+            underTest.addWidget(provider, priority) { throw IllegalStateException("some error") }
             runCurrent()
 
             verify(communalWidgetHost).allocateIdAndBindWidget(provider)
@@ -222,8 +183,6 @@
     @Test
     fun addWidget_configurationNotRequired_doesNotConfigure_addWidgetToDb() =
         testScope.runTest {
-            underTest.updateAppWidgetHostActive(true)
-
             val provider = ComponentName("pkg_name", "cls_name")
             val id = 1
             val priority = 1
@@ -241,8 +200,6 @@
     @Test
     fun deleteWidget_removeWidgetId_andDeleteFromDb() =
         testScope.runTest {
-            underTest.updateAppWidgetHostActive(true)
-
             val id = 1
             underTest.deleteWidget(id)
             runCurrent()
@@ -254,8 +211,6 @@
     @Test
     fun reorderWidgets_queryDb() =
         testScope.runTest {
-            underTest.updateAppWidgetHostActive(true)
-
             val widgetIdToPriorityMap = mapOf(104 to 1, 103 to 2, 101 to 3)
             underTest.updateWidgetOrder(widgetIdToPriorityMap)
             runCurrent()
@@ -263,28 +218,6 @@
             verify(communalWidgetDao).updateWidgetOrder(widgetIdToPriorityMap)
         }
 
-    @Test
-    fun appWidgetHost_startListening() =
-        testScope.runTest {
-            verify(appWidgetHost, never()).startListening()
-
-            underTest.updateAppWidgetHostActive(true)
-
-            verify(appWidgetHost).startListening()
-        }
-
-    @Test
-    fun appWidgetHost_stopListening() =
-        testScope.runTest {
-            underTest.updateAppWidgetHostActive(true)
-
-            verify(appWidgetHost).startListening()
-
-            underTest.updateAppWidgetHostActive(false)
-
-            verify(appWidgetHost).stopListening()
-        }
-
     private fun installedProviders(providers: List<AppWidgetProviderInfo>) {
         whenever(appWidgetManager.installedProviders).thenReturn(providers)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt
index e821673..6a3fc2a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorCommunalDisabledTest.kt
@@ -80,15 +80,4 @@
 
             assertThat(isCommunalAvailable).isFalse()
         }
-
-    @Test
-    fun updateAppWidgetHostActive_whenStorageUnlock_false() =
-        testScope.runTest {
-            assertThat(widgetRepository.isHostActive()).isFalse()
-
-            keyguardRepository.setIsEncryptedOrLockdown(false)
-            runCurrent()
-
-            assertThat(widgetRepository.isHostActive()).isFalse()
-        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 1b7117f..ee01bf9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -125,7 +125,7 @@
             keyguardRepository.setIsEncryptedOrLockdown(false)
             userRepository.setSelectedUserInfo(mainUser)
             keyguardRepository.setKeyguardShowing(true)
-            runCurrent()
+            communalRepository.setCommunalEnabledState(true)
 
             assertThat(isAvailable).isTrue()
         }
@@ -138,7 +138,8 @@
 
             keyguardRepository.setIsEncryptedOrLockdown(true)
             userRepository.setSelectedUserInfo(mainUser)
-            runCurrent()
+            keyguardRepository.setKeyguardShowing(true)
+            communalRepository.setCommunalEnabledState(true)
 
             assertThat(isAvailable).isFalse()
         }
@@ -152,7 +153,7 @@
             keyguardRepository.setIsEncryptedOrLockdown(false)
             userRepository.setSelectedUserInfo(secondaryUser)
             keyguardRepository.setKeyguardShowing(true)
-            runCurrent()
+            communalRepository.setCommunalEnabledState(true)
 
             assertThat(isAvailable).isFalse()
         }
@@ -166,23 +167,23 @@
             keyguardRepository.setIsEncryptedOrLockdown(false)
             userRepository.setSelectedUserInfo(mainUser)
             keyguardRepository.setDreaming(true)
-            runCurrent()
+            communalRepository.setCommunalEnabledState(true)
 
             assertThat(isAvailable).isTrue()
         }
 
     @Test
-    fun updateAppWidgetHostActive_uponStorageUnlockAsMainUser_true() =
+    fun isCommunalAvailable_communalDisabled_false() =
         testScope.runTest {
-            collectLastValue(underTest.isCommunalAvailable)
-            assertThat(widgetRepository.isHostActive()).isFalse()
+            val isAvailable by collectLastValue(underTest.isCommunalAvailable)
+            assertThat(isAvailable).isFalse()
 
             keyguardRepository.setIsEncryptedOrLockdown(false)
             userRepository.setSelectedUserInfo(mainUser)
             keyguardRepository.setKeyguardShowing(true)
-            runCurrent()
+            communalRepository.setCommunalEnabledState(false)
 
-            assertThat(widgetRepository.isHostActive()).isTrue()
+            assertThat(isAvailable).isFalse()
         }
 
     @Test
@@ -647,6 +648,14 @@
             verify(editWidgetsActivityStarter).startActivity()
         }
 
+    @Test
+    fun showWidgetEditor_withPreselectedKey_startsActivity() =
+        testScope.runTest {
+            val widgetKey = CommunalContentModel.KEY.widget(123)
+            underTest.showWidgetEditor(preselectedKey = widgetKey)
+            verify(editWidgetsActivityStarter).startActivity(widgetKey)
+        }
+
     private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget {
         val timer = mock(SmartspaceTarget::class.java)
         whenever(timer.smartspaceTargetId).thenReturn(id)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
index 352463f..6c87e0f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
@@ -34,20 +34,15 @@
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.user.data.repository.fakeUserRepository
-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.Mock
-import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class CommunalTutorialInteractorTest : SysuiTestCase() {
-    @Mock lateinit var user: UserInfo
-
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
 
@@ -60,14 +55,14 @@
 
     @Before
     fun setUp() {
-        MockitoAnnotations.initMocks(this)
-
         keyguardRepository = kosmos.fakeKeyguardRepository
         communalTutorialRepository = kosmos.fakeCommunalTutorialRepository
         communalRepository = kosmos.fakeCommunalRepository
         communalInteractor = kosmos.communalInteractor
         userRepository = kosmos.fakeUserRepository
 
+        userRepository.setUserInfos(listOf(MAIN_USER_INFO))
+
         underTest = kosmos.communalTutorialInteractor
     }
 
@@ -204,12 +199,17 @@
     private suspend fun setCommunalAvailable(available: Boolean) {
         if (available) {
             communalRepository.setIsCommunalEnabled(true)
+            communalRepository.setCommunalEnabledState(true)
             keyguardRepository.setIsEncryptedOrLockdown(false)
-            whenever(user.isMain).thenReturn(true)
-            userRepository.setUserInfos(listOf(user))
-            userRepository.setSelectedUserInfo(user)
+            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
+            keyguardRepository.setKeyguardShowing(true)
         } else {
-            keyguardRepository.setIsEncryptedOrLockdown(true)
+            communalRepository.setIsCommunalEnabled(false)
+            communalRepository.setCommunalEnabledState(false)
         }
     }
+
+    private companion object {
+        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+    }
 }
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 a2dec5f..273d1cd 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
@@ -129,6 +129,19 @@
         }
 
     @Test
+    fun selectedKey_onReorderWidgets_isCleared() =
+        testScope.runTest {
+            val selectedKey by collectLastValue(underTest.selectedKey)
+
+            val key = CommunalContentModel.KEY.widget(123)
+            underTest.setSelectedKey(key)
+            assertThat(selectedKey).isEqualTo(key)
+
+            underTest.onReorderWidgetStart()
+            assertThat(selectedKey).isNull()
+        }
+
+    @Test
     fun reorderWidget_uiEventLogging_start() {
         underTest.onReorderWidgetStart()
         verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index c814f3f..0723e83 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
 import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
 import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
+import com.android.systemui.communal.data.repository.fakeCommunalRepository
 import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
 import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
 import com.android.systemui.communal.domain.interactor.communalInteractor
@@ -90,6 +91,8 @@
         mediaRepository = kosmos.fakeCommunalMediaRepository
         userRepository = kosmos.fakeUserRepository
 
+        kosmos.fakeCommunalRepository.setCommunalEnabledState(true)
+
         underTest =
             CommunalViewModel(
                 testScope,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
new file mode 100644
index 0000000..a3654b6
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
@@ -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.systemui.communal.widgets
+
+import android.content.pm.UserInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.fakeCommunalRepository
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+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
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    @Mock private lateinit var appWidgetHost: CommunalAppWidgetHost
+
+    private lateinit var underTest: CommunalAppWidgetHostStartable
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        kosmos.fakeUserRepository.setUserInfos(listOf(MAIN_USER_INFO))
+
+        underTest =
+            CommunalAppWidgetHostStartable(
+                appWidgetHost,
+                kosmos.communalInteractor,
+                kosmos.applicationCoroutineScope,
+                kosmos.testDispatcher,
+            )
+    }
+
+    @Test
+    fun editModeShowingStartsAppWidgetHost() =
+        with(kosmos) {
+            testScope.runTest {
+                setCommunalAvailable(false)
+                communalInteractor.setEditModeOpen(true)
+                verify(appWidgetHost, never()).startListening()
+
+                underTest.start()
+                runCurrent()
+
+                verify(appWidgetHost).startListening()
+                verify(appWidgetHost, never()).stopListening()
+
+                communalInteractor.setEditModeOpen(false)
+                runCurrent()
+
+                verify(appWidgetHost).stopListening()
+            }
+        }
+
+    @Test
+    fun communalShowingStartsAppWidgetHost() =
+        with(kosmos) {
+            testScope.runTest {
+                setCommunalAvailable(true)
+                communalInteractor.setEditModeOpen(false)
+                verify(appWidgetHost, never()).startListening()
+
+                underTest.start()
+                runCurrent()
+
+                verify(appWidgetHost).startListening()
+                verify(appWidgetHost, never()).stopListening()
+
+                setCommunalAvailable(false)
+                runCurrent()
+
+                verify(appWidgetHost).stopListening()
+            }
+        }
+
+    @Test
+    fun communalAndEditModeNotShowingNeverStartListening() =
+        with(kosmos) {
+            testScope.runTest {
+                setCommunalAvailable(false)
+                communalInteractor.setEditModeOpen(false)
+
+                underTest.start()
+                runCurrent()
+
+                verify(appWidgetHost, never()).startListening()
+                verify(appWidgetHost, never()).stopListening()
+            }
+        }
+
+    private suspend fun setCommunalAvailable(available: Boolean) =
+        with(kosmos) {
+            fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
+            fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO)
+            fakeKeyguardRepository.setKeyguardShowing(true)
+            fakeCommunalRepository.setCommunalEnabledState(available)
+        }
+
+    private companion object {
+        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 6a14220..6808f5d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -38,6 +38,7 @@
 import com.android.internal.logging.InstanceId.fakeInstanceId
 import com.android.internal.logging.UiEventLogger
 import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.Flags as AConfigFlags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
@@ -62,7 +63,6 @@
 import com.android.systemui.display.data.repository.display
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags.KEYGUARD_WM_STATE_REFACTOR
 import com.android.systemui.keyguard.data.repository.BiometricType
 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
@@ -194,7 +194,7 @@
         biometricSettingsRepository = FakeBiometricSettingsRepository()
         deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
         trustRepository = FakeTrustRepository()
-        featureFlags = FakeFeatureFlags().apply { set(KEYGUARD_WM_STATE_REFACTOR, false) }
+        featureFlags = FakeFeatureFlags()
 
         powerRepository = FakePowerRepository()
         powerInteractor =
@@ -252,6 +252,10 @@
             .thenReturn(listOf(createFaceSensorProperties(supportsFaceDetection = true)))
         whenever(bypassController.bypassEnabled).thenReturn(true)
         underTest = createDeviceEntryFaceAuthRepositoryImpl(faceManager, bypassController)
+
+        mSetFlagsRule.disableFlags(
+            AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
+        )
     }
 
     private fun createDeviceEntryFaceAuthRepositoryImpl(
@@ -301,7 +305,6 @@
             faceAuthBuffer,
             keyguardTransitionInteractor,
             displayStateInteractor,
-            featureFlags,
             dumpManager,
         )
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorTest.kt
new file mode 100644
index 0000000..88ad3f3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorTest.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.systemui.deviceentry.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.kosmos.testScope
+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.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AuthRippleInteractorTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val deviceEntrySourceInteractor = kosmos.deviceEntrySourceInteractor
+    private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+    private val keyguardRepository = kosmos.fakeKeyguardRepository
+    private val underTest = kosmos.authRippleInteractor
+
+    @Test
+    fun enteringDeviceFromDeviceEntryIcon_udfpsNotSupported_doesNotShowAuthRipple() =
+        testScope.runTest {
+            val showUnlockRipple by collectLastValue(underTest.showUnlockRipple)
+            fingerprintPropertyRepository.supportsRearFps()
+            keyguardRepository.setKeyguardDismissible(true)
+            runCurrent()
+            deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon()
+            assertThat(showUnlockRipple).isNull()
+        }
+
+    @Test
+    fun enteringDeviceFromDeviceEntryIcon_udfpsSupported_showsAuthRipple() =
+        testScope.runTest {
+            val showUnlockRipple by collectLastValue(underTest.showUnlockRipple)
+            fingerprintPropertyRepository.supportsUdfps()
+            keyguardRepository.setKeyguardDismissible(true)
+            runCurrent()
+            deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon()
+            assertThat(showUnlockRipple).isEqualTo(BiometricUnlockSource.FINGERPRINT_SENSOR)
+        }
+
+    @Test
+    fun faceUnlocked_showsAuthRipple() =
+        testScope.runTest {
+            val showUnlockRipple by collectLastValue(underTest.showUnlockRipple)
+            keyguardRepository.setBiometricUnlockSource(BiometricUnlockSource.FACE_SENSOR)
+            keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+            assertThat(showUnlockRipple).isEqualTo(BiometricUnlockSource.FACE_SENSOR)
+        }
+
+    @Test
+    fun fingerprintUnlocked_showsAuthRipple() =
+        testScope.runTest {
+            val showUnlockRippleFromBiometricUnlock by collectLastValue(underTest.showUnlockRipple)
+            keyguardRepository.setBiometricUnlockSource(BiometricUnlockSource.FINGERPRINT_SENSOR)
+            keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+            assertThat(showUnlockRippleFromBiometricUnlock)
+                .isEqualTo(BiometricUnlockSource.FINGERPRINT_SENSOR)
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorTest.kt
new file mode 100644
index 0000000..d216fa0
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.deviceentry.domain.interactor
+
+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.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.kosmos.testScope
+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.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntrySourceInteractorTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val keyguardRepository = kosmos.fakeKeyguardRepository
+    private val underTest = kosmos.deviceEntrySourceInteractor
+
+    @Test
+    fun deviceEntryFromFaceUnlock() =
+        testScope.runTest {
+            val deviceEntryFromBiometricAuthentication by
+                collectLastValue(underTest.deviceEntryFromBiometricSource)
+            keyguardRepository.setBiometricUnlockSource(BiometricUnlockSource.FACE_SENSOR)
+            keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+            runCurrent()
+            assertThat(deviceEntryFromBiometricAuthentication)
+                .isEqualTo(BiometricUnlockSource.FACE_SENSOR)
+        }
+
+    @Test
+    fun deviceEntryFromFingerprintUnlock() = runTest {
+        val deviceEntryFromBiometricAuthentication by
+            collectLastValue(underTest.deviceEntryFromBiometricSource)
+        keyguardRepository.setBiometricUnlockSource(BiometricUnlockSource.FINGERPRINT_SENSOR)
+        keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+        runCurrent()
+        assertThat(deviceEntryFromBiometricAuthentication)
+            .isEqualTo(BiometricUnlockSource.FINGERPRINT_SENSOR)
+    }
+
+    @Test
+    fun noDeviceEntry() = runTest {
+        val deviceEntryFromBiometricAuthentication by
+            collectLastValue(underTest.deviceEntryFromBiometricSource)
+        keyguardRepository.setBiometricUnlockSource(BiometricUnlockSource.FINGERPRINT_SENSOR)
+        // doesn't dismiss keyguard:
+        keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.ONLY_WAKE)
+        runCurrent()
+        assertThat(deviceEntryFromBiometricAuthentication).isNull()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/binder/LiftToRunFaceAuthBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/binder/LiftToRunFaceAuthBinderTest.kt
new file mode 100644
index 0000000..e9e85c9
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/binder/LiftToRunFaceAuthBinderTest.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.deviceentry.domain.ui.binder
+
+import android.content.packageManager
+import android.content.pm.PackageManager
+import android.hardware.Sensor
+import android.hardware.TriggerEventListener
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
+import com.android.systemui.deviceentry.ui.binder.liftToRunFaceAuthBinder
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.data.repository.fakePowerRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.sensors.asyncSensorManager
+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
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class LiftToRunFaceAuthBinderTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val sensorManager = kosmos.asyncSensorManager
+    private val powerRepository = kosmos.fakePowerRepository
+    private val keyguardRepository = kosmos.fakeKeyguardRepository
+    private val bouncerRepository = kosmos.keyguardBouncerRepository
+    private val biometricSettingsRepository = kosmos.biometricSettingsRepository
+    private val packageManager = kosmos.packageManager
+
+    @Captor private lateinit var triggerEventListenerCaptor: ArgumentCaptor<TriggerEventListener>
+    @Mock private lateinit var mockSensor: Sensor
+
+    private val underTest = kosmos.liftToRunFaceAuthBinder
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true)
+        whenever(sensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)).thenReturn(mockSensor)
+    }
+
+    @Test
+    fun doNotListenForGesture() =
+        testScope.runTest {
+            start()
+            verifyNeverRequestsTriggerSensor()
+        }
+
+    @Test
+    fun awakeKeyguard_listenForGesture() =
+        testScope.runTest {
+            start()
+            givenAwakeKeyguard(true)
+            runCurrent()
+            verifyRequestTriggerSensor()
+        }
+
+    @Test
+    fun faceNotEnrolled_listenForGesture() =
+        testScope.runTest {
+            start()
+            givenAwakeKeyguard(true)
+            biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+            runCurrent()
+            verifyNeverRequestsTriggerSensor()
+        }
+
+    @Test
+    fun notInteractive_doNotListenForGesture() =
+        testScope.runTest {
+            start()
+            givenAwakeKeyguard(true)
+            powerRepository.setInteractive(false)
+            runCurrent()
+            verifyNeverRequestsTriggerSensor()
+        }
+
+    @Test
+    fun primaryBouncer_listenForGesture() =
+        testScope.runTest {
+            start()
+            givenAwakeKeyguard(false)
+            givenPrimaryBouncerShowing()
+            runCurrent()
+            verifyRequestTriggerSensor()
+        }
+
+    @Test
+    fun alternateBouncer_listenForGesture() =
+        testScope.runTest {
+            start()
+            givenAwakeKeyguard(false)
+            givenAlternateBouncerShowing()
+            runCurrent()
+            verifyRequestTriggerSensor()
+        }
+
+    @Test
+    fun restartListeningForGestureAfterSensorTrigger() =
+        testScope.runTest {
+            start()
+            givenAwakeKeyguard(true)
+            runCurrent()
+            verifyRequestTriggerSensor()
+            clearInvocations(sensorManager)
+
+            triggerEventListenerCaptor.value.onTrigger(null)
+            runCurrent()
+            verifyRequestTriggerSensor()
+        }
+
+    @Test
+    fun cancelTriggerSensor_keyguardNotAwakeAnymore() =
+        testScope.runTest {
+            start()
+            givenAwakeKeyguard(true)
+            runCurrent()
+            verifyRequestTriggerSensor()
+
+            givenAwakeKeyguard(false)
+            runCurrent()
+            verifyCancelTriggerSensor()
+        }
+
+    private fun start() {
+        underTest.start()
+        biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+        givenAwakeKeyguard(false)
+        givenBouncerNotShowing()
+    }
+
+    private fun givenAwakeKeyguard(isAwake: Boolean) {
+        powerRepository.setInteractive(isAwake)
+        keyguardRepository.setKeyguardShowing(isAwake)
+        keyguardRepository.setKeyguardOccluded(false)
+    }
+
+    private fun givenPrimaryBouncerShowing() {
+        bouncerRepository.setPrimaryShow(true)
+        bouncerRepository.setAlternateVisible(false)
+    }
+
+    private fun givenBouncerNotShowing() {
+        bouncerRepository.setPrimaryShow(false)
+        bouncerRepository.setAlternateVisible(false)
+    }
+
+    private fun givenAlternateBouncerShowing() {
+        bouncerRepository.setPrimaryShow(false)
+        bouncerRepository.setAlternateVisible(true)
+    }
+
+    private fun verifyRequestTriggerSensor() {
+        verify(sensorManager).requestTriggerSensor(capture(triggerEventListenerCaptor), any())
+    }
+
+    private fun verifyNeverRequestsTriggerSensor() {
+        verify(sensorManager, never()).requestTriggerSensor(any(), any())
+    }
+
+    private fun verifyCancelTriggerSensor() {
+        verify(sensorManager).cancelTriggerSensor(any(), any())
+    }
+}
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFakeKosmos.kt
similarity index 71%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFakeKosmos.kt
index 692584d..06275fa 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFakeKosmos.kt
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package com.android.systemui.dock
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.dockManager: DockManager by Kosmos.Fixture { fakeDockManager }
+val Kosmos.fakeDockManager: DockManagerFake by Kosmos.Fixture { DockManagerFake() }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index dc8b97a..c01c79d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -238,10 +238,10 @@
         }
 
     @Test
-    fun isKeyguardUnlocked() =
+    fun isKeyguardDismissible() =
         testScope.runTest {
             whenever(keyguardStateController.isUnlocked).thenReturn(false)
-            val isKeyguardUnlocked by collectLastValue(underTest.isKeyguardUnlocked)
+            val isKeyguardUnlocked by collectLastValue(underTest.isKeyguardDismissible)
 
             runCurrent()
             assertThat(isKeyguardUnlocked).isFalse()
@@ -574,7 +574,7 @@
 
     @Test
     fun isEncryptedOrLockdown() =
-        testScope.runTest {
+        TestScope(mainDispatcher).runTest {
             whenever(userTracker.userId).thenReturn(0)
             whenever(keyguardUpdateMonitor.isEncryptedOrLockdown(0)).thenReturn(true)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 34f703b..db414b7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
 import com.android.systemui.dock.DockManager
 import com.android.systemui.dock.DockManagerFake
 import com.android.systemui.flags.FakeFeatureFlags
@@ -49,16 +50,17 @@
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.testKosmos
 import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.settings.FakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -82,6 +84,7 @@
     @Mock private lateinit var activityStarter: ActivityStarter
     @Mock private lateinit var launchAnimator: DialogLaunchAnimator
     @Mock private lateinit var devicePolicyManager: DevicePolicyManager
+    @Mock private lateinit var shadeInteractor: ShadeInteractor
     @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
 
     private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -95,8 +98,6 @@
     private lateinit var dockManager: DockManagerFake
     private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
 
-    private val kosmos = testKosmos()
-
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -183,7 +184,7 @@
         underTest =
             KeyguardQuickAffordanceInteractor(
                 keyguardInteractor = withDeps.keyguardInteractor,
-                shadeInteractor = kosmos.shadeInteractor,
+                shadeInteractor = shadeInteractor,
                 lockPatternUtils = lockPatternUtils,
                 keyguardStateController = keyguardStateController,
                 userTracker = userTracker,
@@ -198,6 +199,8 @@
                 backgroundDispatcher = testDispatcher,
                 appContext = context,
             )
+
+        whenever(shadeInteractor.anyExpansion).thenReturn(MutableStateFlow(0f))
     }
 
     @Test
@@ -344,6 +347,25 @@
         }
 
     @Test
+    fun quickAffordance_updateOncePerShadeExpansion() =
+        testScope.runTest {
+            val shadeExpansion = MutableStateFlow(0f)
+            whenever(shadeInteractor.anyExpansion).thenReturn(shadeExpansion)
+
+            val collectedValue by
+                collectValues(
+                    underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
+                )
+
+            val initialSize = collectedValue.size
+            for (i in 0..10) {
+                shadeExpansion.value = i / 10f
+            }
+
+            assertThat(collectedValue.size).isEqualTo(initialSize + 1)
+        }
+
+    @Test
     fun quickAffordanceAlwaysVisible_notVisible_restrictedByPolicyManager() =
         testScope.runTest {
             whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index 30ac344..6fc5be1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -19,7 +19,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -52,11 +52,9 @@
     val testScope = kosmos.testScope
 
     val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
-    val primaryBouncerInteractor = kosmos.primaryBouncerInteractor
+    val primaryBouncerInteractor = kosmos.mockPrimaryBouncerInteractor
     val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController
-    val underTest by lazy {
-        kosmos.primaryBouncerToGoneTransitionViewModel
-    }
+    val underTest by lazy { kosmos.primaryBouncerToGoneTransitionViewModel }
 
     @Before
     fun setUp() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
index d277fca..1545e74 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.data.repository
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class AutoAddSettingsRepositoryTest : SysuiTestCase() {
     private val secureSettings = FakeSettings()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
index 3db676d..ee7a97a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName
 import android.content.SharedPreferences
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -29,6 +30,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class CustomTileAddedSharedPreferencesRepositoryTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
index eb845b2..d9f24b3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
@@ -35,7 +35,6 @@
 import com.android.systemui.common.data.repository.packageChangeRepository
 import com.android.systemui.common.data.shared.model.PackageChangeModel
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
@@ -44,6 +43,8 @@
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 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
@@ -52,6 +53,7 @@
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
@@ -82,7 +84,7 @@
         underTest =
             InstalledTilesComponentRepositoryImpl(
                 context,
-                kosmos.testDispatcher,
+                testScope.backgroundScope,
                 kosmos.packageChangeRepository
             )
     }
@@ -103,6 +105,7 @@
                 .thenReturn(listOf(resolveInfo))
 
             val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+            runCurrent()
 
             assertThat(componentNames).containsExactly(TEST_COMPONENT)
         }
@@ -115,6 +118,8 @@
                 ResolveInfo(TEST_COMPONENT, hasPermission = true, defaultEnabled = true)
 
             val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+            runCurrent()
+
             assertThat(componentNames).isEmpty()
 
             whenever(
@@ -126,6 +131,7 @@
                 )
                 .thenReturn(listOf(resolveInfo))
             kosmos.fakePackageChangeRepository.notifyChange(PackageChangeModel.Empty)
+            runCurrent()
 
             assertThat(componentNames).containsExactly(TEST_COMPONENT)
         }
@@ -146,6 +152,8 @@
                 .thenReturn(listOf(resolveInfo))
 
             val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+            runCurrent()
+
             assertThat(componentNames).isEmpty()
         }
 
@@ -165,6 +173,8 @@
                 .thenReturn(listOf(resolveInfo))
 
             val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+            runCurrent()
+
             assertThat(componentNames).isEmpty()
         }
 
@@ -210,10 +220,31 @@
                 .thenReturn(listOf(resolveInfo))
 
             val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+            runCurrent()
 
             assertThat(componentNames).containsExactly(TEST_COMPONENT)
         }
 
+    @Test
+    fun loadComponentsForSameUserTwice_returnsSameFlow() =
+        testScope.runTest {
+            val flowForUser1 = underTest.getInstalledTilesComponents(1)
+            val flowForUser1TheSecondTime = underTest.getInstalledTilesComponents(1)
+            runCurrent()
+
+            assertThat(flowForUser1TheSecondTime).isEqualTo(flowForUser1)
+        }
+
+    @Test
+    fun loadComponentsForDifferentUsers_returnsDifferentFlow() =
+        testScope.runTest {
+            val flowForUser1 = underTest.getInstalledTilesComponents(1)
+            val flowForUser2 = underTest.getInstalledTilesComponents(2)
+            runCurrent()
+
+            assertThat(flowForUser2).isNotEqualTo(flowForUser1)
+        }
+
     companion object {
         private val INTENT = Intent(TileService.ACTION_QS_TILE)
         private val FLAGS =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
index f7c3b21..3418977 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.data.repository
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -39,6 +40,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class TileSpecSettingsRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
index 9516c21..9e99fc0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.qs.pipeline.data.repository
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -9,6 +10,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class TilesSettingConverterTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
index 36e860e..1ca3c06 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.qs.pipeline.data.repository
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -24,6 +25,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class UserAutoAddRepositoryTest : SysuiTestCase() {
     private val secureSettings = FakeSettings()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
index d4a9fab..58fc109 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.qs.pipeline.data.repository
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -23,6 +24,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
+@EnabledOnRavenwood
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class UserTileSpecRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
index 30d1822..57bb77f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.pipeline.data.restoreprocessors
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -31,6 +32,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class WorkTileRestoreProcessorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
index 4454a3c..f185ed5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
 import android.content.ComponentName
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
@@ -28,6 +29,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class AutoAddableSettingListTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
index d153e9d..cfb84a7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -35,6 +36,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class AutoAddableSettingTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
index ec139e4..ea8d873 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -35,6 +36,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class CallbackControllerAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
index 4fae532..9bb591e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -41,6 +42,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class CastAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
index 9e2d1f8..b925b27 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -40,6 +41,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class DataSaverAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
index 0116bd9..188c6a9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -43,6 +44,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class DeviceControlsAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
index e7ea9a6..02699dd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -40,6 +41,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class HotspotAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
index 19ac63c..6d6fd75 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -43,6 +44,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
index d645ee3..633e494 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName
 import android.content.pm.PackageManager
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
@@ -51,6 +52,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class SafetyCenterAutoAddableTest : SysuiTestCase() {
     private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
index 83ff35d..c5c76eb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.autoaddable
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -37,6 +38,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class WalletAutoAddableTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
index 54b03a9..2ea12ef 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.pipeline.domain.interactor
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -46,6 +47,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class AutoAddInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
index 0d97115..d38c19b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.qs.pipeline.domain.interactor
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -28,6 +29,7 @@
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
+@EnabledOnRavenwood
 class PanelInteractorImplTest : SysuiTestCase() {
 
     @Mock private lateinit var shadeController: ShadeController
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
index b2a9783..0b3144a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.qs.pipeline.domain.interactor
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -26,6 +27,7 @@
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
+@EnabledOnRavenwood
 class RestoreReconciliationInteractorTest : SysuiTestCase() {
 
     private val tileSpecRepository = FakeTileSpecRepository()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
index 558e769..869ab6c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.pipeline.shared
 
 import android.content.ComponentName
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -25,6 +26,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class TileSpecTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
index c104977..bf48784 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager.ResolveInfoFlags
 import android.content.pm.ResolveInfo
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -44,6 +45,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class QSTileIntentUserInputHandlerTest : SysuiTestCase() {
     @Mock private lateinit var packageManager: PackageManager
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
index 9861606..fd09e3c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tiles.base.analytics
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.InstanceId
@@ -33,6 +34,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class QSTileAnalyticsTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
index 2bdc154..a1f885c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
@@ -20,6 +20,7 @@
 import android.content.Context
 import android.content.Intent
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.RestrictedLockUtils
@@ -45,6 +46,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class DisabledByPolicyInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt
index 937744d..89b9b7f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.airplate.domain.interactor
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -36,6 +37,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class AirplaneModeTileDataInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
index 81bde81..8982d81 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tiles.impl.airplate.domain.interactor
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import android.telephony.TelephonyManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -37,6 +38,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class AirplaneModeTileUserActionInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
index 8c612ac..abaf808 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -35,6 +36,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class ColorCorrectionTileDataInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
index 3049cc0..3bc53b27 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -32,6 +33,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class ColorCorrectionTileUserActionInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt
index 7f7490d..a9e39354 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.flashlight.domain.interactor
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.testing.LeakCheck
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -37,6 +38,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class FlashlightTileDataInteractorTest : SysuiTestCase() {
     private lateinit var controller: FakeFlashlightController
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt
index 24c7bfb..75b07ee 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.inversion.domain.interactor
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -35,6 +36,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class ColorInversionTileDataInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
index 99bae18..f574f79 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.inversion.domain.interactor
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -32,6 +33,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class ColorInversionUserActionInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileDataInteractorTest.kt
index 8fdc93b..9adf57a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.location.interactor
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.testing.LeakCheck
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class LocationTileDataInteractorTest : SysuiTestCase() {
     private lateinit var controller: FakeLocationController
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileUserActionInteractorTest.kt
index 0fb8ae6..8b21cb4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileUserActionInteractorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tiles.impl.location.interactor
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -42,6 +43,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class LocationTileUserActionInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
index 4b96251..f24723a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.saver.domain
 
 import android.content.SharedPreferences
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.testing.LeakCheck
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -37,6 +38,7 @@
 
 /** Test [DataSaverDialogDelegate]. */
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class DataSaverDialogDelegateTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileDataInteractorTest.kt
index 819bd03..daee22d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.saver.domain.interactor
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.testing.LeakCheck
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -36,6 +37,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class DataSaverTileDataInteractorTest : SysuiTestCase() {
     private val controller: FakeDataSaverController = FakeDataSaverController(LeakCheck())
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt
index 004ec62..eea6d16 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.impl.uimodenight.domain
 
 import android.app.UiModeManager
+import android.platform.test.annotations.EnabledOnRavenwood
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -39,6 +40,7 @@
 import org.mockito.Mockito.verify
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class UiModeNightTileUserActionInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt
index 5eca8ca..40971a8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tiles.viewmodel
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -27,6 +28,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class QSTileConfigProviderTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
index 3a0ebdb..a8bc8d6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.viewmodel
 
 import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.android.systemui.SysuiTestCase
@@ -50,6 +51,7 @@
 import org.mockito.MockitoAnnotations
 
 @MediumTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class QSTileViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
index 22fb152..18cdd71 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tiles.viewmodel
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.android.settingslib.RestrictedLockUtils
@@ -53,6 +54,7 @@
 
 /** Tests all possible [QSTileUserAction]s. If you need */
 @MediumTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class QSTileViewModelUserInputTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
index 18a7320..d1bc686 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.ui.adapter
 
+import android.platform.test.annotations.EnabledOnRavenwood
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -25,6 +26,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
+@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class QSSceneAdapterTest : SysuiTestCase() {
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 1e5ebd0..504ded3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -52,6 +52,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.media.controls.pipeline.MediaDataManager
 import com.android.systemui.model.SysUiState
+import com.android.systemui.model.sceneContainerPlugin
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
 import com.android.systemui.power.domain.interactor.powerInteractor
@@ -244,7 +245,7 @@
         kosmos.fakeDeviceEntryRepository.setUnlocked(false)
 
         val displayTracker = FakeDisplayTracker(context)
-        val sysUiState = SysUiState(displayTracker)
+        val sysUiState = SysUiState(displayTracker, kosmos.sceneContainerPlugin)
         val startable =
             SceneContainerStartable(
                 applicationScope = testScope.backgroundScope,
@@ -775,14 +776,9 @@
     }
 
     /** Emulates the dismissal of the IME (soft keyboard). */
-    private suspend fun TestScope.dismissIme(
-        showImeBeforeDismissing: Boolean = true,
-    ) {
+    private fun TestScope.dismissIme() {
         (bouncerViewModel.authMethodViewModel.value as? PasswordBouncerViewModel)?.let {
-            if (showImeBeforeDismissing) {
-                it.onImeVisibilityChanged(true)
-            }
-            it.onImeVisibilityChanged(false)
+            it.onImeDismissed()
             runCurrent()
         }
     }
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 bf99a86..942fbc2 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
@@ -174,105 +174,6 @@
         }
 
     @Test
-    fun transitioning_idle_false() =
-        testScope.runTest {
-            val transitionState =
-                MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(SceneKey.Shade)
-                )
-            val transitioning by
-                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
-            underTest.setTransitionState(transitionState)
-
-            assertThat(transitioning).isFalse()
-        }
-
-    @Test
-    fun transitioning_wrongFromScene_false() =
-        testScope.runTest {
-            val transitionState =
-                MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Gone,
-                        toScene = SceneKey.Lockscreen,
-                        progress = flowOf(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
-                    )
-                )
-            val transitioning by
-                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
-            underTest.setTransitionState(transitionState)
-
-            assertThat(transitioning).isFalse()
-        }
-
-    @Test
-    fun transitioning_wrongToScene_false() =
-        testScope.runTest {
-            val transitionState =
-                MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Shade,
-                        toScene = SceneKey.QuickSettings,
-                        progress = flowOf(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
-                    )
-                )
-            underTest.setTransitionState(transitionState)
-
-            assertThat(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen).value).isFalse()
-        }
-
-    @Test
-    fun transitioning_correctFromAndToScenes_true() =
-        testScope.runTest {
-            val transitionState =
-                MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Shade,
-                        toScene = SceneKey.Lockscreen,
-                        progress = flowOf(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
-                    )
-                )
-            val transitioning by
-                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
-            underTest.setTransitionState(transitionState)
-
-            assertThat(transitioning).isTrue()
-        }
-
-    @Test
-    fun transitioning_updates() =
-        testScope.runTest {
-            val transitionState =
-                MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(SceneKey.Shade)
-                )
-            val transitioning by
-                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
-            underTest.setTransitionState(transitionState)
-
-            assertThat(transitioning).isFalse()
-
-            transitionState.value =
-                ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Shade,
-                    toScene = SceneKey.Lockscreen,
-                    progress = flowOf(0.5f),
-                    isInitiatedByUserInput = false,
-                    isUserInputOngoing = flowOf(false),
-                )
-            assertThat(transitioning).isTrue()
-
-            transitionState.value = ObservableTransitionState.Idle(SceneKey.Lockscreen)
-            assertThat(transitioning).isFalse()
-        }
-
-    @Test
     fun isTransitionUserInputOngoing_idle_false() =
         testScope.runTest {
             val transitionState =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
similarity index 66%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
index 6bbe900..1ef07fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
@@ -16,71 +16,37 @@
 
 package com.android.systemui.shade.domain.interactor
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth
-import dagger.BindsInstance
-import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.Test
+import org.junit.runner.RunWith
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@RunWith(AndroidJUnit4::class)
 class ShadeAnimationInteractorSceneContainerImplTest : SysuiTestCase() {
+    val kosmos = testKosmos()
+    val testScope = kosmos.testScope
+    val sceneInteractor = kosmos.sceneInteractor
 
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent : SysUITestComponent<ShadeAnimationInteractorSceneContainerImpl> {
-        val sceneInteractor: SceneInteractor
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                featureFlags: FakeFeatureFlagsClassicModule,
-                mocks: TestMocksModule,
-            ): TestComponent
-        }
-    }
-
-    private val dozeParameters: DozeParameters = mock()
-
-    private val testComponent: TestComponent =
-        DaggerShadeAnimationInteractorSceneContainerImplTest_TestComponent.factory()
-            .create(
-                test = this,
-                featureFlags =
-                    FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
-                mocks =
-                    TestMocksModule(
-                        dozeParameters = dozeParameters,
-                    ),
-            )
+    val underTest = kosmos.shadeAnimationInteractorSceneContainerImpl
 
     @Test
     fun isAnyCloseAnimationRunning_qsToShade() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.isAnyCloseAnimationRunning)
 
             // WHEN transitioning from QS to Shade
@@ -103,10 +69,10 @@
 
     @Test
     fun isAnyCloseAnimationRunning_qsToGone_userInputNotOngoing() =
-        testComponent.runTest() {
+        testScope.runTest() {
             val actual by collectLastValue(underTest.isAnyCloseAnimationRunning)
 
-            // WHEN transitioning from QS to Gone with no ongoing user input
+            // WHEN transitioning from QS to Gone lwith no ongoing user input
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
@@ -126,7 +92,7 @@
 
     @Test
     fun isAnyCloseAnimationRunning_qsToGone_userInputOngoing() =
-        testComponent.runTest() {
+        testScope.runTest() {
             val actual by collectLastValue(underTest.isAnyCloseAnimationRunning)
 
             // WHEN transitioning from QS to Gone with user input ongoing
@@ -149,7 +115,7 @@
 
     @Test
     fun updateIsLaunchingActivity() =
-        testComponent.runTest {
+        testScope.runTest {
             Truth.assertThat(underTest.isLaunchingActivity.value).isEqualTo(false)
 
             underTest.setIsLaunchingActivity(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
index 71a7420..4e82feb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
@@ -19,124 +19,65 @@
 import android.app.StatusBarManager.DISABLE2_NONE
 import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
 import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
-import android.content.pm.UserInfo
-import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.DozeStateModel
 import com.android.systemui.keyguard.shared.model.DozeTransitionModel
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.power.data.repository.FakePowerRepository
+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.res.R
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.data.repository.fakeShadeRepository
 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
-import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.phone.dozeParameters
+import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
+import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
+import com.android.systemui.testKosmos
 import com.android.systemui.user.data.model.UserSwitcherSettingsModel
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.user.data.repository.fakeUserRepository
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
-import dagger.BindsInstance
-import dagger.Component
-import kotlinx.coroutines.runBlocking
-import org.junit.Before
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.Test
+import org.junit.runner.RunWith
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@RunWith(AndroidJUnit4::class)
 class ShadeInteractorImplTest : SysuiTestCase() {
+    val kosmos = testKosmos()
+    val testScope = kosmos.testScope
+    val configurationRepository = kosmos.fakeConfigurationRepository
+    val deviceProvisioningRepository = kosmos.fakeDeviceProvisioningRepository
+    val disableFlagsRepository = kosmos.fakeDisableFlagsRepository
+    val keyguardRepository = kosmos.fakeKeyguardRepository
+    val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+    val powerRepository = kosmos.fakePowerRepository
+    val sceneInteractor = kosmos.sceneInteractor
+    val shadeRepository = kosmos.fakeShadeRepository
+    val userRepository = kosmos.fakeUserRepository
+    val userSetupRepository = kosmos.fakeUserSetupRepository
+    val dozeParameters = kosmos.dozeParameters
 
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent : SysUITestComponent<ShadeInteractorImpl> {
-
-        val configurationRepository: FakeConfigurationRepository
-        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
-        val disableFlagsRepository: FakeDisableFlagsRepository
-        val keyguardRepository: FakeKeyguardRepository
-        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
-        val powerRepository: FakePowerRepository
-        val sceneInteractor: SceneInteractor
-        val shadeRepository: FakeShadeRepository
-        val userRepository: FakeUserRepository
-        val userSetupRepository: FakeUserSetupRepository
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                featureFlags: FakeFeatureFlagsClassicModule,
-                mocks: TestMocksModule,
-            ): TestComponent
-        }
-    }
-
-    private val dozeParameters: DozeParameters = mock()
-
-    private val testComponent: TestComponent =
-        DaggerShadeInteractorImplTest_TestComponent.factory()
-            .create(
-                test = this,
-                featureFlags =
-                    FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
-                mocks =
-                    TestMocksModule(
-                        dozeParameters = dozeParameters,
-                    ),
-            )
-
-    @Before
-    fun setUp() {
-        runBlocking {
-            val userInfos =
-                listOf(
-                    UserInfo(
-                        /* id= */ 0,
-                        /* name= */ "zero",
-                        /* iconPath= */ "",
-                        /* flags= */ UserInfo.FLAG_PRIMARY or
-                            UserInfo.FLAG_ADMIN or
-                            UserInfo.FLAG_FULL,
-                        UserManager.USER_TYPE_FULL_SYSTEM,
-                    ),
-                )
-            testComponent.apply {
-                userRepository.setUserInfos(userInfos)
-                userRepository.setSelectedUserInfo(userInfos[0])
-            }
-        }
-    }
+    val underTest = kosmos.shadeInteractorImpl
 
     @Test
     fun isShadeEnabled_matchesDisableFlagsRepo() =
-        testComponent.runTest {
+        testScope.runTest {
             val actual by collectLastValue(underTest.isShadeEnabled)
 
             disableFlagsRepository.disableFlags.value =
@@ -150,7 +91,7 @@
 
     @Test
     fun isExpandToQsEnabled_deviceNotProvisioned_false() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(false)
 
             val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -160,7 +101,7 @@
 
     @Test
     fun isExpandToQsEnabled_userNotSetupAndSimpleUserSwitcher_false() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
 
             userSetupRepository.setUserSetUp(false)
@@ -173,7 +114,7 @@
 
     @Test
     fun isExpandToQsEnabled_shadeNotEnabled_false() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetUp(true)
 
@@ -189,7 +130,7 @@
 
     @Test
     fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetUp(true)
 
@@ -204,7 +145,7 @@
 
     @Test
     fun isExpandToQsEnabled_dozing_false() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetUp(true)
             disableFlagsRepository.disableFlags.value =
@@ -221,7 +162,7 @@
 
     @Test
     fun isExpandToQsEnabled_userSetup_true() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -238,7 +179,7 @@
 
     @Test
     fun isExpandToQsEnabled_notSimpleUserSwitcher_true() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -255,7 +196,7 @@
 
     @Test
     fun isExpandToQsEnabled_respondsToDozingUpdates() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -283,7 +224,7 @@
 
     @Test
     fun isExpandToQsEnabled_respondsToDisableUpdates() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -315,7 +256,7 @@
 
     @Test
     fun isExpandToQsEnabled_respondsToUserUpdates() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -344,7 +285,7 @@
 
     @Test
     fun fullShadeExpansionWhenShadeLocked() =
-        testComponent.runTest {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
@@ -355,7 +296,7 @@
 
     @Test
     fun fullShadeExpansionWhenStatusBarStateIsNotShadeLocked() =
-        testComponent.runTest {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
@@ -369,7 +310,7 @@
 
     @Test
     fun shadeExpansionWhenInSplitShadeAndQsExpanded() =
-        testComponent.runTest {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is enabled and QS is expanded
@@ -386,7 +327,7 @@
 
     @Test
     fun shadeExpansionWhenNotInSplitShadeAndQsExpanded() =
-        testComponent.runTest {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is not enabled and QS is expanded
@@ -402,7 +343,7 @@
 
     @Test
     fun shadeExpansionWhenNotInSplitShadeAndQsCollapsed() =
-        testComponent.runTest {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is not enabled and QS is expanded
@@ -416,7 +357,7 @@
 
     @Test
     fun anyExpansion_shadeGreater() =
-        testComponent.runTest() {
+        testScope.runTest() {
             // WHEN shade is more expanded than QS
             shadeRepository.setLegacyShadeExpansion(.5f)
             shadeRepository.setQsExpansion(0f)
@@ -428,7 +369,7 @@
 
     @Test
     fun anyExpansion_qsGreater() =
-        testComponent.runTest() {
+        testScope.runTest() {
             // WHEN qs is more expanded than shade
             shadeRepository.setLegacyShadeExpansion(0f)
             shadeRepository.setQsExpansion(.5f)
@@ -440,7 +381,7 @@
 
     @Test
     fun userInteractingWithShade_shadeDraggedUpAndDown() =
-        testComponent.runTest() {
+        testScope.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -496,7 +437,7 @@
 
     @Test
     fun userInteractingWithShade_shadeExpanded() =
-        testComponent.runTest() {
+        testScope.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -531,7 +472,7 @@
 
     @Test
     fun userInteractingWithShade_shadePartiallyExpanded() =
-        testComponent.runTest() {
+        testScope.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -572,7 +513,7 @@
 
     @Test
     fun userInteractingWithShade_shadeCollapsed() =
-        testComponent.runTest() {
+        testScope.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade expanded and not tracking input
             shadeRepository.setLegacyShadeExpansion(1f)
@@ -607,7 +548,7 @@
 
     @Test
     fun userInteractingWithQs_qsDraggedUpAndDown() =
-        testComponent.runTest() {
+        testScope.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithQs)
             // GIVEN qs collapsed and not tracking input
             shadeRepository.setQsExpansion(0f)
@@ -663,7 +604,7 @@
 
     @Test
     fun isShadeTouchable_isFalse_whenFrpIsActive() =
-        testComponent.runTest {
+        testScope.runTest {
             deviceProvisioningRepository.setFactoryResetProtectionActive(true)
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -677,7 +618,7 @@
 
     @Test
     fun isShadeTouchable_isFalse_whenDeviceAsleepAndNotPulsing() =
-        testComponent.runTest {
+        testScope.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.ASLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -704,7 +645,7 @@
 
     @Test
     fun isShadeTouchable_isTrue_whenDeviceAsleepAndPulsing() =
-        testComponent.runTest {
+        testScope.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.ASLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -731,7 +672,7 @@
 
     @Test
     fun isShadeTouchable_isFalse_whenStartingToSleepAndNotControlScreenOff() =
-        testComponent.runTest {
+        testScope.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.STARTING_TO_SLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -753,7 +694,7 @@
 
     @Test
     fun isShadeTouchable_isTrue_whenStartingToSleepAndControlScreenOff() =
-        testComponent.runTest {
+        testScope.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.STARTING_TO_SLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -775,7 +716,7 @@
 
     @Test
     fun isShadeTouchable_isTrue_whenNotAsleep() =
-        testComponent.runTest {
+        testScope.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.AWAKE,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
similarity index 74%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
index 6e6e438..682c4ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
@@ -16,108 +16,45 @@
 
 package com.android.systemui.shade.domain.interactor
 
-import android.content.pm.UserInfo
-import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.data.repository.fakeShadeRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
 import com.google.common.truth.Truth.assertThat
-import dagger.BindsInstance
-import dagger.Component
-import kotlinx.coroutines.runBlocking
-import org.junit.Before
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.Test
+import org.junit.runner.RunWith
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@RunWith(AndroidJUnit4::class)
 class ShadeInteractorLegacyImplTest : SysuiTestCase() {
+    val kosmos = testKosmos()
+    val testScope = kosmos.testScope
+    val configurationRepository = kosmos.fakeConfigurationRepository
+    val keyguardRepository = kosmos.fakeKeyguardRepository
+    val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+    val sceneInteractor = kosmos.sceneInteractor
+    val shadeRepository = kosmos.fakeShadeRepository
+    val userRepository = kosmos.fakeUserRepository
 
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent : SysUITestComponent<ShadeInteractorLegacyImpl> {
-
-        val configurationRepository: FakeConfigurationRepository
-        val keyguardRepository: FakeKeyguardRepository
-        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
-        val powerRepository: FakePowerRepository
-        val sceneInteractor: SceneInteractor
-        val shadeRepository: FakeShadeRepository
-        val userRepository: FakeUserRepository
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                featureFlags: FakeFeatureFlagsClassicModule,
-                mocks: TestMocksModule,
-            ): TestComponent
-        }
-    }
-
-    private val dozeParameters: DozeParameters = mock()
-
-    private val testComponent: TestComponent =
-        DaggerShadeInteractorLegacyImplTest_TestComponent.factory()
-            .create(
-                test = this,
-                featureFlags =
-                    FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
-                mocks =
-                    TestMocksModule(
-                        dozeParameters = dozeParameters,
-                    ),
-            )
-
-    @Before
-    fun setUp() {
-        runBlocking {
-            val userInfos =
-                listOf(
-                    UserInfo(
-                        /* id= */ 0,
-                        /* name= */ "zero",
-                        /* iconPath= */ "",
-                        /* flags= */ UserInfo.FLAG_PRIMARY or
-                            UserInfo.FLAG_ADMIN or
-                            UserInfo.FLAG_FULL,
-                        UserManager.USER_TYPE_FULL_SYSTEM,
-                    ),
-                )
-            testComponent.apply {
-                userRepository.setUserInfos(userInfos)
-                userRepository.setSelectedUserInfo(userInfos[0])
-            }
-        }
-    }
+    val underTest = kosmos.shadeInteractorLegacyImpl
 
     @Test
     fun fullShadeExpansionWhenShadeLocked() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
@@ -128,7 +65,7 @@
 
     @Test
     fun fullShadeExpansionWhenStatusBarStateIsNotShadeLocked() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
@@ -142,7 +79,7 @@
 
     @Test
     fun shadeExpansionWhenInSplitShadeAndQsExpanded() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is enabled and QS is expanded
@@ -159,7 +96,7 @@
 
     @Test
     fun shadeExpansionWhenNotInSplitShadeAndQsExpanded() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is not enabled and QS is expanded
@@ -175,7 +112,7 @@
 
     @Test
     fun shadeExpansionWhenNotInSplitShadeAndQsCollapsed() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is not enabled and QS is expanded
@@ -189,7 +126,7 @@
 
     @Test
     fun userInteractingWithShade_shadeDraggedUpAndDown() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -245,7 +182,7 @@
 
     @Test
     fun userInteractingWithShade_shadeExpanded() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -280,7 +217,7 @@
 
     @Test
     fun userInteractingWithShade_shadePartiallyExpanded() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -321,7 +258,7 @@
 
     @Test
     fun userInteractingWithShade_shadeCollapsed() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade expanded and not tracking input
             shadeRepository.setLegacyShadeExpansion(1f)
@@ -356,7 +293,7 @@
 
     @Test
     fun userInteractingWithQs_qsDraggedUpAndDown() =
-        testComponent.runTest() {
+        testScope.runTest {
             val actual by collectLastValue(underTest.isUserInteractingWithQs)
             // GIVEN qs collapsed and not tracking input
             shadeRepository.setQsExpansion(0f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
index 310b86f..bf136cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
@@ -16,114 +16,48 @@
 
 package com.android.systemui.shade.domain.interactor
 
-import android.content.pm.UserInfo
-import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.userRepository
 import com.google.common.truth.Truth
-import dagger.BindsInstance
-import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.runBlocking
-import org.junit.Before
-import org.junit.Ignore
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.Test
+import org.junit.runner.RunWith
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@RunWith(AndroidJUnit4::class)
 class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {
 
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent : SysUITestComponent<ShadeInteractorSceneContainerImpl> {
+    val kosmos = testKosmos()
+    val testComponent = kosmos.testScope
+    val configurationRepository = kosmos.fakeConfigurationRepository
+    val keyguardRepository = kosmos.fakeKeyguardRepository
+    val keyguardTransitionRepository = kosmos.keyguardTransitionRepository
+    val sceneInteractor = kosmos.sceneInteractor
+    val userRepository = kosmos.userRepository
 
-        val configurationRepository: FakeConfigurationRepository
-        val keyguardRepository: FakeKeyguardRepository
-        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
-        val powerRepository: FakePowerRepository
-        val sceneInteractor: SceneInteractor
-        val shadeRepository: FakeShadeRepository
-        val userRepository: FakeUserRepository
+    val underTest = kosmos.shadeInteractorSceneContainerImpl
 
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                featureFlags: FakeFeatureFlagsClassicModule,
-                mocks: TestMocksModule,
-            ): TestComponent
-        }
-    }
-
-    private val dozeParameters: DozeParameters = mock()
-
-    private val testComponent: TestComponent =
-        DaggerShadeInteractorSceneContainerImplTest_TestComponent.factory()
-            .create(
-                test = this,
-                featureFlags =
-                    FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
-                mocks =
-                    TestMocksModule(
-                        dozeParameters = dozeParameters,
-                    ),
-            )
-
-    @Before
-    fun setUp() {
-        runBlocking {
-            val userInfos =
-                listOf(
-                    UserInfo(
-                        /* id= */ 0,
-                        /* name= */ "zero",
-                        /* iconPath= */ "",
-                        /* flags= */ UserInfo.FLAG_PRIMARY or
-                            UserInfo.FLAG_ADMIN or
-                            UserInfo.FLAG_FULL,
-                        UserManager.USER_TYPE_FULL_SYSTEM,
-                    ),
-                )
-            testComponent.apply {
-                userRepository.setUserInfos(userInfos)
-                userRepository.setSelectedUserInfo(userInfos[0])
-            }
-        }
-    }
-
-    @Ignore("b/309825977")
     @Test
     fun qsExpansionWhenInSplitShadeAndQsExpanded() =
-        testComponent.runTest() {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.qsExpansion)
 
             // WHEN split shade is enabled and QS is expanded
@@ -148,10 +82,9 @@
             Truth.assertThat(actual).isEqualTo(.3f)
         }
 
-    @Ignore("b/309825977")
     @Test
     fun qsExpansionWhenNotInSplitShadeAndQsExpanded() =
-        testComponent.runTest() {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.qsExpansion)
 
             // WHEN split shade is not enabled and QS is expanded
@@ -179,7 +112,7 @@
 
     @Test
     fun qsFullscreen_falseWhenTransitioning() =
-        testComponent.runTest() {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.isQsFullscreen)
 
             // WHEN scene transition active
@@ -203,7 +136,7 @@
 
     @Test
     fun qsFullscreen_falseWhenIdleNotQS() =
-        testComponent.runTest() {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.isQsFullscreen)
 
             // WHEN Idle but not on QuickSettings scene
@@ -221,7 +154,7 @@
 
     @Test
     fun qsFullscreen_trueWhenIdleQS() =
-        testComponent.runTest() {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.isQsFullscreen)
 
             // WHEN Idle on QuickSettings scene
@@ -239,7 +172,7 @@
 
     @Test
     fun lockscreenShadeExpansion_idle_onScene() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
             val key = SceneKey.Shade
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -256,7 +189,7 @@
 
     @Test
     fun lockscreenShadeExpansion_idle_onDifferentScene() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.Shade)
             val expansionAmount by collectLastValue(expansion)
@@ -274,7 +207,7 @@
 
     @Test
     fun lockscreenShadeExpansion_transitioning_toScene() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -312,7 +245,7 @@
 
     @Test
     fun lockscreenShadeExpansion_transitioning_fromScene() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -349,7 +282,7 @@
         }
 
     fun isQsBypassingShade_goneToQs() =
-        testComponent.runTest() {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.isQsBypassingShade)
 
             // WHEN transitioning from QS directly to Gone
@@ -372,7 +305,7 @@
         }
 
     fun isQsBypassingShade_shadeToQs() =
-        testComponent.runTest() {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.isQsBypassingShade)
 
             // WHEN transitioning from QS to Shade
@@ -396,7 +329,7 @@
 
     @Test
     fun lockscreenShadeExpansion_transitioning_toAndFromDifferentScenes() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.QuickSettings)
             val expansionAmount by collectLastValue(expansion)
@@ -433,7 +366,7 @@
 
     @Test
     fun userInteracting_idle() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.Shade
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -450,7 +383,7 @@
 
     @Test
     fun userInteracting_transitioning_toScene_programmatic() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -488,7 +421,7 @@
 
     @Test
     fun userInteracting_transitioning_toScene_userInputDriven() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -526,7 +459,7 @@
 
     @Test
     fun userInteracting_transitioning_fromScene_programmatic() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -564,7 +497,7 @@
 
     @Test
     fun userInteracting_transitioning_fromScene_userInputDriven() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -602,7 +535,7 @@
 
     @Test
     fun userInteracting_transitioning_toAndFromDifferentScenes() =
-        testComponent.runTest() {
+        testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, SceneKey.Shade)
             val interacting by collectLastValue(interactingFlow)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index e9a2a3b..c0aaab3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -9,8 +9,6 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
@@ -22,8 +20,6 @@
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -74,74 +70,6 @@
     }
 
     @Test
-    fun isTransitioning_idle_false() =
-        testScope.runTest {
-            val isTransitioning by collectLastValue(underTest.isTransitioning)
-            sceneInteractor.setTransitionState(
-                MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Shade))
-            )
-
-            assertThat(isTransitioning).isFalse()
-        }
-
-    @Test
-    fun isTransitioning_shadeToQs_true() =
-        testScope.runTest {
-            val isTransitioning by collectLastValue(underTest.isTransitioning)
-            sceneInteractor.setTransitionState(
-                MutableStateFlow(
-                    ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Shade,
-                        toScene = SceneKey.QuickSettings,
-                        progress = MutableStateFlow(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
-                    )
-                )
-            )
-
-            assertThat(isTransitioning).isTrue()
-        }
-
-    @Test
-    fun isTransitioning_qsToShade_true() =
-        testScope.runTest {
-            val isTransitioning by collectLastValue(underTest.isTransitioning)
-            sceneInteractor.setTransitionState(
-                MutableStateFlow(
-                    ObservableTransitionState.Transition(
-                        fromScene = SceneKey.QuickSettings,
-                        toScene = SceneKey.Shade,
-                        progress = MutableStateFlow(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
-                    )
-                )
-            )
-
-            assertThat(isTransitioning).isTrue()
-        }
-
-    @Test
-    fun isTransitioning_otherTransition_false() =
-        testScope.runTest {
-            val isTransitioning by collectLastValue(underTest.isTransitioning)
-            sceneInteractor.setTransitionState(
-                MutableStateFlow(
-                    ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Gone,
-                        toScene = SceneKey.Shade,
-                        progress = MutableStateFlow(0.5f),
-                        isInitiatedByUserInput = false,
-                        isUserInputOngoing = flowOf(false),
-                    )
-                )
-            )
-
-            assertThat(isTransitioning).isFalse()
-        }
-
-    @Test
     fun mobileSubIds_update() =
         testScope.runTest {
             val mobileSubIds by collectLastValue(underTest.mobileSubIds)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index 7274c0c..4528957 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -31,6 +31,7 @@
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.ravenwood.RavenwoodRule;
 import android.testing.TestableLooper.RunWithLooper;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -66,8 +67,11 @@
     @Mock
     private SystemUIDialog.Delegate mDelegate;
 
+    // TODO(b/292141694): build out Ravenwood support for DeviceFlagsValueProvider
+    // Ravenwood already has solid support for SetFlagsRule, but CheckFlagsRule will be added soon
     @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood() ? null
+            : DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Before
     public void setup() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/BooleanFlowOperatorsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/BooleanFlowOperatorsTest.kt
new file mode 100644
index 0000000..b4a0a37
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/BooleanFlowOperatorsTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.util.kotlin
+
+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.testKosmos
+import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.not
+import com.android.systemui.util.kotlin.BooleanFlowOperators.or
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BooleanFlowOperatorsTest : SysuiTestCase() {
+
+    val kosmos = testKosmos()
+    val testScope = kosmos.testScope
+
+    @Test
+    fun and_allTrue_returnsTrue() =
+        testScope.runTest {
+            val result by collectLastValue(and(TRUE, TRUE))
+            assertThat(result).isTrue()
+        }
+
+    @Test
+    fun and_anyFalse_returnsFalse() =
+        testScope.runTest {
+            val result by collectLastValue(and(TRUE, FALSE, TRUE))
+            assertThat(result).isFalse()
+        }
+
+    @Test
+    fun and_allFalse_returnsFalse() =
+        testScope.runTest {
+            val result by collectLastValue(and(FALSE, FALSE, FALSE))
+            assertThat(result).isFalse()
+        }
+
+    @Test
+    fun or_allTrue_returnsTrue() =
+        testScope.runTest {
+            val result by collectLastValue(or(TRUE, TRUE))
+            assertThat(result).isTrue()
+        }
+
+    @Test
+    fun or_anyTrue_returnsTrue() =
+        testScope.runTest {
+            val result by collectLastValue(or(FALSE, TRUE, FALSE))
+            assertThat(result).isTrue()
+        }
+
+    @Test
+    fun or_allFalse_returnsFalse() =
+        testScope.runTest {
+            val result by collectLastValue(or(FALSE, FALSE, FALSE))
+            assertThat(result).isFalse()
+        }
+
+    @Test
+    fun not_true_returnsFalse() =
+        testScope.runTest {
+            val result by collectLastValue(not(TRUE))
+            assertThat(result).isFalse()
+        }
+
+    @Test
+    fun not_false_returnsFalse() =
+        testScope.runTest {
+            val result by collectLastValue(not(FALSE))
+            assertThat(result).isTrue()
+        }
+
+    private companion object {
+        val TRUE: Flow<Boolean>
+            get() = flowOf(true)
+        val FALSE: Flow<Boolean>
+            get() = flowOf(false)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
new file mode 100644
index 0000000..471c8d8
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.bottombar.ui.viewmodel
+
+import android.content.Intent
+import android.provider.Settings
+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.plugins.activityStarter
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.volume.panel.volumePanelViewModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BottomBarViewModelTest : SysuiTestCase() {
+
+    @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+    @Captor private lateinit var intentCaptor: ArgumentCaptor<Intent>
+
+    private val kosmos = testKosmos()
+
+    private lateinit var underTest: BottomBarViewModel
+
+    private fun initUnderTest() {
+        underTest = with(kosmos) { BottomBarViewModel(activityStarter, volumePanelViewModel) }
+    }
+
+    @Test
+    fun onDoneClicked_hidesPanel() {
+        with(kosmos) {
+            testScope.runTest {
+                initUnderTest()
+                underTest.onDoneClicked()
+                runCurrent()
+
+                val volumePanelState by collectLastValue(volumePanelViewModel.volumePanelState)
+                assertThat(volumePanelState!!.isVisible).isFalse()
+            }
+        }
+    }
+
+    @Test
+    fun onSettingsClicked_dismissesPanelAndNavigatesToSettings() {
+        with(kosmos) {
+            testScope.runTest {
+                initUnderTest()
+                underTest.onSettingsClicked()
+
+                runCurrent()
+
+                val volumePanelState by collectLastValue(volumePanelViewModel.volumePanelState)
+                assertThat(volumePanelState!!.isVisible).isFalse()
+                verify(activityStarter).startActivity(capture(intentCaptor), eq(true))
+                assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_SOUND_SETTINGS)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt
new file mode 100644
index 0000000..6256eec
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.systemui.volume.panel.domain.interactor
+
+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.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.volume.panel.availableCriteria
+import com.android.systemui.volume.panel.criteriaByKey
+import com.android.systemui.volume.panel.defaultCriteria
+import com.android.systemui.volume.panel.domain.model.ComponentModel
+import com.android.systemui.volume.panel.enabledComponents
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.unavailableCriteria
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ComponentsInteractorImplTest : SysuiTestCase() {
+
+    private val kosmos = Kosmos()
+
+    private lateinit var underTest: ComponentsInteractor
+
+    private fun initUnderTest() {
+        underTest =
+            with(kosmos) {
+                ComponentsInteractorImpl(
+                    enabledComponents,
+                    defaultCriteria,
+                    testScope.backgroundScope,
+                    criteriaByKey,
+                )
+            }
+    }
+
+    @Test
+    fun componentsAvailability_checked() {
+        with(kosmos) {
+            testScope.runTest {
+                enabledComponents =
+                    setOf(
+                        BOTTOM_BAR,
+                        COMPONENT_1,
+                        COMPONENT_2,
+                    )
+                criteriaByKey =
+                    mapOf(
+                        BOTTOM_BAR to availableCriteria,
+                        COMPONENT_1 to unavailableCriteria,
+                        COMPONENT_2 to availableCriteria,
+                    )
+                initUnderTest()
+
+                val components by collectLastValue(underTest.components)
+
+                assertThat(components)
+                    .containsExactly(
+                        ComponentModel(BOTTOM_BAR, true),
+                        ComponentModel(COMPONENT_1, false),
+                        ComponentModel(COMPONENT_2, true),
+                    )
+            }
+        }
+    }
+
+    @Test
+    fun noCriteria_fallbackToDefaultCriteria() {
+        with(kosmos) {
+            testScope.runTest {
+                enabledComponents =
+                    setOf(
+                        BOTTOM_BAR,
+                        COMPONENT_1,
+                        COMPONENT_2,
+                    )
+                criteriaByKey =
+                    mapOf(
+                        BOTTOM_BAR to availableCriteria,
+                        COMPONENT_2 to availableCriteria,
+                    )
+                defaultCriteria = unavailableCriteria
+                initUnderTest()
+
+                val components by collectLastValue(underTest.components)
+
+                assertThat(components)
+                    .containsExactly(
+                        ComponentModel(BOTTOM_BAR, true),
+                        ComponentModel(COMPONENT_1, false),
+                        ComponentModel(COMPONENT_2, true),
+                    )
+            }
+        }
+    }
+
+    private companion object {
+        const val BOTTOM_BAR: VolumePanelComponentKey = "test_bottom_bar"
+        const val COMPONENT_1: VolumePanelComponentKey = "test_component:1"
+        const val COMPONENT_2: VolumePanelComponentKey = "test_component:2"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorTest.kt
deleted file mode 100644
index dbff63f..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorTest.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.systemui.volume.panel.domain.interactor
-
-class ComponentsInteractorTest {
-
-    // TODO(b/318080198) Write tests
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt
new file mode 100644
index 0000000..3dbf23e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.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.volume.panel.ui.composable
+
+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.volume.panel.componentByKey
+import com.android.systemui.volume.panel.mockVolumePanelUiComponentProvider
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ComponentsFactoryTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+
+    private lateinit var underTest: ComponentsFactory
+
+    private fun initUnderTest() {
+        underTest = ComponentsFactory(kosmos.componentByKey)
+    }
+
+    @Test
+    fun existingComponent_created() {
+        kosmos.componentByKey = mapOf(TEST_COMPONENT to kosmos.mockVolumePanelUiComponentProvider)
+        initUnderTest()
+
+        val component = underTest.createComponent(TEST_COMPONENT)
+
+        Truth.assertThat(component).isNotNull()
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun componentAbsence_throws() {
+        kosmos.componentByKey = emptyMap()
+        initUnderTest()
+
+        underTest.createComponent(TEST_COMPONENT)
+    }
+
+    private companion object {
+        const val TEST_COMPONENT: VolumePanelComponentKey = "test_component"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
index e5fb942..35d9698 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
@@ -16,7 +16,78 @@
 
 package com.android.systemui.volume.panel.ui.viewmodel
 
-class DefaultComponentsLayoutManagerTest {
+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.volume.panel.mockVolumePanelUiComponent
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+import com.android.systemui.volume.panel.ui.layout.DefaultComponentsLayoutManager
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
 
-    // TODO(b/318080198) Write tests
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DefaultComponentsLayoutManagerTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val underTest: ComponentsLayoutManager = DefaultComponentsLayoutManager()
+
+    @Test
+    fun bottomBar_isSet() {
+        val bottomBarComponentState =
+            ComponentState(BOTTOM_BAR, kosmos.mockVolumePanelUiComponent, false)
+        val layout =
+            underTest.layout(
+                VolumePanelState(0, false),
+                setOf(
+                    bottomBarComponentState,
+                    ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false),
+                    ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false),
+                )
+            )
+
+        Truth.assertThat(layout.bottomBarComponent).isEqualTo(bottomBarComponentState)
+    }
+
+    @Test
+    fun componentsAreInOrder() {
+        val bottomBarComponentState =
+            ComponentState(BOTTOM_BAR, kosmos.mockVolumePanelUiComponent, false)
+        val component1State = ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false)
+        val component2State = ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false)
+        val layout =
+            underTest.layout(
+                VolumePanelState(0, false),
+                setOf(
+                    bottomBarComponentState,
+                    component1State,
+                    component2State,
+                )
+            )
+
+        Truth.assertThat(layout.contentComponents[0]).isEqualTo(component1State)
+        Truth.assertThat(layout.contentComponents[1]).isEqualTo(component2State)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun bottomBarAbsence_throwsException() {
+        val component1State = ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false)
+        val component2State = ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false)
+        underTest.layout(
+            VolumePanelState(0, false),
+            setOf(
+                component1State,
+                component2State,
+            )
+        )
+    }
+
+    private companion object {
+        const val BOTTOM_BAR: VolumePanelComponentKey = "bottom_bar"
+        const val COMPONENT_1: VolumePanelComponentKey = "test_component:1"
+        const val COMPONENT_2: VolumePanelComponentKey = "test_component:2"
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
index 9795237..c4c9cc6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
@@ -16,7 +16,120 @@
 
 package com.android.systemui.volume.panel.ui.viewmodel
 
-class VolumePanelViewModelTest {
+import android.content.res.Configuration
+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.statusbar.policy.fakeConfigurationController
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.panel.componentByKey
+import com.android.systemui.volume.panel.componentsLayoutManager
+import com.android.systemui.volume.panel.criteriaByKey
+import com.android.systemui.volume.panel.dagger.factory.KosmosVolumePanelComponentFactory
+import com.android.systemui.volume.panel.mockVolumePanelUiComponentProvider
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.ui.layout.FakeComponentsLayoutManager
+import com.android.systemui.volume.panel.unavailableCriteria
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
 
-    // TODO(b/318080198) Write tests
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class VolumePanelViewModelTest : SysuiTestCase() {
+
+    private val kosmos =
+        testKosmos().apply {
+            componentsLayoutManager = FakeComponentsLayoutManager { it.key == BOTTOM_BAR }
+        }
+
+    private val testableResources = context.orCreateTestableResources
+
+    private lateinit var underTest: VolumePanelViewModel
+
+    private fun initUnderTest() {
+        underTest =
+            VolumePanelViewModel(
+                testableResources.resources,
+                KosmosVolumePanelComponentFactory(kosmos),
+                kosmos.fakeConfigurationController,
+            )
+    }
+
+    @Test
+    fun dismissingPanel_changesVisibility() {
+        with(kosmos) {
+            testScope.runTest {
+                initUnderTest()
+                assertThat(underTest.volumePanelState.value.isVisible).isTrue()
+
+                underTest.dismissPanel()
+                runCurrent()
+
+                assertThat(underTest.volumePanelState.value.isVisible).isFalse()
+            }
+        }
+    }
+
+    @Test
+    fun orientationChanges_panelOrientationChanges() {
+        with(kosmos) {
+            testScope.runTest {
+                initUnderTest()
+                val volumePanelState by collectLastValue(underTest.volumePanelState)
+                testableResources.overrideConfiguration(
+                    Configuration().apply { orientation = Configuration.ORIENTATION_PORTRAIT }
+                )
+                assertThat(volumePanelState!!.orientation)
+                    .isEqualTo(Configuration.ORIENTATION_PORTRAIT)
+
+                fakeConfigurationController.onConfigurationChanged(
+                    Configuration().apply { orientation = Configuration.ORIENTATION_LANDSCAPE }
+                )
+                runCurrent()
+
+                assertThat(volumePanelState!!.orientation)
+                    .isEqualTo(Configuration.ORIENTATION_LANDSCAPE)
+            }
+        }
+    }
+
+    @Test
+    fun components_areReturned() {
+        with(kosmos) {
+            testScope.runTest {
+                componentByKey =
+                    mapOf(
+                        COMPONENT_1 to mockVolumePanelUiComponentProvider,
+                        COMPONENT_2 to mockVolumePanelUiComponentProvider,
+                        BOTTOM_BAR to mockVolumePanelUiComponentProvider,
+                    )
+                criteriaByKey = mapOf(COMPONENT_2 to unavailableCriteria)
+                initUnderTest()
+
+                val componentsLayout by collectLastValue(underTest.componentsLayout)
+                runCurrent()
+
+                assertThat(componentsLayout!!.contentComponents).hasSize(2)
+                assertThat(componentsLayout!!.contentComponents[0].key).isEqualTo(COMPONENT_1)
+                assertThat(componentsLayout!!.contentComponents[0].isVisible).isTrue()
+                assertThat(componentsLayout!!.contentComponents[1].key).isEqualTo(COMPONENT_2)
+                assertThat(componentsLayout!!.contentComponents[1].isVisible).isFalse()
+                assertThat(componentsLayout!!.bottomBarComponent.key).isEqualTo(BOTTOM_BAR)
+                assertThat(componentsLayout!!.bottomBarComponent.isVisible).isTrue()
+            }
+        }
+    }
+
+    private companion object {
+        const val BOTTOM_BAR: VolumePanelComponentKey = "test_bottom_bar"
+        const val COMPONENT_1: VolumePanelComponentKey = "test_component:1"
+        const val COMPONENT_2: VolumePanelComponentKey = "test_component:2"
+    }
 }
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index f801990..3b2eb15 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laai tans"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laai tans vinnig"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laai tans stadig"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laaiproses is onderbreek om battery te beskerm"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Gaan die laaibykomstigheid na"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk is gesluit"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Geen SIM nie"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Onbruikbare SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 356eebb..c3d141c 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ኃይል በመሙላት ላይ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • በፍጥነት ኃይልን በመሙላት ላይ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> - ባትሪን ለመጠበቅ ኃይል መሙላት በይቆይ ላይ"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • የኃይል መሙላት መለዋወጫን ይፈትሹ"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"አውታረ መረብ ተቆልፏል"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ምንም SIM የለም"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ጥቅም ላይ የማይውል ሲም።"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 707388e..cf8341d 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن سريعًا"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن ببطء"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"‫<xliff:g id="PERCENTAGE">%s</xliff:g> • الشحن معلّق لحماية البطارية"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"‫<xliff:g id="PERCENTAGE">%s</xliff:g> • يُرجى فحص ملحق الشحن."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"الشبكة مؤمّنة"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"‏لا تتوفر شريحة SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"‏شريحة SIM غير قابلة للاستخدام."</string>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 8b9d306..d11a9c1 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চ্চার্জ কৰি থকা হৈছে"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • দ্ৰুত গতিৰে চাৰ্জ কৰি থকা হৈছে"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • লাহে লাহে চাৰ্জ কৰি থকা হৈছে"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • বেটাৰী সুৰক্ষিত কৰিবলৈ চাৰ্জিং স্থগিত ৰখা হৈছে"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চাৰ্জিঙৰ সৈতে জড়িত আনুষংগিক সামগ্ৰী পৰীক্ষা কৰক"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটৱর্ক লক কৰা অৱস্থাত আছে"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"কোনো ছিম নাই"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ব্যৱহাৰ কৰিব নোৱৰা ছিম।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index 39d8032..4de32d9 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Enerji yığır"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sürətlə enerji yığır"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Yavaş enerji yığır"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Batareyanı qorumaq üçün şarj gözlədilir"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj aksesuarını yoxlayın"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Şəbəkə kilidlidir"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM yoxdur"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"İstifadəyə yararsız SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index 519e5f6..d23ff41 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Puni se"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Brzo se puni"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sporo se puni"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je na čekanju da bi se zaštitila baterija"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Proverite dodatnu opremu za punjenje"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Neupotrebljiv SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 15bc616..e704c3c8 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе зарадка"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе хуткая зарадка"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе павольная зарадка"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарадка прыпынена, каб абараніць акумулятар"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Праверце зарадную прыладу"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сетка заблакіравана"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Няма SIM-карты"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Непрыдатная для выкарыстання SIM-карта."</string>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 7e2e2b3..795d4b83 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се бързо"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се бавно"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зареждането е поставено на пауза с цел запазване на батерията"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверете аксесоара за зареждане"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заключена"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Няма SIM карта"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Неизползваема SIM карта."</string>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 2f7d3ba..e333ddd 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চার্জ হচ্ছে"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • দ্রুত চার্জ হচ্ছে"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ধীরে চার্জ হচ্ছে"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ব্যাটারিকে সুরক্ষিত রাখতে চার্জিং হোল্ড করা হয়েছে"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চার্জিং অ্যাক্সেসরি চেক করুন"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটওয়ার্ক লক করা আছে"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"কোনও সিম নেই"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ব্যবহারযোগ্য নয় এমন সিম।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index e35298b..75fe286 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Brzo punjenje"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sporo punjenje"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je na čekanju radi zaštite baterije"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Provjera dodatne opreme za punjenje"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Neupotrebljiv SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 0fcc491..4047d7c 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant ràpidament"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant lentament"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • La càrrega s\'ha posat en espera per protegir la bateria"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Revisa l\'accessori de càrrega"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"La xarxa està bloquejada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hi ha cap SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"La SIM no es pot utilitzar."</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 3764032..ea9a683 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíjení"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Rychlé nabíjení"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pomalé nabíjení"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíjení je odloženo za účelem ochrany baterie"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Zkontrolujte nabíjecí příslušenství"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Síť je blokována"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Žádná SIM karta"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM kartu nelze použít."</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 8b04c46..8794bc0 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader hurtigt"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader langsomt"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladningen er sat på pause for at beskytte batteriet"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tjek opladningstilbehøret"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netværket er låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Intet SIM-kort"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Deaktiveret SIM-kort."</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index f122f49..9e80b74 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird geladen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird schnell geladen"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird langsam geladen"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladevorgang zum Schutz des Akkus angehalten"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladezubehör prüfen"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netzwerk gesperrt"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Keine SIM-Karte"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-Karte ist nicht nutzbar."</string>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 9c05a29..b7d3250 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Φόρτιση"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Γρήγορη φόρτιση"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Αργή φόρτιση"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Η φόρτιση τέθηκε σε αναμονή για την προστασία της μπαταρίας"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ελέγξτε το αξεσουάρ φόρτισης"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Κλειδωμένο δίκτυο"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Δεν υπάρχει SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Η SIM δεν μπορεί να χρησιμοποιηθεί."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index fc8790c..d0461c1 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging rapidly"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging on hold to protect battery"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Check charging accessory"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index fc8790c..d0461c1 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging rapidly"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging on hold to protect battery"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Check charging accessory"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index fc8790c..d0461c1 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging rapidly"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging on hold to protect battery"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Check charging accessory"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 3851b07..43aea8d 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rápidamente"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se detuvo la carga para proteger la batería"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verifica el accesorio de carga"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hay ninguna tarjeta SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Tarjeta SIM inutilizable."</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index c0fccdd..9022a3d 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rápidamente"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carga pausada para proteger la batería"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Comprueba el accesorio de carga"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hay ninguna SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"No se puede usar la SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 5f75c87..c0d5e2f2 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laadimine"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kiirlaadimine"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Aeglane laadimine"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • laadimine on aku kaitsmiseks ootele pandud"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • kontrollige laadimistarvikut"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Võrk on lukus"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM-i pole"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-i ei saa kasutada."</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 486531a..c9ac7e9 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kargatzen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bizkor kargatzen"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mantso kargatzen"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • kargatze-prozesua zain dago bateria babesteko"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Eman begiratu bat kargatzeko osagarriari"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sarea blokeatuta dago"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ez dago SIMik"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ezin da erabili SIMa."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 4822487..b1b1f8a 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • درحال شارژ شدن"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • درحال شارژ سریع"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • آهسته‌آهسته شارژ می‌شود"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • برای محافظت از باتری، شارژ موقتاً متوقف شده است"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • لوازم شارژ را بررسی کنید"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"شبکه قفل شد"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"سیم‌کارتی وجود ندارد"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"سیم‌کارت قابل‌استفاده نیست."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 39b0529..f5a6759 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan nopeasti"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan hitaasti"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lataus on keskeytetty akun suojaamiseksi"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tarkista latauslisävaruste"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Verkko lukittu"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ei SIM-korttia"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-korttia ei voi käyttää."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index fcf5052..bca8dd7 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"En recharge : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"En recharge rapide : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"En recharge lente : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • La recharge a été mise en pause pour protéger la pile"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Vérifier l\'accessoire de recharge"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Aucune carte SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"La carte SIM est inutilisable."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index ffa0b1d..97d2081 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge…"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge rapide…"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge lente"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge en pause pour protéger la batterie"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Vérifier l\'accessoire de recharge"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Aucune SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilisable."</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 1163ed0..12b6c2c 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rapidamente"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carga púxose en pausa para protexer a batería"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Comproba o accesorio de carga"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada pola rede"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Non hai ningunha SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"A SIM non se pode usar."</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index bfbb2f2..9e2fd53 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ઝડપથી ચાર્જિંગ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ધીમેથી ચાર્જિંગ"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • બૅટરીને સુરક્ષિત રાખવા માટે, ચાર્જિંગ હોલ્ડ પર રાખવામાં આવ્યું છે"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ ઍક્સેસરી ચેક કરો"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"નેટવર્ક લૉક થયું"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"કોઈ સિમ કાર્ડ નથી"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ઉપયોગમાં ન લઈ શકાતું સિમ કાર્ડ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 9ee840d..12cb7e3 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज हो रहा है"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • तेज़ चार्ज हो रहा है"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • धीरे चार्ज हो रहा है"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • बैटरी को सुरक्षित रखने के लिए, चार्जिंग को रोका गया है"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिंग ऐक्सेसरी की जांच करें"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक किया हुआ है"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"कोई सिम नहीं है"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"सिम को हमेशा के लिए बंद कर दिया गया है."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 4edd7d2..fad222d 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • punjenje"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • brzo punjenje"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • sporo punjenje"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je pauzirano radi zaštite baterije"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Provjerite dodatak za punjenje"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM je neupotrebljiv."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index f27156d..a22fbce 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Töltés"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Gyors töltés"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lassú töltés"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Az akkumulátor védelme érdekében a töltés szünetel"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ellenőrizze a töltőtartozékot"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Hálózat zárolva"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nincs SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nem használható SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index a402721..119928a 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Լիցքավորում"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Արագ լիցքավորում"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Դանդաղ լիցքավորում"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Լիցքավորումը դադարեցվել է՝ մարտկոցը պաշտպանելու համար"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ստուգեք լիցքավորիչը"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Ցանցը կողպված է"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM քարտ չկա"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Անվավեր SIM քարտ։"</string>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 229419e..f4db035 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan cepat"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan lambat"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengisian daya dihentikan sementara untuk melindungi baterai"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Periksa aksesori pengisi daya"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Jaringan terkunci"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Tidak ada SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM tidak dapat digunakan."</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 7edcdbd..c364f60 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Í hleðslu"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hröð hleðsla"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hæg hleðsla"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hleðsla í bið til að vernda rafhlöðuna"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Athugaðu hleðslubúnaðinn"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Net læst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ekkert SIM-kort"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ónothæft SIM-kort."</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 7856a49..659928f 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • In carica"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica veloce"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica lenta"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica in sospeso per proteggere la batteria"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Controlla l\'accessorio di ricarica"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rete bloccata"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nessuna SIM presente"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilizzabile."</string>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 9182c5a..0021d0a 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה מהירה"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה איטית"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • הטעינה הושהתה כדי להגן על הסוללה"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • צריך לבדוק את אביזר הטעינה"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"הרשת נעולה"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"‏אין כרטיס SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"‏לא ניתן להשתמש בכרטיס ה-SIM הזה."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index e589f85..c94d6b1 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電中"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 急速充電中"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 低速充電中"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • バッテリーを保護するため、充電を一時停止しています"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電用アクセサリを確認してください"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ネットワークがロックされました"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM がありません"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM が使用できません。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 0fe5a39..c36b471 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • იტენება"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • სწრაფად იტენება"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ნელა იტენება"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • დატენვა შეჩერებულია ბატარეის დასაცავად"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • შეამოწმეთ დამტენი აქსესუარი"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ქსელი ჩაკეტილია"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM არ არის"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"გამოუყენებელი SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 3882c5d..fef02be 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядталуда"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Жылдам зарядтау"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Баяу зарядталуда"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяны қорғау мақсатында зарядтау кідіртілді."</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядтау құрылғысын тексеріңіз."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Желі құлыптаулы"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM картасы жоқ."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM картасын пайдалану мүмкін емес."</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 0ebda04..f82defd 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្ម"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្មយ៉ាង​ឆាប់រហ័ស"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្មយឺត"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុងផ្អាកការសាកថ្ម ដើម្បីការពារថ្ម"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ពិនិត្យមើលគ្រឿងសាកថ្ម"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"បណ្ដាញ​ជាប់​សោ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"គ្មានស៊ីមទេ"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ស៊ីមមិនអាចប្រើបាន។"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 4dbefed..4ab035e5 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಚಾರ್ಜ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ವೇಗವಾಗಿ ಚಾರ್ಜ್‌ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಬ್ಯಾಟರಿಯನ್ನು ರಕ್ಷಿಸಲು ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ಹೋಲ್ಡ್‌ ಮಾಡಲಾಗಿದೆ"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಚಾರ್ಜಿಂಗ್ ಪರಿಕರವನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ನೆಟ್‌ವರ್ಕ್ ಲಾಕ್ ಆಗಿದೆ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM ಇಲ್ಲ"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM ನಿಷ್ಪ್ರಯೋಜಕವಾಗಿದೆ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index e0d7645..d456366 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 충전 중"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 고속 충전 중"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 저속 충전 중"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 배터리 보호를 위해 충전 일시중지"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 충전 액세서리 확인"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"네트워크 잠김"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM 없음"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM을 사용할 수 없습니다."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index cc777a2..e8640ae5 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Кубатталууда"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Тез кубатталууда"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Жай кубатталууда"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяны коргоо үчүн кубаттоо тындырылды"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Кубаттоо шайманын текшериңиз"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Тармак кулпуланган"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM карта жок"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Жараксыз SIM карта."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index ce2fa3b..6f6c1d1 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກແບບດ່ວນ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກແບບຊ້າ"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ຢຸດການສາກຊົ່ວຄາວເພື່ອປົກປ້ອງແບັດເຕີຣີ"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກວດສອບອຸປະກອນເສີມສຳລັບການສາກ"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ເຄືອຂ່າຍຖືກລັອກ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ບໍ່ມີຊິມ"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ຊິມໃຊ້ບໍ່ໄດ້."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 4344b61..9d13485 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Įkraunama"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Greitai įkraunama"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lėtai įkraunama"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • įkrovimas pristabdytas, siekiant apsaugoti akumuliatorių"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • patikrinkite įkrovimo priedą"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tinklas užrakintas"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nėra SIM kortelės"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nenaudojama SIM kortelė."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index b521511..10d657b 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek uzlāde"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek ātrā uzlāde"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek lēnā uzlāde"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Uzlāde apturēta, lai aizsargātu akumulatoru"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pārbaudiet uzlādes piederumu"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tīkls ir bloķēts."</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nav SIM kartes"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM karte nav izmantojama."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 7fe966f..9aafb86 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Се полни"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Брзо полнење"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Бавно полнење"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Полнењето е паузирано за да се заштити батеријата"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверете го додатокот за полнење"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заклучена"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Нема SIM-картичка"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-картичката е неупотреблива."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index afd7c40..f690ce5 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ചാർജ് ചെയ്യുന്നു"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • വേഗത്തിൽ ചാർജ് ചെയ്യുന്നു"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • പതുക്കെ ചാർജ് ചെയ്യുന്നു"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ബാറ്ററി പരിരക്ഷിക്കാൻ ചാർജിംഗ് ഹോൾഡിലാണ്"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ചാർജിംഗ് ആക്സസറി പരിശോധിക്കുക"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"നെറ്റ്‌വർക്ക് ലോക്കുചെയ്‌തു"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"സിം ഇല്ല"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ഉപയോഗശൂന്യമായ സിം."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index d29daa5..70cfa37 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Цэнэглэж байна"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Хурдан цэнэглэж байна"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Удаан цэнэглэж байна"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батарейг хамгаалахын тулд цэнэглэхийг хүлээлгэсэн"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Цэнэглэх нэмэлт хэрэгслийг шалгах"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сүлжээ түгжигдсэн"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM байхгүй"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ашиглах боломжгүй SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 85522d7d..9da4fb0 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज होत आहे"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • वेगाने चार्ज होत आहे"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • सावकाश चार्ज होत आहे"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • बॅटरीचे संरक्षण करण्यासाठी चार्जिंग थांबवले आहे"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिंगसंबंधित ॲक्सेसरी तपासा"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक केले"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"सिम नाही"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"वापरण्यायोग्य नसलेले सिम."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 1b8ef07..76de213 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas dengan cepat"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas dengan perlahan"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengecasan ditunda untuk melindungi bateri"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Periksa aksesori pengecasan"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rangkaian dikunci"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Tiada SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM tidak boleh digunakan."</string>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index a638d17d..bedabb8 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • အားသွင်းနေသည်"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • အမြန်အားသွင်းနေသည်"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • နှေးကွေးစွာ အားသွင်းနေသည်"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ဘက်ထရီကို ကာကွယ်ရန် အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • အားသွင်းပစ္စည်းကို စစ်ပါ"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ကွန်ရက်ကို လော့ခ်ချထားသည်"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ဆင်းမ်ကတ် မရှိပါ"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ဆင်းမ်ကတ်ကို သုံး၍မရပါ။"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index b289b72c..04b567b 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lader"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lader raskt"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lader sakte"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladingen er satt på vent for å beskytte batteriet"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> · Sjekk ladetilbehøret"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nettverket er låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ingen SIM-kort"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-kortet kan ikke brukes."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index fc6f21fe..692e693 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज गरिँदै"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • द्रुत गतिमा चार्ज गरिँदै छ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • मन्द गतिमा चार्ज गरिँदै"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ब्याट्रीको सुरक्षा गर्न चार्जिङ होल्ड गरिएको छ"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिङ एक्सेसरी जाँच्नुहोस्"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लक भएको छ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM कार्ड हालिएको छैन"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"यो SIM कार्ड प्रयोग गर्न मिल्दैन।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 093c7b7..9833505 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Snel opladen"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Langzaam opladen"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladen in de wacht gezet om batterij te beschermen"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Check je oplaadaccessoire"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk vergrendeld"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Geen simkaart"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Onbruikbare simkaart."</string>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index 76dbdaf..5ed2f11 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ଚାର୍ଜ ହେଉଛି"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ଦ୍ରୁତ ଭାବେ ଚାର୍ଜ ହେଉଛି"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ଧୀରେ ଚାର୍ଜ ହେଉଛି"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ବେଟେରୀକୁ ସୁରକ୍ଷିତ ରଖିବା ପାଇଁ ଚାର୍ଜିଂ ହୋଲ୍ଡରେ ଅଛି"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ଚାର୍ଜିଂ ଆକସେସୋରୀକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ନେଟୱର୍କକୁ ଲକ୍‌ କରାଯାଇଛି"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"କୌଣସି SIM ନାହିଁ"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ବ୍ୟବହାର ଅଯୋଗ୍ୟ ଥିବା SIM।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 10e9eef..e591e5d2 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਬੈਟਰੀ ਦੀ ਸੁਰੱਖਿਆ ਲਈ ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਚਾਰਜਿੰਗ ਐਕਸੈਸਰੀ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ਨੈੱਟਵਰਕ  ਲਾਕ  ਕੀਤਾ ਗਿਆ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ਕੋਈ ਸਿਮ ਨਹੀਂ ਹੈ"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ਬੇਕਾਰ ਸਿਮ।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 08cbc29..396fa79 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ładowanie"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Szybkie ładowanie"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wolne ładowanie"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> – wstrzymano ładowanie, aby chronić baterię"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> – sprawdź akcesoria do ładowania"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieć zablokowana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Brak karty SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nie można użyć karty SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index efd1c75..3de54f9 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando rapidamente"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando lentamente"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento suspenso para proteger a bateria"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verifique o acessório de carregamento"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem chip"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Chip inutilizável."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 38cc437..3d8f7e6 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar…"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar rapidamente…"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar lentamente…"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento em espera para proteger a bateria"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verificar acessório de carregamento"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilizável."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index efd1c75..3de54f9 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando rapidamente"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando lentamente"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento suspenso para proteger a bateria"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verifique o acessório de carregamento"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem chip"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Chip inutilizável."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index e3cfd3e..053f862 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se încarcă"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se încarcă rapid"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se încarcă lent"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Încărcarea s-a întrerupt pentru a proteja bateria"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verifică accesoriul de încărcare"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rețea blocată"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Niciun card SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Cardul SIM nu se poate folosi."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index b5b3266..6be1489 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"Идет зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"Идет быстрая зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"Идет медленная зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядка приостановлена для защиты батареи."</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверьте зарядное устройство."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сеть заблокирована"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM-карта отсутствует"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-карту невозможно использовать."</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index ecd3f3f..401e147 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ආරෝපණය වෙමින්"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • වේගයෙන් ආරෝපණය වෙමින්"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • සෙමින් ආරෝපණය වෙමින්"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • බැටරිය ආරක්ෂා කිරීම සඳහා ආරෝපණය රඳවා තබා ඇත"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ආරෝපණ ආයිත්තම පරීක්ෂා කරන්න"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ජාලය අගුළු දමා ඇත"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM නැත"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"භාවිත කළ නොහැකි SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index c38ba64..2b65466 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíja sa"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíja sa rýchlo"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíja sa pomaly"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíjanie je pozastavené, aby sa chránila batéria"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Skontrolujte nabíjacie príslušenstvo"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieť je zablokovaná"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Žiadna SIM karta"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nepoužiteľná SIM karta."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index c066f50..dbb34c9 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • polnjenje"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • hitro polnjenje"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • počasno polnjenje"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Zaradi zaščite baterije je polnjenje na čakanju"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Preverite pripomoček za polnjenje"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Omrežje je zaklenjeno"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ni kartice SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kartica SIM je neuporabna."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 1dc93fd1..00c4999 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me shpejtësi"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet ngadalë"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Karikimi është vendosur në pritje për të mbrojtur baterinë"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kontrollo aksesorin e karikimit"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rrjeti është i kyçur"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nuk ka kartë SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kartë SIM e papërdorshme."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 34cb06b..feac583 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Пуни се"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Брзо се пуни"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Споро се пуни"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Пуњење је на чекању да би се заштитила батерија"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверите додатну опрему за пуњење"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежа је закључана"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Нема SIM-а"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Неупотребљив SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 76c5dca..67fa2f7 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas snabbt"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas långsamt"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddningen har pausats för att skydda batteriet"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kontrollera laddningstillbehöret"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nätverk låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Inget SIM-kort"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-kortet går inte att använda."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index b310ab9..527e73e 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji kwa kasi"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji pole pole"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Imesitisha kuchaji ili kulinda betri yako"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kagua kifaa cha kuchaji"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mtandao umefungwa"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Hakuna SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM haiwezi kutumika."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index f31137a..05ac0c0 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • சார்ஜாகிறது"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • வேகமாகச் சார்ஜாகிறது"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • மெதுவாகச் சார்ஜாகிறது"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • பேட்டரியைப் பாதுகாப்பதற்காகச் சார்ஜிங் ஹோல்டு செய்யப்பட்டுள்ளது"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • சார்ஜிங் துணைக்கருவியைச் சரிபார்க்கவும்"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"நெட்வொர்க் பூட்டப்பட்டது"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"சிம் இல்லை"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"பயன்படுத்த முடியாத சிம்."</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 924678f..9d37fc1 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ఛార్జ్ అవుతోంది"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • వేగంగా ఛార్జ్ అవుతోంది"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • నెమ్మదిగా ఛార్జ్ అవుతోంది"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • బ్యాటరీని రక్షించడానికి ఛార్జింగ్ హోల్డ్‌లో ఉంచబడింది"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ఛార్జింగ్ యాక్సెసరీని చెక్ చేయండి"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"నెట్‌వర్క్ లాక్ చేయబడింది"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM లేదు"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"వినియోగించలేని SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 980ed99..57aadea 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • กำลังชาร์จ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • กำลังชาร์จอย่างเร็ว"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • กำลังชาร์จอย่างช้าๆ"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • หยุดการชาร์จชั่วคราวเพื่อถนอมแบตเตอรี่"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ตรวจสอบอุปกรณ์เสริมสำหรับการชาร์จ"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"เครือข่ายถูกล็อก"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ไม่มี SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM ใช้งานไม่ได้"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index b054b1e..bb7c344 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nagcha-charge"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mabilis na nagcha-charge"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mabagal na nagcha-charge"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Naka-hold ang pag-charge para protektahan ang baterya"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Suriin ang accessory sa pag-charge"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Naka-lock ang network"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Walang SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Hindi magagamit na SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 343cea1..f401629 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj oluyor"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hızlı şarj oluyor"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Yavaş şarj oluyor"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pili korumak için şarj beklemede"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj aksesuarını kontrol edin"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Ağ kilitli"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM yok"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kullanılamayan SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 56ca79d..4330b32 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Заряджання"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Швидке заряджання"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Повільне заряджання"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Заряджання призупинено, щоб захистити акумулятор"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Перевірте зарядний пристрій"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мережу заблоковано"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Немає SIM-карти"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Непридатна SIM-карта."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 3c47dd5..e466807 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • چارج ہو رہا ہے"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • تیزی سے چارج ہو رہا ہے"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • آہستہ چارج ہو رہا ہے"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • بیٹری کی حفاظت کرنے کے لیے چارجنگ ہولڈ پر ہے"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • چارجنگ ایکسیسری چیک کریں"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"نیٹ ورک مقفل ہو گیا"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"‏کوئی SIM نہیں ہے"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"‏ناقابل استعمال SIM۔"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index f58628b..f3cdf26 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quvvat olmoqda"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tezkor quvvat olmoqda"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sekin quvvat olmoqda"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Batareyani himoyalash uchun quvvatlash toʻxtatildi"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quvvatlash aksessuarini tekshiring"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tarmoq qulflangan"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM kartasiz"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ishlamaydigan SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 7fb272f..3bad8f1 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc nhanh"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc chậm"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang tạm ngưng sạc để bảo vệ pin"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hãy kiểm tra phụ kiện sạc"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mạng đã bị khóa"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Không có SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM không sử dụng được."</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 79e00fd..2818ffb 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在充电"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在快速充电"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在慢速充电"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 为保护电池,充电已暂停"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 请检查充电配件"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"网络已锁定"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"没有 SIM 卡"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡无法使用。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 76f366a..1b196d4 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在充電"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 快速充電中"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 慢速充電中"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> - 為保護電池,目前暫停充電"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 檢查充電配件"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"網絡已鎖定"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"沒有 SIM 卡"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡無法使用。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index e7e25c1..9b7e431 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電中"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 快速充電中"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 慢速充電中"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 為保護電池,目前暫停充電"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 請檢查充電配件"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"網路已鎖定"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"沒有 SIM 卡"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡無法使用。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 61f956a..cd36f95 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -33,10 +33,8 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Iyashaja"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ishaja kaningi"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ishaja kancane"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
-    <skip />
-    <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ukushaja kumisiwe ukuze kuvikelwe ibhethri"</string>
+    <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hlola insiza yokushaja"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Inethiwekhi ivaliwe"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ayikho i-SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"I-SIM engasebenziseki."</string>
diff --git a/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change_inset.xml b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change_inset.xml
new file mode 100644
index 0000000..02486bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change_inset.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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/accessibility_window_magnification_drag_handle_background_change"
+    android:insetBottom="@dimen/magnification_inner_border_margin"
+    android:insetLeft="@dimen/magnification_inner_border_margin"
+    android:insetRight="@dimen/magnification_inner_border_margin"
+    android:insetTop="@dimen/magnification_inner_border_margin" />
diff --git a/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_inset.xml b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_inset.xml
new file mode 100644
index 0000000..bfb7c47
--- /dev/null
+++ b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_inset.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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/accessibility_window_magnification_drag_handle_background"
+    android:insetBottom="@dimen/magnification_inner_border_margin"
+    android:insetLeft="@dimen/magnification_inner_border_margin"
+    android:insetRight="@dimen/magnification_inner_border_margin"
+    android:insetTop="@dimen/magnification_inner_border_margin" />
diff --git a/packages/SystemUI/res/layout/window_magnifier_view.xml b/packages/SystemUI/res/layout/window_magnifier_view.xml
index a8a048d..6286f34 100644
--- a/packages/SystemUI/res/layout/window_magnifier_view.xml
+++ b/packages/SystemUI/res/layout/window_magnifier_view.xml
@@ -117,12 +117,11 @@
         android:id="@+id/drag_handle"
         android:layout_width="@dimen/magnification_drag_view_size"
         android:layout_height="@dimen/magnification_drag_view_size"
-        android:layout_margin="@dimen/magnification_inner_border_margin"
         android:layout_gravity="right|bottom"
         android:padding="@dimen/magnifier_drag_handle_padding"
         android:scaleType="center"
         android:src="@drawable/ic_move_magnification"
-        android:background="@drawable/accessibility_window_magnification_drag_handle_background"/>
+        android:background="@drawable/accessibility_window_magnification_drag_handle_background_inset"/>
 
     <ImageView
         android:id="@+id/close_button"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 30ac963..32ea2ce 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Voeg by, verwyder en herrangskik jou legstukke in hierdie spasie"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Voeg meer legstukke by"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Langdruk om legstukke te pasmaak"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwyder"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Voeg legstuk by"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikerteenwoordigheid is bespeur"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string>
     <string name="install_app" msgid="5066668100199613936">"Installeer app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swiep om voort te gaan"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Sinkroniseer wedersyds na eksterne skerm?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Jou binneste skerm sal weerspieël word. Jou boonste skerm sal afgeskakel word."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Sinkroniseer skerm wedersyds"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9aa6a18..12bca7d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"በዚህ ቦታ ላይ የእርስዎን ምግብሮች ያክሉ፣ ያስወግዱ እና እንደገና ቅደም ተከተል ያስይዙ"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ተጨማሪ ምግብሮችን ያክሉ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ምግብሮችን ለማበጀት በረጅሙ ይጫኑ"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"አስወግድ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ምግብር አክል"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ተከናውኗል"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"የተጠቃሚ ተገኝነት ታውቋል"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string>
     <string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ለመቀጠል ያንሸራትቱ"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ወደ ውጫዊ ማሳያ ይንጸባረቅ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"የውስጥ ማሳያዎ ይንጸባረቃል። የፊት ማሳያዎ ይጠፋል።"</string>
     <string name="mirror_display" msgid="2515262008898122928">"ማሳያን አንጸባርቅ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 0874ffb..1101e20 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"يمكنك في هذه المساحة إضافة التطبيقات المصغّرة وإزالتها وإعادة ترتيبها."</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"إضافة المزيد من التطبيقات المصغّرة"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"اضغط مع الاستمرار لتخصيص التطبيقات المصغّرة."</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"إزالة"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"إضافة تطبيق مصغّر"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"تم"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"تم رصد تواجد المستخدم."</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string>
     <string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"مرِّر سريعًا للمتابعة."</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"هل تريد بث محتوى جهازك على الشاشة الخارجية؟"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"سيتم النسخ المطابق لمحتوى الشاشة الداخلية، وإيقاف الشاشة الأمامية."</string>
     <string name="mirror_display" msgid="2515262008898122928">"بث المحتوى على الشاشة"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 0338188..3050685 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"এই স্পেচটোত আপোনাৰ ৱিজেটসমূহ যোগ দিয়ক, আঁতৰাওক আৰু সেইসমূহৰ ক্ৰম সলনি কৰক"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"অধিক ৱিজেট যোগ দিয়ক"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ৱিজেট কাষ্টমাইজ কৰিবলৈ দীঘলীয়াকৈ টিপক"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"আঁতৰাওক"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ৱিজেট যোগ দিয়ক"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"কৰা হ’ল"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"ব্যৱহাৰকাৰীৰ উপস্থিতি চিনাক্ত কৰা হৈছে"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string>
     <string name="install_app" msgid="5066668100199613936">"এপ্‌টো ইনষ্টল কৰক"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"অব্যাহত ৰাখিবলৈ ছোৱাইপ কৰক"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"বাহ্যিক ডিছপ্লে’লৈ মিৰ’ৰ কৰিবনে?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"আপোনাৰ ইনাৰ ডিছপ্লে’ প্ৰতিবিম্বিত কৰা হ’ব। আপোনাৰ ফ্ৰণ্ট ডিছপ্লে’ অফ কৰা হ’ব।"</string>
     <string name="mirror_display" msgid="2515262008898122928">"ডিছপ্লে’ মিৰ’ৰ কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index c858c3b..3c3462b 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Burada vidcetlər əlavə edin, silin və sırasını dəyişin"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Vidcetlər əlavə edin"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Basıb saxlayaraq vidcetləri fərdiləşdirin"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Silin"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidcet əlavə edin"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hazırdır"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"İstifadəçi mövcudluğu aşkarlandı"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string>
     <string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Çəkərək davam edin"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Xarici displeyə əks etdirilsin?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"İç displey əks etdiriləcək. Ön ekran deaktiv ediləcək."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Displeyi əks etdirin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 379c68e..33e7921 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodajte, uklonite i preuredite vidžete u ovom prostoru"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte još vidžeta"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugi pritisak za prilagođavanje vidžeta"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj vidžet"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Prisustvo korisnika može da se otkrije"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string>
     <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prevucite da biste nastavili"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li da preslikate na spoljnji ekran?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutrašnji ekran će se preslikati. Prednji ekran će se isključiti."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 97e8f17..b7e3b1b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Дадаць ці выдаліць віджэты ў гэтай вобласці або змяніць іх парадак"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Дадаць іншыя віджэты"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Доўга націскайце, каб наладзіць віджэты"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Выдаліць"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Дадаць віджэт"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Гатова"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Выяўлена прысутнасць карыстальніка"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string>
     <string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Правядзіце пальцам, каб працягнуць"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Адлюстраваць на знешнім дысплэі?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Будзе ўключана дубліраванне ўнутранага дысплэя. Пярэдні дысплэй будзе выключаны."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Адлюстраваць дысплэй"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index f8585bc..c1a27d2 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Добавяйте, премахвайте и пренареждайте приспособленията си в тази област"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Добавете още приспособления"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Натиснете продължително за персонализ. на приспос."</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Премахване"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавяне на приспособление"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Установено е присъствие на потребител"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Прекарайте пръст, за да продължите"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се дублира ли на външния екран?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Съдържанието на вътрешния ви дисплей ще бъде дублирано. Предният ви дисплей ще бъде изключен."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Дублиране на дисплея"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 2229e8f..a694f5e 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"এই স্পেসে আপনার উইজেট যোগ করুন, সরান ও আবার সাজান"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"আরও উইজেট যোগ করুন"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"উইজেট কাস্টমাইজ করতে বেশিক্ষণ প্রেস করুন"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"সরান"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"উইজেট যোগ করুন"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"হয়ে গেছে"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"ব্যবহারকারীর উপস্থিতি শনাক্ত করা হয়েছে"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string>
     <string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"চালিয়ে যেতে সোয়াইপ করুন"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"এক্সটার্নাল ডিসপ্লেতে মিরর করবেন?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"আপনার ইনার ডিসপ্লে মিরর করা হবে। আপনার ফ্রন্ট ডিসপ্লে বন্ধ করা হবে।"</string>
     <string name="mirror_display" msgid="2515262008898122928">"ডিসপ্লে দেখান"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d704b0a..1c7198a 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodajte, uklonite i promijenite raspored vidžeta u ovom prostoru"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte još vidžeta"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pritisnite i zadržite da prilagodite vidžete"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Uklanjanje"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajte vidžet"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkriveno je prisustvo korisnika"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string>
     <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prevucite da nastavite"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Preslikati na vanjski ekran?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutrašnji ekran će se preslikavati. Prednji ekran će se isključiti."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ab3bc8f..948fb5c 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Afegeix, suprimeix i reordena widgets en aquest espai"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Afegeix més widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén premut per personalitzar els widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Suprimeix"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Afegeix un widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fet"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"S\'ha detectat la presència d\'usuaris"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string>
     <string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Llisca per continuar"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Duplicar a la pantalla externa?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"La pantalla interior es duplicarà. La pantalla frontal es desactivarà."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Duplica la pantalla"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4dd9d4f..33397fe 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"V tomto prostoru můžete přidávat a odstraňovat widgety a měnit jejich pořadí"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Přidat další widgety"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dlouhým stisknutím můžete přizpůsobit widgety"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstranit"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Přidat widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hotovo"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Je zjištěna přítomnost uživatele"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string>
     <string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pokračujte přejetím prstem"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Zrcadlit na externí displej?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Vnitřní displej bude zrcadlen. Přední displej bude vypnutý."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Zrcadlit displej"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index a2d17df..35142da 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Tilføj, fjern og omorganiser widgets i dette rum"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tilføj flere widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Hold fingeren nede for at tilpasse widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tilføj widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Udfør"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Brugertilstedeværelse er registreret"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Stryg for at fortsætte"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du spejle til ekstern skærm?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Din indre skærm spejles. Din skærm på forsiden slukkes."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Spejl skærm"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index bebedce..e100b90 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Hier kannst du Widgets hinzufügen, entfernen und neu anordnen"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Weitere Widgets hinzufügen"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Lange drücken, um Widgets anzupassen"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Entfernen"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget hinzufügen"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fertig"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Anwesenheit des Nutzers wurde erkannt"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string>
     <string name="install_app" msgid="5066668100199613936">"App installieren"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Zum Fortfahren wischen"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Auf externen Bildschirm spiegeln?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Dein inneres Display wird gespiegelt. Das Frontdisplay wird ausgeschaltet."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Bildschirm spiegeln"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3c87ad9..ed3a678 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Προσθήκη, κατάργηση και αναδιάταξη των γραφικών στοιχείων σε αυτόν τον χώρο"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Προσθήκη περισσότερων γραφικών στοιχείων"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Παρατεταμένο πάτημα για προσαρμογή γραφ. στοιχείων"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Κατάργηση"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Προσθήκη γραφικού στοιχείου"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Τέλος"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Εντοπίστηκε παρουσία χρήστη"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string>
     <string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Σύρετε για συνέχεια"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Κατοπτρισμός σε εξωτερική οθόνη;"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Θα γίνει κατοπτρισμός της εσωτερικής προβολής. Η μπροστινή οθόνη θα απενεργοποιηθεί."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Κατοπτρισμός οθόνης"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index cbdc26f..31b4b6e 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove and reorder your widgets in this space"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index da14f53..23cd700 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -418,6 +418,9 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove, and reorder your widgets in this space"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1216,7 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+    <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"Swipe up to continue"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index cbdc26f..31b4b6e 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove and reorder your widgets in this space"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index cbdc26f..31b4b6e 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove and reorder your widgets in this space"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index aec29d8..2970880 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -418,6 +418,9 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎Add, remove, and reorder your widgets in this space‎‏‎‎‏‎"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎Add more widgets‎‏‎‎‏‎"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎Long press to customize widgets‎‏‎‎‏‎"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <string name="edit_widget" msgid="9030848101135393954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‎‎Edit widget‎‏‎‎‏‎"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎Remove‎‏‎‎‏‎"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎Add widget‎‏‎‎‏‎"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎Done‎‏‎‎‏‎"</string>
@@ -1213,7 +1216,7 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎User presence is detected‎‏‎‎‏‎"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎Set default notes app in Settings‎‏‎‎‏‎"</string>
     <string name="install_app" msgid="5066668100199613936">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎Install app‎‏‎‎‏‎"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎Swipe to continue‎‏‎‎‏‎"</string>
+    <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‎‎Swipe up to continue‎‏‎‎‏‎"</string>
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎Mirror to external display?‎‏‎‎‏‎"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‏‎Your inner display will be mirrored. Your front display will be turned off.‎‏‎‎‏‎"</string>
     <string name="mirror_display" msgid="2515262008898122928">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎Mirror display‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 6dcc40a..8f2d0e7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Agrega, quita y reordena tus widgets en este espacio"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Agregar más widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén presionado para personalizar los widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Agregar widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Listo"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Se detectó la presencia del usuario"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Desliza el dedo para continuar"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Quieres duplicar en la pantalla externa?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Se duplicará la pantalla interior. Se apagará la pantalla frontal."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Duplicar pantalla"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index aecf5b1..7848e87 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Añade, elimina y reordena tus widgets en este espacio"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Añade más widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén pulsado para personalizar los widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Añadir widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hecho"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Se ha detectado la presencia de usuarios"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Desliza para continuar"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Proyectar a pantalla externa?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Se proyectará tu pantalla interior. Se apagará tu pantalla frontal."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Proyectar pantalla"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index edfb5be..6591799 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Lisage ja eemaldage selles ruumis oma vidinaid ning muutke nende järjestust"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisage rohkem vidinaid"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vajutage pikalt vidinate kohandamiseks"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Eemalda"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisa vidin"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Valmis"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Tuvastati kasutaja kohalolu"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string>
     <string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pühkige jätkamiseks"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kas peegeldada välisekraanile?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Teie siseekraani peegeldatakse. Teie esiekraan lülitatakse välja."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Peegelda ekraani"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 7fe37b4..937aa24 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -366,8 +366,8 @@
     <string name="sensor_privacy_mic_unblocked_dialog_content" msgid="4889961886199270224">"Aplikazio eta zerbitzu guztiek mikrofonoa erabil dezakete."</string>
     <string name="sensor_privacy_mic_blocked_no_exception_dialog_content" msgid="5864898470772965394">"Mikrofonoa erabiltzeko baimena desgaituta dago aplikazio eta zerbitzu guztietarako. Mikrofonoa erabiltzeko baimena gaitzeko, joan Ezarpenak &gt; Pribatutasuna &gt; Mikrofonoa atalera."</string>
     <string name="sensor_privacy_mic_blocked_with_exception_dialog_content" msgid="810289713700437896">"Mikrofonoa erabiltzeko baimena desgaituta dago aplikazio eta zerbitzu guztietarako. Baimen hori aldatzeko, joan Ezarpenak &gt; Pribatutasuna &gt; Mikrofonoa atalera."</string>
-    <string name="sensor_privacy_camera_turned_on_dialog_title" msgid="8039095295100075952">"Piztu da kamera"</string>
-    <string name="sensor_privacy_camera_turned_off_dialog_title" msgid="1936603903120742696">"Itzali da kamera"</string>
+    <string name="sensor_privacy_camera_turned_on_dialog_title" msgid="8039095295100075952">"Aktibatu da kamera"</string>
+    <string name="sensor_privacy_camera_turned_off_dialog_title" msgid="1936603903120742696">"Desaktibatu da kamera"</string>
     <string name="sensor_privacy_camera_unblocked_dialog_content" msgid="7847190103011782278">"Aplikazio eta zerbitzu guztiek kamera erabil dezakete."</string>
     <string name="sensor_privacy_camera_blocked_dialog_content" msgid="3182428709314874616">"Kamera erabiltzeko baimena desgaituta dago aplikazio eta zerbitzu guztietarako."</string>
     <string name="sensor_privacy_htt_blocked_dialog_content" msgid="3333321592997666441">"Mikrofonoaren botoia erabiltzeko, gaitu mikrofonoa erabiltzeko baimena ezarpenetan."</string>
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Gehitu eta kendu eremu honetako widgetak, edo aldatu haien ordena"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Gehitu widget gehiago"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widgetak pertsonalizatzeko, sakatu luze"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Kendu"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Gehitu widget bat"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Eginda"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Erabiltzailearen presentzia hauteman da"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Aurrera egiteko, pasatu hatza"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kanpoko pantailan islatu nahi duzu?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Barneko pantaila islatuko da. Aurreko pantaila desaktibatu egingo da."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Islatu pantaila"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 485009d..9948f5f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"افزودن، برداشتن، و تغییر ترتیب ابزارک‌ها در این فضا"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"افزودن ابزارک‌های بیشتر"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"برای سفارشی‌سازی ابزارک‌ها، فشار طولانی دهید"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"برداشتن"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"افزودن ابزارک"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"تمام"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"حضور کاربر شناسایی می‌شود"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیش‌فرض یادداشت را در «تنظیمات» تنظیم کنید"</string>
     <string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"برای ادامه، تند بکشید"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"روی نمایشگر خارجی قرینه‌سازی شود؟"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"نمایشگر داخلی شما قرینه‌سازی می‌شود. نمایشگر جلو خاموش می‌شود."</string>
     <string name="mirror_display" msgid="2515262008898122928">"قرینه‌سازی نمایشگر"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index e65d7e0..d4bb6bd 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Lisää, poista ja järjestä widgetejäsi uudelleen tässä tilassa"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisää widgetejä"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Yksilöi widgetit pitkällä painalluksella"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Poista"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisää widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Valmis"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Käyttäjän läsnäolo havaittu"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string>
     <string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Jatka pyyhkäisemällä"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Peilataanko ulkoiselle näytölle?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Sisänäyttö peilataan. Etunäyttö laitetaan pois päältä."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Peilaa näyttö"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 557b9b8..ea7b0b0 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Ajouter, retirer et réorganiser vos widgets dans cet espace"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ajouter plus de widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Maintenez le doigt pour personnaliser les widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Terminé"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence d\'un utilisateur est détectée"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Balayez l\'écran pour continuer"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer l\'écran sur un moniteur externe?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Votre écran intérieur sera dupliqué. Votre écran frontal sera désactivé."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 13af9a5..acaa43e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dans cet espace, ajoutez, supprimez et réorganisez vos widgets"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ajouter des widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Appuyez de manière prolongée pour personnaliser les widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Supprimer"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"OK"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence de l\'utilisateur est détectée"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Balayer pour continuer"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer sur l\'écran externe ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Votre écran intérieur sera dupliqué. Votre écran frontal sera éteint."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index d30770d..6b23868 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Engadir, quitar e reordenar widgets neste espazo"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Engadir máis widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pulsación longa para personalizar os widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engadir widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Feito"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Detectouse a presenza de usuarios"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pasa o dedo para continuar"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Queres proxectar contido nunha pantalla externa?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Proxectarase a pantalla interior. Desactivarase a pantalla frontal."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Proxectar pantalla"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 62ffdd3..6ea1f0e 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"આ સ્પેસમાં તમારા વિજેટ ઉમેરો, તેને કાઢી નાખો અને ફરી તેને ક્રમમાં ગોઠવો"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"વધુ વિજેટ ઉમેરો"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"વિજેટ કસ્ટમાઇઝ કરવા માટે થોડીવાર દબાવી રાખો"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"કાઢી નાખો"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"વિજેટ ઉમેરો"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"થઈ ગયું"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"વપરાશકર્તાની હાજરીની ભાળ મળી છે"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string>
     <string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ચાલુ રાખવા સ્વાઇપ કરો"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"શું બાહ્ય ડિસ્પ્લે પર મિરર કરીએ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"તમારું ઇનર ડિસ્પ્લે મિરર કરવામાં આવશે. તમારું ફ્રન્ટ ડિસ્પ્લે બંધ કરવામાં આવશે."</string>
     <string name="mirror_display" msgid="2515262008898122928">"મિરર ડિસ્પ્લે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 65cf5f7..db3549a 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"इस स्पेस में विजेट जोड़ें, हटाएं, और उन्हें फिर से क्रम में लगाएं"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ज़्यादा विजेट जोड़ें"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट पसंद के मुताबिक बनाने के लिए उसे दबाकर रखें"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाएं"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोड़ें"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"हो गया"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"उपयोगकर्ता की मौजूदगी का पता लगाया गया"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string>
     <string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"जारी रखने के लिए स्वाइप करें"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"क्या आपको किसी बाहरी डिवाइस पर डिसप्ले करना है?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"आपके फ़ोन के इनर डिसप्ले की स्क्रीन शेयर की जाएगी. फ़्रंट डिसप्ले को बंद कर दिया जाएगा."</string>
     <string name="mirror_display" msgid="2515262008898122928">"डिसप्ले करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b502e85..27eb8e9 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodavanje, uklanjanje i promjena redoslijeda widgeta u ovom prostoru"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodavanje još widgeta"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugo pritisnite za prilagodbu widgeta"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkrivena je prisutnost korisnika"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalacija"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prijeđite prstom za nastavak"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li zrcaliti na vanjski zaslon?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutarnji zaslon bit će zrcaljen. Prednji zaslon bit će isključen."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Zrcaljenje zaslona"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c7ce0b5b..7a16d74 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Modulok hozzáadása, eltávolítása és átrendezése ezen a területen"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"További modulok hozzáadása"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nyomja meg hosszan a modulok személyre szabásához"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Eltávolítás"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Modul hozzáadása"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Kész"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Felhasználói jelenlét észlelve"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string>
     <string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Csúsztasson a folytatáshoz"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tükrözi a kijelzőt a külső képernyőre?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"A belső kijelző tükrözve lesz. Az elülső kijelző ki lesz kapcsolva."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Kijelző tükrözése"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 7db84db..f3e883f 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Ավելացնել վիջեթներ, ինչպես նաև հեռացնել և վերադասավորել դրանք այս տարածքում"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ավելացնել վիջեթներ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Երկար սեղմեք՝ վիջեթները հարմարեցնելու համար"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Հեռացնել"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ավելացնել վիջեթ"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Պատրաստ է"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Հայտնաբերվել է օգտատեր"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string>
     <string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Սահեցրեք շարունակելու համար"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Հայելապատճենե՞լ արտաքին էկրանին"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ներքին էկրանը կհայելապատճենվի։ Առջևի էկրանը կանջատվի։"</string>
     <string name="mirror_display" msgid="2515262008898122928">"Հայելապատճենել էկրանը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index b7e7e81..fdd111f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Tambahkan, hapus, dan susun ulang widget Anda di ruang ini"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tambahkan widget lainnya"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Hapus"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Selesai"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna terdeteksi"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string>
     <string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Geser untuk melanjutkan"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Cerminkan ke layar eksternal?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Layar dalam akan dicerminkan. Layar depan akan dinonaktifkan."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Cerminkan layar"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index db1b743..cdbc055c 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Bættu við, fjarlægðu og endurraðaðu græjunum þínum í þessu rými"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Bæta við fleiri græjum"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Haltu inni til að sérsníða græjur"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjarlægja"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Bæta græju við"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Lokið"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Viðvera notanda greindist"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string>
     <string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Strjúktu til að halda áfram"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spegla yfir á ytri skjá?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Innri skjárinn þinn verður speglaður. Slökkt verður á framskjánum þínum."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Spegla skjá"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 997b76b..ec74e40 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Aggiungi, rimuovi e riordina i tuoi widget in questo spazio"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Aggiungi altri widget"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Premi a lungo per personalizzare i widget"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Rimuovi"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Aggiungi widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fine"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Viene rilevata la presenza dell\'utente"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string>
     <string name="install_app" msgid="5066668100199613936">"Installa app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Scorri per continuare"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vuoi eseguire il mirroring al display esterno?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Verrà eseguito il mirroring del tuo display interno. Il tuo display frontale verrà spento."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Esegui il mirroring del display"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 22079ac..ee1d0bd 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"הוספה, הסרה, וסידור מחדש של הווידג\'טים במרחב הזה"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"הוספת ווידג\'טים"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"לוחצים לחיצה ארוכה כדי להתאים אישית את הווידג\'טים"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"הסרה"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"הוספת ווידג\'ט"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"סיום"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"נוכחות המשתמש זוהתה"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string>
     <string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"צריך להחליק כדי להמשיך"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"לשקף למסך חיצוני?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"המסך הפנימי שלך ישוכפל. המסך החיצוני שלך יכובה."</string>
     <string name="mirror_display" msgid="2515262008898122928">"תצוגת מראה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 74ccd50d..416a61d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"このスペースでのウィジェットの追加、削除、並べ替え"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ウィジェットの追加"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長押ししてウィジェットをカスタマイズ"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"削除"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ウィジェットを追加"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完了"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"会話を始められます"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string>
     <string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"スワイプして続行"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"外部ディスプレイにミラーリングしますか?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"インナー ディスプレイがミラーリングされます。フロント ディスプレイはオフになります。"</string>
     <string name="mirror_display" msgid="2515262008898122928">"ディスプレイをミラーリングする"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 59d7487..db57e7e 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ამ სივრცეში შეძლებთ თქვენი ვიჯეტების დამატებას, ამოშლასა და გადაწყობას"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ვიჯეტების დამატება"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ხანგრძლივად დააჭირეთ ვიჯეტების მოსარგებად"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ამოშლა"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ვიჯეტის დამატება"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"მზადაა"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"აღმოჩენილია მომხმარებლის ყოფნა"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string>
     <string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"გადაფურცლეთ გასაგრძელებლად"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"აირეკლოს გარე ეკრანზე?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"თქვენი შიდა ეკრანი აირეკლება. თქვენი წინა ეკრანი გამოირთვება."</string>
     <string name="mirror_display" msgid="2515262008898122928">"ეკრანის არეკვლა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index b6a18d79..a90c6e8 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Осы бөлмеде виджеттер қосыңыз, оларды өшіріңіз және ретін өзгертіңіз."</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Басқа виджеттер қосыңыз."</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерді бейімдеу үшін ұзақ басып тұрыңыз."</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Өшіру"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет қосу"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Дайын"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Пайдаланушы анықталды."</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string>
     <string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Жалғастыру үшін сырғытыңыз."</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Сыртқы экран арқылы да көрсету керек пе?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ішкі экран көшірмесі көрсетіледі. Алдыңғы экран өшіріледі."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Көрсету"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index c2551e7..dfa26a5 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"បញ្ចូល ដកចេញ និងតម្រៀបធាតុ​ក្រាហ្វិករបស់អ្នកឡើងវិញនៅក្នុងលំហនេះ"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"បញ្ចូលធាតុ​ក្រាហ្វិកច្រើនទៀត"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ចុច​ឱ្យ​យូរ ដើម្បីប្ដូរធាតុ​ក្រាហ្វិកតាមបំណង"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ដកចេញ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"បញ្ចូលធាតុ​ក្រាហ្វិក"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"រួចរាល់"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"វត្តមានអ្នកប្រើប្រាស់ត្រូវបានចាប់ដឹង"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string>
     <string name="install_app" msgid="5066668100199613936">"ដំឡើង​កម្មវិធី"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"សូមអូសដើម្បីបន្ត"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"បញ្ចាំងទៅ​ផ្ទាំងអេក្រង់​ខាងក្រៅឬ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"អេក្រង់ខាងក្នុងរបស់អ្នកនឹងត្រូវបានធ្វើ​សមកាលកម្មទៅវិញទៅមក។ អេក្រង់មុខរបស់អ្នកនឹងត្រូវបានបិទ។"</string>
     <string name="mirror_display" msgid="2515262008898122928">"បញ្ចាំងទៅផ្ទាំងអេក្រង់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index a04c95b..51d74cc 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ಈ ಜಾಗದಲ್ಲಿ ನಿಮ್ಮ ವಿಜೆಟ್‌ಗಳನ್ನು ಸೇರಿಸಿ, ತೆಗೆದುಹಾಕಿ ಮತ್ತು ಮರುಕ್ರಮಗೊಳಿಸಿ"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ಹೆಚ್ಚಿನ ವಿಜೆಟ್‌ಗಳನ್ನು ಸೇರಿಸಿ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ವಿಜೆಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ಮುಗಿದಿದೆ"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"ಬಳಕೆದಾರರ ಉಪಸ್ಥಿತಿಯನ್ನು ಪತ್ತೆಹಚ್ಚಲಾಗಿದೆ"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
     <string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ಮುಂದುವರಿಯಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ಬಾಹ್ಯ ಡಿಸ್‌ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಬೇಕೆ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ನಿಮ್ಮ ಒಳಗಿನ ಡಿಸ್‌ಪ್ಲೇ ಅನ್ನು ಪ್ರತಿಬಿಂಬಿಸಲಾಗುತ್ತದೆ. ನಿಮ್ಮ ಫ್ರಂಟ್ ಡಿಸ್‌ಪ್ಲೇ ಅನ್ನು ಆಫ್ ಮಾಡಲಾಗುತ್ತದೆ."</string>
     <string name="mirror_display" msgid="2515262008898122928">"ಮಿರರ್ ಡಿಸ್‌ಪ್ಲೇ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e199783..316fea7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"이 공간에서 위젯 추가, 삭제 또는 다시 정렬"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"더 많은 위젯 추가"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"위젯을 맞춤설정하려면 길게 누르기"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"삭제"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"위젯 추가"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"완료"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"사용자 정보가 감지되었습니다."</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string>
     <string name="install_app" msgid="5066668100199613936">"앱 설치"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"계속하려면 스와이프하세요"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"외부 디스플레이로 미러링하시겠습니까?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"내부 디스플레이가 미러링됩니다. 전면 디스플레이는 꺼집니다."</string>
     <string name="mirror_display" msgid="2515262008898122928">"디스플레이 미러링"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index e42dc71..d7b13a6 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Бул иш чөйрөсүнө виджеттерди кошуп, өчүрүп жана иретин өзгөртүңүз"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Көбүрөөк виджеттерди кошуу"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерди ыңгайлаштыруу үчүн кое бербей басып туруңуз"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Өчүрүү"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет кошуу"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Бүттү"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Колдонуучу аныкталды"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string>
     <string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Улантуу үчүн экранды сүрүп коюңуз"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Тышкы экранга чыгарасызбы?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ички экраныңыз башка экранга чыгарылат. Алдыңкы экраныңыз өчүрүлөт."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Тышкы экран"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index ea12242..1f0fbe4 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ເພີ່ມ, ລຶບອອກ ແລະ ຈັດຮຽງວິດເຈັດຂອງທ່ານຄືນໃໝ່ໃນພື້ນທີ່ນີ້"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ເພີ່ມວິດເຈັດເພີ່ມເຕີມ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ກົດຄ້າງໄວ້ເພື່ອປັບແຕ່ງວິດເຈັດ"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ລຶບອອກ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ເພີ່ມວິດເຈັດ"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ແລ້ວໆ"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"ກວດພົບຕົວຕົນຜູ້ໃຊ້"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string>
     <string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ປັດເພື່ອສືບຕໍ່"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ສາຍໃສ່ຈໍສະແດງຜົນພາຍນອກບໍ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ການສະແດງຜົນທາງໃນຂອງທ່ານຈະຖືກສະທ້ອນ. ການສະແດງຜົນທາງໜ້າຂອງທ່ານຈະຖືກປິດໄວ້."</string>
     <string name="mirror_display" msgid="2515262008898122928">"ຈໍສະແດງຜົນແບບສະທ້ອນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 38a25e5..df88f0a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Šioje erdvėje pridėkite valdiklių, juos pašalinkite ir keiskite jų tvarką"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pridėkite daugiau valdiklių"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Ilgai paspauskite, kad tinkintumėte valdiklius"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Pašalinti"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridėti valdiklį"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Atlikta"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Aptikta naudotojo veikla"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string>
     <string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Perbraukite, kad galėtumėte tęsti"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Bendrinti ekrano vaizdą išoriniame ekrane?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Bus bendrinamas vidinio rodinio ekrano vaizdas. Priekinis rodinys bus išjungtas."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Bendrinti ekrano vaizdą"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index bea683b..7139fdb 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Šajā vietā varat pievienot, noņemt un pārkārtot logrīkus"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pievienot citus logrīkus"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nospiediet un turiet, lai pielāgotu logrīkus."</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Noņemt"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pievienot logrīku"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gatavs"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Konstatēta lietotāja klātbūtne"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string>
     <string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Velciet, lai turpinātu"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vai spoguļot ārējā displejā?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Jūsu iekšējais displejs tiks spoguļots. Jūsu priekšējais displejs tiks izslēgts."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Spoguļot displeju"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 26192e5a..26e4caa 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Додајте, отстранете и прераспоредете ги виџетите во просторов"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додајте повеќе виџети"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Притиснете долго за да ги приспособите виџетите"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Отстранува"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додајте виџет"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Откриено е присуство на корисник"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Повлечете нагоре за да продолжите"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се преслика на надворешниот екран?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Вашиот внатрешен екран ќе се отслика. Вашиот преден екран ќе се исклучи."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 8d3a8cc..181e2fd 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ഈ സ്‌പെയ്‌സിൽ നിങ്ങളുടെ വിജറ്റുകൾ ചേർക്കുക, നീക്കം ചെയ്യുക, പുനഃക്രമീകരിക്കുക"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"കൂടുതൽ വിജറ്റുകൾ ചേർക്കുക"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കാൻ ദീർഘനേരം അമർത്തുക"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"നീക്കം ചെയ്യുക"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"വിജറ്റ് ചേർക്കുക"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"പൂർത്തിയായി"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"ഉപയോക്താവിന്റെ സാന്നിധ്യം കണ്ടെത്തി"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string>
     <string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"തുടരാൻ സ്വൈപ്പ് ചെയ്യുക"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ബാഹ്യ ഡിസ്‌പ്ലേയിലേക്ക് മിറർ ചെയ്യണോ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"നിങ്ങളുടെ ഇന്നർ ഡിസ്പ്ലേ മിറർ ചെയ്യും. നിങ്ങളുടെ ഫ്രണ്ട് ഡിസ്പ്ലേ ഓഫാകും."</string>
     <string name="mirror_display" msgid="2515262008898122928">"മിറർ ഡിസ്‌പ്ലേ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 3380af4..8b8265d 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Энэ орон зайд виджетүүдээ нэмэх, хасах болон дахин эрэмбэлэх"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Илүү олон виджет нэмэх"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджетүүдийг өөрчлөхийн тулд удаан дарна уу"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Хасах"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет нэмэх"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Болсон"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Хэрэглэгч байгааг илрүүлсэн"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string>
     <string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Үргэлжлүүлэхийн тулд шударна уу"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Гадны дэлгэцэд тусгал үүсгэх үү?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Таны дотоод дэлгэцийн тусгалыг үүсгэнэ. Таны урд талын дэлгэцийг унтраана."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Дэлгэцийн тусгал үүсгэх"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 58ceb79..b61d408 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"या स्पेसमध्ये तुमची विजेट जोडा, काढून टाका आणि पुन्हा क्रमाने लावा"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"आणखी विजेट जोडा"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट कस्टमाइझ करण्यासाठी प्रेस करून ठेवा"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"काढून टाका"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोडा"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"पूर्ण झाले"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"वापरकर्त्याची उपस्थिती डिटेक्ट केली"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अ‍ॅप सेट करा"</string>
     <string name="install_app" msgid="5066668100199613936">"अ‍ॅप इंस्टॉल करा"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"सुरू ठेवण्यासाठी स्वाइप करा"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेवर मिरर करायचे आहे का?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"तुमचा अंतर्गत डिस्प्ले मिरर केला जाईल. तुमचा पुढील डिस्प्ले बंद केला जाईल."</string>
     <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 04e0170..86c0dd9 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Tambahkan, alih keluar dan susun semula widget anda dalam ruang ini"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tambahkan lagi widget"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Alih keluar"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Selesai"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna dikesan"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string>
     <string name="install_app" msgid="5066668100199613936">"Pasang apl"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Leret untuk meneruskan proses"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Paparkan pada paparan luaran?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Paparan dalaman anda akan dicerminkan. Paparan depan anda akan dimatikan."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Segerakkan paparan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 5b7fa6d..19c9c04 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ဤနေရာတွင် သင့်ဝိဂျက်များကို ထည့်ရန်၊ ဖယ်ရှားရန်၊ ပြန်စီရန်"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"နောက်ထပ်ဝိဂျက်များ ထည့်ရန်"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ဝိဂျက်များ စိတ်ကြိုက်လုပ်ရန် ကြာကြာနှိပ်ထားပါ"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ဖယ်ရှားရန်"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ဝိဂျက်ထည့်ရန်"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ပြီးပြီ"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"အသုံးပြုသူရှိကြောင်း တွေ့ရသည်"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string>
     <string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ရှေ့ဆက်ရန် ပွတ်ဆွဲပါ"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ပြင်ပဖန်သားပြင်သို့ စကရင်ပွားမလား။"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"အတွင်းပြကွက်ကို စကရင်ပွားပါမည်။ ရှေ့မျက်နှာပြင်ပြကွက်ကို ပိတ်မည်။"</string>
     <string name="mirror_display" msgid="2515262008898122928">"ဖန်သားပြင်ကို စကရင်ပွားရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1dd377e..18fba66 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Legg til, fjern og omorganiser modulene i dette området"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Legg til flere moduler"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Trykk lenge for å tilpasse modulene"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Legg til modul"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Ferdig"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Det er registrert at brukeren er til stede"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer appen"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Sveip for å fortsette"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du speile til en ekstern skjerm?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Den indre skjermen speiles. Den ytre skjermen slås av."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Speil skjermen"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 58baede..a192c93 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"यो स्पेसमा आफ्ना विजेटहरू हाल्नुहोस्, हटाउनुहोस् र तिनका क्रम फेरि मिलाउनुहोस्"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"थप विजेटहरू हाल्नुहोस्"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेटहरू कस्टमाइज गर्न केही बेरसम्म थिच्नुहोस्"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाउनुहोस्"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट हाल्नुहोस्"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"पूरा भयो"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"प्रयोगकर्ता उपस्थित भएको कुरा पत्ता लागेको छ"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string>
     <string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"जारी राख्न स्वाइप गर्नुहोस्"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेमा मिरर गर्ने हो?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"तपाईंको भित्री डिस्प्ले मिरर गरिने छ। तपाईंको अगाडिको डिस्प्ले अफ गरिने छ।"</string>
     <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a882a28..d518a87 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Je widgets aan deze ruimte toevoegen, eruit verwijderen of opnieuw ordenen"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Meer widgets toevoegen"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Houd lang ingedrukt om widgets aan te passen"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwijderen"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget toevoegen"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikersaanwezigheid is waargenomen"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string>
     <string name="install_app" msgid="5066668100199613936">"App installeren"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe om door te gaan"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spiegelen naar extern scherm?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Het scherm aan de binnenkant wordt gemirrord. Het scherm aan de voorkant wordt uitgezet."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Scherm spiegelen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 59145d4..38d0bd9 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ଏହି ସ୍ପେସରେ ଆପଣଙ୍କ ୱିଜେଟଗୁଡ଼ିକୁ ଯୋଗ କରନ୍ତୁ, କାଢ଼ି ଦିଅନ୍ତୁ ଏବଂ ରିଅର୍ଡର କରନ୍ତୁ"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ଅଧିକ ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ ଅଧିକ ସମୟ ଦବାନ୍ତୁ"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ହୋଇଗଲା"</string>
@@ -1088,7 +1092,7 @@
     <string name="empty_user_name" msgid="3389155775773578300">"ସାଙ୍ଗମାନେ"</string>
     <string name="empty_status" msgid="5938893404951307749">"ଆଜି ରାତି ଚାଟ କରିବା!"</string>
     <string name="status_before_loading" msgid="1500477307859631381">"ବିଷୟବସ୍ତୁ ଶୀଘ୍ର ଦେଖାଯିବ"</string>
-    <string name="missed_call" msgid="4228016077700161689">"ମିସ୍ଡ କଲ୍"</string>
+    <string name="missed_call" msgid="4228016077700161689">"ମିସ୍ଡ କଲ"</string>
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"ବର୍ତ୍ତମାନର ମେସେଜ, ମିସ୍ଡ କଲ ଏବଂ ସ୍ଥିତି ଅପଡେଟଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"ବାର୍ତ୍ତାଳାପ"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"ୟୁଜରଙ୍କ ଉପସ୍ଥିତି ଚିହ୍ନଟ କରାଯାଇଛି"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string>
     <string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ଜାରି ରଖିବାକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେକୁ ମିରର କରିବେ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ଆପଣଙ୍କ ଇନର ଡିସପ୍ଲେକୁ ମିରର କରାଯିବ। ଆପଣଙ୍କ ଫ୍ରଣ୍ଟ ଡିସପ୍ଲେକୁ ବନ୍ଦ କରାଯିବ।"</string>
     <string name="mirror_display" msgid="2515262008898122928">"ଡିସପ୍ଲେ ମିରର କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index be69c1e..fdbc0e5 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ਇਸ ਜਗ੍ਹਾ ਵਿੱਚ ਆਪਣੇ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ, ਹਟਾਓ ਅਤੇ ਮੁੜ-ਕ੍ਰਮਬੱਧ ਕਰੋ"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ਹੋਰ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ਵਿਜੇਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ਹਟਾਓ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ਹੋ ਗਿਆ"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"ਵਰਤੋਂਕਾਰ ਦੀ ਮੌਜੂਦਗੀ ਦਾ ਪਤਾ ਲਗਾਇਆ ਜਾਂਦਾ ਹੈ"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string>
     <string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ਕੀ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰਨਾ ਹੈ?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ਤੁਹਾਡੀ ਅੰਦਰੂਨੀ ਡਿਸਪਲੇ ਪ੍ਰਤੀਬਿੰਬਤ ਕੀਤੀ ਜਾਵੇਗੀ। ਤੁਹਾਡੀ ਅਗਲੀ ਡਿਸਪਲੇ ਬੰਦ ਕਰ ਦਿੱਤੀ ਜਾਵੇਗੀ।"</string>
     <string name="mirror_display" msgid="2515262008898122928">"ਡਿਸਪਲੇ ਨੂੰ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 192614b..53a1a67c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodawaj widżety, usuwaj je i zmieniaj ich kolejność w tym obszarze"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodaj więcej widżetów"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Przytrzymaj, aby dostosować widżety"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Usuń"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widżet"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotowe"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Wykryto obecność użytkownika"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string>
     <string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Przesuń, aby kontynuować"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Powielić na wyświetlaczu zewnętrznym?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Powstanie odbicie lustrzane Twojego wewnętrznego ekranu. Przedni ekran zostanie wyłączony."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Powielaj obraz"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 3ca10d3..3508558 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicione, remova e reorganize seus widgets neste espaço"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluído"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize para continuar"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Seu display interno será espelhado. O display frontal será desligado."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1656e27..3ac26f0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicionar, remover e reordenar widgets neste espaço"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicionar mais widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha premido para personalizar os widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluir"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Quando deteta a presença do utilizador"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize rapidamente para continuar"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para o ecrã externo?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"O seu ecrã interior vai ser espelhado. O seu ecrã frontal vai ser desativado."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Espelhar ecrã"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 3ca10d3..3508558 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicione, remova e reorganize seus widgets neste espaço"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluído"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize para continuar"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Seu display interno será espelhado. O display frontal será desligado."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index fa2aa1a..7cdc121 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adaugă, elimină și reordonează widgeturile în acest spațiu"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adaugă mai multe widgeturi"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Apasă lung pentru a personaliza widgeturi"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Elimină"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adaugă un widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gata"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"S-a detectat prezența utilizatorului"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Glisează pentru a continua"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Oglindești pe ecranul extern?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ecranul interior va fi oglindit. Ecranul frontal va fi dezactivat."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Afișare în oglindă"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7cb509f..a059e55 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Добавление, удаление и упорядочивание виджетов в этом пространстве"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Добавить виджеты"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Нажмите и удерживайте, чтобы настроить виджеты."</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Удалить"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавить виджет"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Обнаружен пользователь"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string>
     <string name="install_app" msgid="5066668100199613936">"Установить приложение"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Проведите по экрану, чтобы продолжить."</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублировать на внешний дисплей?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Для внутреннего экрана включится дублирование. Передний экран будет отключен."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Дублировать"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 97d1c3d..ad7b241 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"මෙම අවකාශය තුළ ඔබේ විජට් එක් කරන්න, ඉවත් කරන්න, සහ නැවත අනුපිළිවෙල කරන්න"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"තවත් විජට් එක් කරන්න"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"විජට් අභිරුචිකරණය කිරීමට දිගු ඔබන්න"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ඉවත් කරන්න"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"විජට්ටුව එක් කරන්න"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"නිමයි"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"පරිශීලක රූපාකාරය අනාවරණය වේ"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string>
     <string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ඉදිරියට යාමට ස්වයිප් කරන්න"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"බාහිර සංදර්ශකයට දර්පණය කරන්න ද?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ඔබේ අභ්‍යන්තර සංදර්ශකය පිළිබිඹු වනු ඇත. ඔබේ ඉදිරිපස සංදර්ශකය ක්‍රියාවිරහිත වනු ඇත."</string>
     <string name="mirror_display" msgid="2515262008898122928">"සංදර්ශකය දර්පණය කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f1ff09e..e4162db 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Pridávajte aj odstraňujte miniaplikácie a meňte ich poradie v tomto priestore"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pridať ďalšie miniaplikácie"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Miniaplikácie prispôsobíte dlhým stlačením"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrániť"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridať miniaplikáciu"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hotovo"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Bola rozpoznaná prítomnosť používateľa"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string>
     <string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pokračujte potiahnutím"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Chcete zrkadliť na externú obrazovku?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Vnútorná obrazovka bude zrkadlená. Predná obrazovka bude vypnutá."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Zrkadliť obrazovku"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 8a9b624..c8f7dc1 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodajajte, odstranjujte in prerazporejajte pripomočke v tem prostoru"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte več pripomočkov"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pridržite za prilagajanje pripomočkov"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrani"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajanje pripomočka"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Končano"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Zaznana je prisotnost uporabnika"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string>
     <string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Povlecite za nadaljevanje"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite zrcaliti na zunanji zaslon?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Notranji zaslon bo zrcaljen. Sprednji zaslon bo izklopljen."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Zrcali zaslon"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index de68a51..7dd89a1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Shto, hiq dhe rirendit miniaplikacionet e tua në këtë hapësirë"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Shto miniaplikacione të tjera"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Shtyp gjatë për të personalizuar miniaplikacionet"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Hiq"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Shto miniaplikacionin"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"U krye"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Është zbuluar prania e përdoruesit"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string>
     <string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Rrëshqit shpejt për të vazhduar"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Të pasqyrohet në ekranin e jashtëm?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ekrani i brendshëm do të pasqyrohet. Ekrani i parmë do të çaktivizohet."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Pasqyro ekranin"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 28ff0ab..ca43617 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Додајте, уклоните и преуредите виџете у овом простору"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додајте још виџета"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Дуги притисак за прилагођавање виџета"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Уклони"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додај виџет"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Присуство корисника може да се открије"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Превуците да бисте наставили"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Желите ли да пресликате на спољњи екран?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Унутрашњи екран ће се пресликати. Предњи екран ће се искључити."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8bc214f..078942d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Lägg till, ta bort och ordna om dina widgetar i det här rummet"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lägg till fler widgetar"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tryck länge för att anpassa widgetar"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Ta bort"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lägg till widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klar"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Användarnärvaro har upptäckts"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string>
     <string name="install_app" msgid="5066668100199613936">"Installera appen"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Svep för att fortsätta"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vill du spegla till extern skärm?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Den inre skärmen speglas. Den främre skärmen stängs av."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Spegla skärm"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 2aec42e..b056cf7 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Ongeza, ondoa na upange upya wijeti zako katika nafasi hii"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Weka wijeti zingine"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Bonyeza kwa muda mrefu uweke mapendeleo ya wijeti"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Ondoa"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ongeza wijeti"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Nimemaliza"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Imetambua uwepo wa mtumiaji"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string>
     <string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Telezesha kidole ili uendelee"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Ungependa kuonyesha kwenye skrini ya nje?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Mwonekano wa ndani wa kifaa chako utaakisiwa. Mwonekano wa mbele wa kifaa chako utazimwa."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Akisi skrini"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 5319053..42db082 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"இந்த இடத்தில் உங்கள் விட்ஜெட்களைச் சேர்க்கலாம், அகற்றலாம், மறுவரிசைப்படுத்தலாம்"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"கூடுதல் விட்ஜெட்களைச் சேருங்கள்"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"விட்ஜெட்களைப் பிரத்தியேகமாக்க நீண்ட நேரம் அழுத்துக"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"அகற்றும்"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"விட்ஜெட்டைச் சேர்"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"முடிந்தது"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"பயனர் கண்டறியப்பட்டுள்ளார்"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string>
     <string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ஸ்வைப் செய்து தொடரலாம்"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"வெளிப்புறக் காட்சிக்கு மிரர் செய்யவா?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"உங்கள் உட்புற டிஸ்பிளே பிரதிபலிக்கப்படும். உங்கள் முன்புற டிஸ்பிளே முடக்கப்படும்."</string>
     <string name="mirror_display" msgid="2515262008898122928">"டிஸ்பிளேயை மிரர் செய்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index efb8b98..de866a0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ఈ స్పేస్‌లో మీ విడ్జెట్‌లను జోడించండి, తీసివేయండి, క్రమపద్ధతిలో అమర్చండి"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"మరిన్ని విడ్జెట్‌లను జోడించండి"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"విడ్జెట్‌లను అనుకూలీకరించడానికి, నొక్కి, ఉంచండి"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"తీసివేయండి"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"విడ్జెట్‌ను జోడించండి"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"పూర్తయింది"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"యూజర్ ఉనికి గుర్తించబడింది"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్‌లలో ఆటోమేటిక్‌గా ఉండేలా ఒక నోట్స్ యాప్‌ను సెట్ చేసుకోండి"</string>
     <string name="install_app" msgid="5066668100199613936">"యాప్‌ను ఇన్‌స్టాల్ చేయండి"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"కొనసాగించడానికి స్వైప్ చేయండి"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ఎక్స్‌టర్నల్ డిస్‌ప్లే‌కి మిర్రర్‌ చేయాలా?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"మీ లోపలి డిస్‌ప్లే మిర్రర్ చేయబడుతుంది. మీ ముందు వైపు డిస్‌ప్లే ఆఫ్ చేయబడుతుంది."</string>
     <string name="mirror_display" msgid="2515262008898122928">"మిర్రర్ డిస్‌ప్లే"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 78a45d6..341a462 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"เพิ่ม นำออก และจัดลำดับวิดเจ็ตในพื้นที่นี้ใหม่"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"เพิ่มวิดเจ็ตอีก"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"กดค้างเพื่อปรับแต่งวิดเจ็ต"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"นำออก"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"เพิ่มวิดเจ็ต"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"เสร็จสิ้น"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"ตรวจพบการแสดงข้อมูลของผู้ใช้"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string>
     <string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ปัดเพื่อทำต่อ"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"มิเรอร์ไปยังจอแสดงผลภายนอกไหม"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ระบบจะมิเรอร์หน้าจอด้านใน และจะปิดหน้าจอด้านหน้า"</string>
     <string name="mirror_display" msgid="2515262008898122928">"มิเรอร์จอแสดงผล"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9ede0c7..3ac3d3a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Magdagdag, mag-alis, at baguhin ang ayos ng iyong mga widget sa space na ito"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Magdagdag ng higit pang widget"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pindutin nang matagal para i-customize ang mga widget"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Alisin"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Magdagdag ng widget"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Tapos na"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Na-detect ang presensya ng user"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string>
     <string name="install_app" msgid="5066668100199613936">"I-install ang app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Mag-swipe para magpatuloy"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"I-mirror sa external na display?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Imi-mirror ang inner display mo. Io-off ang iyong front display."</string>
     <string name="mirror_display" msgid="2515262008898122928">"I-mirror ang display"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index ef5d06e..9a09961 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Bu alanda widget\'larınızı ekleyin, kaldırın ve yeniden sıralayın"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Daha fazla widget ekle"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widget\'ları özelleştirmek için uzun basın"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Kaldır"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget ekle"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Bitti"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kullanıcı varlığı algılandı"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string>
     <string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Devam etmek için kaydırın"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Harici ekrana yansıtılsın mı?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"İç ekranınız yansıtılacak. Ön ekranınız kapatılacak."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Ekranı yansıt"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 700a8a0..152d93c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Додати, вилучити чи впорядкувати віджети в цьому просторі"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додати більше віджетів"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Утримуйте, щоб налаштувати віджети"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Видалити"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додати віджет"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Виявлено присутність користувача"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string>
     <string name="install_app" msgid="5066668100199613936">"Установити додаток"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Щоб продовжити, проведіть пальцем по екрану"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублювати на зовнішньому екрані?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ваш внутрішній екран буде продубльовано. Передній екран буде вимкнено."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Дублювати екран"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index a1fab6c5..2ec5007 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"اس اسپیس میں اپنے ویجٹس شامل کریں، ہٹائیں اور دوبارہ ترتیب دیں"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"مزید ویجٹس شامل کریں"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ویجٹس کو حسب ضرورت بنانے کے لیے لانگ پریس کریں"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ہٹائیں"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ویجیٹ شامل کریں"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ہو گیا"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"صارف کی موجودگی کا پتہ چلا ہے"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string>
     <string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"جاری رکھنے کے لیے سوائپ کریں"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"بیرونی ڈسپلے پر مرر کریں؟"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"آپ کے اندرونی ڈسپلے کو دو طرفہ مطابقت پذیر بنایا جائے گا۔ آپ کا فرنٹ ڈسپلے آف ہو جائے گا۔"</string>
     <string name="mirror_display" msgid="2515262008898122928">"ڈسپلے کو مرر کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 6478f52..8bcda40 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Bu xonadagi vidjetlaringizni olib tashlang, tartibini oʻzgartiring va yangisini qoʻshing"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Koʻproq vidjetlar qoʻshish"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vidjetlarni sozlash uchun bosib turing"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Olib tashlash"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidjet kiritish"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Tayyor"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Foydalanuvchi aniqlandi"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standart qaydlar ilovasini Sozlamalar orqali tanlang"</string>
     <string name="install_app" msgid="5066668100199613936">"Ilovani oʻrnatish"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Davom etish uchun suring"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tashqi displeyda aks ettirilsinmi?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ichki ekran uchun aks ettirish yoqiladi. Old ekran oʻchiriladi."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Displeyni aks ettirish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e425992..51d9c48 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Thêm, xoá và sắp xếp lại các tiện ích trong không gian này."</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Thêm tiện ích khác"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nhấn và giữ để tuỳ chỉnh tiện ích"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Xoá"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Thêm tiện ích"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Xong"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Phát hiện thấy người dùng đang hiện diện"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string>
     <string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Vuốt để tiếp tục"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Phản chiếu sang màn hình ngoài?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Màn hình trong của bạn sẽ được phản chiếu. Màn hình ngoài của bạn sẽ tắt."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Phản chiếu màn hình"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 1c6fb41..847418a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"在此空间内添加、移除和重新排列您的微件"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"添加更多微件"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"长按即可自定义微件"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"添加微件"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"检测到用户存在"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string>
     <string name="install_app" msgid="5066668100199613936">"安装应用"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"滑动可继续操作"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"镜像到外接显示屏?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"系统将镜像您的内屏,而关闭外屏。"</string>
     <string name="mirror_display" msgid="2515262008898122928">"镜像到显示屏"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index c6a1bd8..b5a6089 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"增、移除小工具,以及調整小工具在此空間中的位置"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"新增更多小工具"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"偵測到使用者動態"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string>
     <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"輕掃即可繼續瀏覽"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要鏡像投射至外部顯示屏嗎?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"鏡像畫面將顯示在內部螢幕,前方螢幕則會關閉。"</string>
     <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5231a06..417b70e 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"新增、移除小工具,以及調整小工具在這個空間中的位置"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"新增更多小工具"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"偵測到使用者"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string>
     <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"滑動畫面繼續瀏覽"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要以鏡像方式投放至外部螢幕嗎?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"鏡像畫面將顯示在內螢幕,封面螢幕則會關閉。"</string>
     <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 10ee16d..795ed38 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -418,6 +418,10 @@
     <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Engeza, susa, futhi uhlele kabusha amawijethi akho kulesi sikhala"</string>
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Engeza amawijethi engeziwe"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Cindezela isikhathi eside ukuze wenze ngokwezifiso amawijethi"</string>
+    <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+    <skip />
+    <!-- no translation found for edit_widget (9030848101135393954) -->
+    <skip />
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Susa"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engeza iwijethi"</string>
     <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Kwenziwe"</string>
@@ -1213,7 +1217,8 @@
     <string name="assistant_attention_content_description" msgid="4166330881435263596">"Ubukhona bomsebenzisi butholakele"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string>
     <string name="install_app" msgid="5066668100199613936">"Faka i-app"</string>
-    <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swayipha ukuze uqhubeke"</string>
+    <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+    <skip />
     <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Fanisa nesibonisi sangaphandle?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Isibonisi sakho sangaphakathi sizoboniswa. Isibonisi sakho sangaphambili sizovalwa."</string>
     <string name="mirror_display" msgid="2515262008898122928">"Isibonisi sokufanisa"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3839dd9..307a619 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -29,6 +29,9 @@
     <color name="status_bar_icons_hover_color_light">#38FFFFFF</color> <!-- 22% white -->
     <color name="status_bar_icons_hover_color_dark">#38000000</color> <!-- 22% black -->
 
+    <!-- The dark background color behind the shade -->
+    <color name="shade_scrim_background_dark">@*android:color/black</color>
+
     <!-- The color of the background in the separated list of the Global Actions menu -->
     <color name="global_actions_separated_background">#F5F5F5</color>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4209c1f..fa89fcd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1249,7 +1249,7 @@
     <dimen name="magnification_drag_corner_margin">8dp</dimen>
     <dimen name="magnification_frame_move_short">5dp</dimen>
     <dimen name="magnification_frame_move_long">25dp</dimen>
-    <dimen name="magnification_drag_view_size">36dp</dimen>
+    <dimen name="magnification_drag_view_size">70dp</dimen>
     <dimen name="magnification_controls_size">90dp</dimen>
     <dimen name="magnification_switch_button_size">56dp</dimen>
     <dimen name="magnification_switch_button_padding">6dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 8ec5ccd..2ab0813 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -184,6 +184,7 @@
     <item type="id" name="action_move_to_edge_and_hide"/>
     <item type="id" name="action_move_out_edge_and_show"/>
     <item type="id" name="action_remove_menu"/>
+    <item type="id" name="action_edit"/>
 
     <!-- rounded corner view id -->
     <item type="id" name="rounded_corner_top_left"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2b43360..7943588 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1077,8 +1077,6 @@
     <!-- Indicator on keyguard to start the communal tutorial. [CHAR LIMIT=100] -->
     <string name="communal_tutorial_indicator_text">Swipe left to start the communal tutorial</string>
 
-    <!-- Description for the button that opens the widget editor on click. [CHAR LIMIT=50] -->
-    <string name="button_to_open_widget_editor">Open the widget editor</string>
     <!-- Text for CTA button that launches the hub mode widget editor on click. [CHAR LIMIT=50] -->
     <string name="cta_tile_button_to_open_widget_editor">Customize</string>
     <!-- Text for CTA button that dismisses the tile on click. [CHAR LIMIT=50] -->
@@ -1750,6 +1748,9 @@
     <!-- Notification: Snooze panel: Snooze undo button label. [CHAR LIMIT=50]-->
     <string name="snooze_undo">Undo</string>
 
+    <!-- Notification: Snooze panel: Snooze undo content description for a11y. [CHAR LIMIT=NONE]-->
+    <string name="snooze_undo_content_description">Undo notification snooze</string>
+
     <!-- Notification: Snooze panel: message indicating how long the notification was snoozed for. [CHAR LIMIT=100]-->
     <string name="snoozed_for_time">Snoozed for <xliff:g id="time_amount" example="15 minutes">%1$s</xliff:g></string>
 
@@ -2560,6 +2561,8 @@
     <string name="accessibility_floating_button_action_remove_menu">Remove</string>
     <!-- Action in accessibility menu to toggle on/off the accessibility feature. [CHAR LIMIT=30]-->
     <string name="accessibility_floating_button_action_double_tap_to_toggle">toggle</string>
+    <!-- Action in accessibility menu to open the shortcut edit menu" [CHAR LIMIT=30]-->
+    <string name="accessibility_floating_button_action_edit">Edit</string>
 
     <!-- Device Controls strings -->
     <!-- Device Controls, Quick Settings tile title [CHAR LIMIT=30] -->
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
index a00cdfa..7c674c8 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
@@ -47,3 +47,14 @@
         FingerprintSensorProperties.TYPE_HOME_BUTTON -> FingerprintSensorType.HOME_BUTTON
         else -> throw IllegalArgumentException("Invalid SensorType value: $this")
     }
+
+/** Convert [this] to corresponding [Int] */
+fun FingerprintSensorType.toInt(): Int =
+    when (this) {
+        FingerprintSensorType.UNKNOWN -> FingerprintSensorProperties.TYPE_UNKNOWN
+        FingerprintSensorType.REAR -> FingerprintSensorProperties.TYPE_REAR
+        FingerprintSensorType.UDFPS_ULTRASONIC -> FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC
+        FingerprintSensorType.UDFPS_OPTICAL -> FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+        FingerprintSensorType.POWER_BUTTON -> FingerprintSensorProperties.TYPE_POWER_BUTTON
+        FingerprintSensorType.HOME_BUTTON -> FingerprintSensorProperties.TYPE_HOME_BUTTON
+    }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index f094102..d4ac195 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -40,7 +40,15 @@
      */
     public static RemoteAnimationTarget[] wrapApps(TransitionInfo info,
             SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
-        return wrap(info, t, leashMap, new TransitionUtil.LeafTaskFilter());
+        // LeafTaskFilter is order-dependent, so the same object needs to be used for all Change
+        // objects. That's why it's constructed here and captured by the lambda instead of building
+        // a new one ad hoc every time.
+        TransitionUtil.LeafTaskFilter taskFilter = new TransitionUtil.LeafTaskFilter();
+        return wrap(info, t, leashMap, (change) -> {
+            // Intra-task activity -> activity transitions should be categorized as apps.
+            if (change.getActivityComponent() != null) return true;
+            return taskFilter.test(change);
+        });
     }
 
     /**
@@ -53,8 +61,12 @@
      */
     public static RemoteAnimationTarget[] wrapNonApps(TransitionInfo info, boolean wallpapers,
             SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
-        return wrap(info, t, leashMap, (change) -> (wallpapers
-                ? TransitionUtil.isWallpaper(change) : TransitionUtil.isNonApp(change)));
+        return wrap(info, t, leashMap, (change) -> {
+            // Intra-task activity -> activity transitions should be categorized as apps.
+            if (change.getActivityComponent() != null) return false;
+            return wallpapers
+                    ? TransitionUtil.isWallpaper(change) : TransitionUtil.isNonApp(change);
+        });
     }
 
     private static RemoteAnimationTarget[] wrap(TransitionInfo info,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index ecce223..25d7713 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -19,9 +19,9 @@
 import static android.app.StatusBarManager.SESSION_KEYGUARD;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 
+import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISSIBLE_KEYGUARD;
 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
-import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISSIBLE_KEYGUARD;
 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_PASSWORD;
 import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_SIM;
@@ -84,6 +84,7 @@
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.KeyguardWmStateRefactor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.ActivityStarter;
@@ -100,8 +101,6 @@
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.GlobalSettings;
 
-import dagger.Lazy;
-
 import java.io.File;
 import java.util.Arrays;
 import java.util.Optional;
@@ -109,6 +108,7 @@
 import javax.inject.Inject;
 import javax.inject.Provider;
 
+import dagger.Lazy;
 import kotlinx.coroutines.Job;
 
 /** Controller for {@link KeyguardSecurityContainer} */
@@ -330,7 +330,7 @@
                 }
             }
 
-            if (mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (KeyguardWmStateRefactor.isEnabled()) {
                 mKeyguardTransitionInteractor.startDismissKeyguardTransition();
             }
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index d5dc85c..8e98150 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -63,6 +63,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
+import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -87,6 +88,8 @@
 
 import javax.inject.Inject;
 
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
+
 /**
  * Controls when to show the LockIcon affordance (lock/unlocked icon or circle) on lock screen.
  *
@@ -717,6 +720,7 @@
         return mDownDetected;
     }
 
+    @ExperimentalCoroutinesApi
     @VisibleForTesting
     protected void onLongPress() {
         cancelTouches();
@@ -727,7 +731,8 @@
 
         // pre-emptively set to true to hide view
         mIsBouncerShowing = true;
-        if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
+        if (!DeviceEntryUdfpsRefactor.isEnabled()
+                && mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
             mAuthRippleController.showUnlockRipple(FINGERPRINT);
         }
         updateVisibility();
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 76f93e1..a81c1b0 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -26,6 +26,7 @@
 import android.graphics.drawable.VectorDrawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 import androidx.annotation.Nullable;
 
@@ -145,4 +146,10 @@
             mAnimator = null;
         }
     }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setTextEntryKey(true);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 871d57d..dcfa775 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -30,7 +30,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.TextView;
 
 import androidx.annotation.Nullable;
@@ -105,8 +105,6 @@
         }
 
         setOnClickListener(mListener);
-        setOnHoverListener(new LiftToActivateListener(
-                (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE)));
 
         mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
@@ -240,4 +238,10 @@
     public void setAnimationEnabled(boolean enabled) {
         mAnimationsEnabled = enabled;
     }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setTextEntryKey(true);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index bddf3b0..d2ad096 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -97,6 +97,26 @@
         )
     }
 
+    fun logUpdateLockScreenUserLockedMsg(
+        userId: Int,
+        userUnlocked: Boolean,
+        encryptedOrLockdown: Boolean,
+    ) {
+        buffer.log(
+            KeyguardIndicationController.TAG,
+            LogLevel.DEBUG,
+            {
+                int1 = userId
+                bool1 = userUnlocked
+                bool2 = encryptedOrLockdown
+            },
+            {
+                "updateLockScreenUserLockedMsg userId=$int1 " +
+                    "userUnlocked:$bool1 encryptedOrLockdown:$bool2"
+            }
+        )
+    }
+
     fun logUpdateBatteryIndication(
         powerIndication: String,
         pluggedIn: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 4372826..0f5f869 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -20,12 +20,11 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.pm.UserInfo;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
 import android.os.UserHandle;
 
 import androidx.annotation.NonNull;
 
+import com.android.systemui.res.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.GuestResetOrExitSessionReceiver.ResetSessionDialogFactory;
@@ -33,7 +32,6 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.qs.QSUserSwitcherEvent;
-import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -63,7 +61,6 @@
     private final SecureSettings mSecureSettings;
     private final ResetSessionDialogFactory mResetSessionDialogFactory;
     private final GuestSessionNotification mGuestSessionNotification;
-    private final HandlerThread mHandlerThread;
 
     @VisibleForTesting
     public final UserTracker.Callback mUserChangedCallback =
@@ -114,16 +111,13 @@
         mSecureSettings = secureSettings;
         mGuestSessionNotification = guestSessionNotification;
         mResetSessionDialogFactory = resetSessionDialogFactory;
-        mHandlerThread = new HandlerThread("GuestResumeSessionReceiver");
-        mHandlerThread.start();
     }
 
     /**
      * Register this receiver with the {@link BroadcastDispatcher}
      */
     public void register() {
-        mUserTracker.addCallback(mUserChangedCallback,
-                  new HandlerExecutor(mHandlerThread.getThreadHandler()));
+        mUserTracker.addCallback(mUserChangedCallback, mMainExecutor);
     }
 
     private void cancelDialog() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
index 3ca95e1..5171a1f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
@@ -19,6 +19,7 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 
 import static com.android.systemui.accessibility.AccessibilityLogger.MagnificationSettingsEvent;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
@@ -28,10 +29,12 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
+import android.os.Binder;
 import android.os.Handler;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IMagnificationConnection;
@@ -40,6 +43,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.systemui.CoreStartable;
+import com.android.systemui.Flags;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.model.SysUiState;
@@ -49,6 +53,7 @@
 import com.android.systemui.util.settings.SecureSettings;
 
 import java.io.PrintWriter;
+import java.util.function.Supplier;
 
 import javax.inject.Inject;
 
@@ -101,19 +106,28 @@
         @Override
         protected WindowMagnificationController createInstance(Display display) {
             final Context windowContext = mContext.createWindowContext(display,
-                    TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
+                    Flags.createWindowlessWindowMagnifier()
+                            ? TYPE_ACCESSIBILITY_OVERLAY
+                            : TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
+                    /* options */ null);
             windowContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI);
+
+            Supplier<SurfaceControlViewHost> scvhSupplier = () ->
+                    Flags.createWindowlessWindowMagnifier() ? new SurfaceControlViewHost(mContext,
+                            mContext.getDisplay(), new Binder(), TAG) : null;
+
             return new WindowMagnificationController(
                     windowContext,
                     mHandler,
                     new WindowMagnificationAnimationController(windowContext),
-                    new SfVsyncFrameCallbackProvider(),
-                    null,
+                    /* mirrorWindowControl= */ null,
                     new SurfaceControl.Transaction(),
                     mWindowMagnifierCallback,
                     mSysUiState,
-                    WindowManagerGlobal::getWindowSession,
-                    mSecureSettings);
+                    mSecureSettings,
+                    scvhSupplier,
+                    new SfVsyncFrameCallbackProvider(),
+                    WindowManagerGlobal::getWindowSession);
         }
     }
 
@@ -140,7 +154,7 @@
         @Override
         protected MagnificationSettingsController createInstance(Display display) {
             final Context windowContext = mContext.createWindowContext(display,
-                    TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
+                    TYPE_ACCESSIBILITY_OVERLAY, /* options */ null);
             windowContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI);
             return new MagnificationSettingsController(
                     windowContext,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index dde9f48..d65cd5c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -63,23 +63,27 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowMetrics;
+import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.IRemoteMagnificationAnimationCallback;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import androidx.annotation.UiThread;
 import androidx.core.math.MathUtils;
 
 import com.android.internal.accessibility.common.MagnificationConstants;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.systemui.Flags;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.res.R;
 import com.android.systemui.util.settings.SecureSettings;
@@ -158,6 +162,15 @@
     private int mMagnificationFrameOffsetX = 0;
     private int mMagnificationFrameOffsetY = 0;
 
+    @Nullable private Supplier<SurfaceControlViewHost> mScvhSupplier;
+
+    /**
+     * SurfaceControlViewHost is used to control the position of the window containing
+     * {@link #mMirrorView}. Using SurfaceControlViewHost instead of a regular window enables
+     * changing the window's position and setting {@link #mMirrorSurface}'s geometry atomically.
+     */
+    private SurfaceControlViewHost mSurfaceControlViewHost;
+
     // The root of the mirrored content
     private SurfaceControl mMirrorSurface;
 
@@ -236,21 +249,21 @@
             @UiContext Context context,
             @NonNull Handler handler,
             @NonNull WindowMagnificationAnimationController animationController,
-            SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
             MirrorWindowControl mirrorWindowControl,
             SurfaceControl.Transaction transaction,
             @NonNull WindowMagnifierCallback callback,
             SysUiState sysUiState,
-            @NonNull Supplier<IWindowSession> globalWindowSessionSupplier,
-            SecureSettings secureSettings) {
+            SecureSettings secureSettings,
+            Supplier<SurfaceControlViewHost> scvhSupplier,
+            SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
+            Supplier<IWindowSession> globalWindowSessionSupplier) {
         mContext = context;
         mHandler = handler;
         mAnimationController = animationController;
-        mGlobalWindowSessionSupplier = globalWindowSessionSupplier;
         mAnimationController.setWindowMagnificationController(this);
-        mSfVsyncFrameProvider = sfVsyncFrameProvider;
         mWindowMagnifierCallback = callback;
         mSysUiState = sysUiState;
+        mScvhSupplier = scvhSupplier;
         mConfiguration = new Configuration(context.getResources().getConfiguration());
         mWindowMagnificationSizePrefs = new WindowMagnificationSizePrefs(mContext);
 
@@ -288,22 +301,78 @@
         mTransaction = transaction;
         mGestureDetector =
                 new MagnificationGestureDetector(mContext, handler, this);
+        mWindowInsetChangeRunnable = this::onWindowInsetChanged;
+        mGlobalWindowSessionSupplier = globalWindowSessionSupplier;
+        mSfVsyncFrameProvider = sfVsyncFrameProvider;
 
         // Initialize listeners.
-        mMirrorViewRunnable = () -> {
-            if (mMirrorView != null) {
-                final Rect oldViewBounds = new Rect(mMirrorViewBounds);
-                mMirrorView.getBoundsOnScreen(mMirrorViewBounds);
-                if (oldViewBounds.width() != mMirrorViewBounds.width()
-                        || oldViewBounds.height() != mMirrorViewBounds.height()) {
-                    mMirrorView.setSystemGestureExclusionRects(Collections.singletonList(
-                            new Rect(0, 0, mMirrorViewBounds.width(), mMirrorViewBounds.height())));
+        if (Flags.createWindowlessWindowMagnifier()) {
+            mMirrorViewRunnable = new Runnable() {
+                final Rect mPreviousBounds = new Rect();
+
+                @Override
+                public void run() {
+                    if (mMirrorView != null) {
+                        if (mPreviousBounds.width() != mMirrorViewBounds.width()
+                                || mPreviousBounds.height() != mMirrorViewBounds.height()) {
+                            mMirrorView.setSystemGestureExclusionRects(Collections.singletonList(
+                                    new Rect(0, 0, mMirrorViewBounds.width(),
+                                            mMirrorViewBounds.height())));
+                            mPreviousBounds.set(mMirrorViewBounds);
+                        }
+                        updateSystemUIStateIfNeeded();
+                        mWindowMagnifierCallback.onWindowMagnifierBoundsChanged(
+                                mDisplayId, mMirrorViewBounds);
+                    }
                 }
-                updateSystemUIStateIfNeeded();
-                mWindowMagnifierCallback.onWindowMagnifierBoundsChanged(
-                        mDisplayId, mMirrorViewBounds);
-            }
-        };
+            };
+
+            mMirrorSurfaceViewLayoutChangeListener =
+                    (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+                            mMirrorView.post(this::applyTapExcludeRegion);
+
+            mMirrorViewGeometryVsyncCallback = null;
+        } else {
+            mMirrorViewRunnable = () -> {
+                if (mMirrorView != null) {
+                    final Rect oldViewBounds = new Rect(mMirrorViewBounds);
+                    mMirrorView.getBoundsOnScreen(mMirrorViewBounds);
+                    if (oldViewBounds.width() != mMirrorViewBounds.width()
+                            || oldViewBounds.height() != mMirrorViewBounds.height()) {
+                        mMirrorView.setSystemGestureExclusionRects(Collections.singletonList(
+                                new Rect(0, 0,
+                                        mMirrorViewBounds.width(), mMirrorViewBounds.height())));
+                    }
+                    updateSystemUIStateIfNeeded();
+                    mWindowMagnifierCallback.onWindowMagnifierBoundsChanged(
+                            mDisplayId, mMirrorViewBounds);
+                }
+            };
+
+            mMirrorSurfaceViewLayoutChangeListener =
+                    (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+                            mMirrorView.post(this::applyTapExcludeRegion);
+
+            mMirrorViewGeometryVsyncCallback =
+                    l -> {
+                        if (isActivated() && mMirrorSurface != null && calculateSourceBounds(
+                                mMagnificationFrame, mScale)) {
+                            // The final destination for the magnification surface should be at 0,0
+                            // since the ViewRootImpl's position will change
+                            mTmpRect.set(0, 0, mMagnificationFrame.width(),
+                                    mMagnificationFrame.height());
+                            mTransaction.setGeometry(mMirrorSurface, mSourceBounds, mTmpRect,
+                                    Surface.ROTATION_0).apply();
+
+                            // Notify source bounds change when the magnifier is not animating.
+                            if (!mAnimationController.isAnimating()) {
+                                mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId,
+                                        mSourceBounds);
+                            }
+                        }
+                    };
+        }
+
         mMirrorViewLayoutChangeListener =
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                     if (!mHandler.hasCallbacks(mMirrorViewRunnable)) {
@@ -311,34 +380,11 @@
                     }
                 };
 
-        mMirrorSurfaceViewLayoutChangeListener =
-                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
-                        mMirrorView.post(this::applyTapExcludeRegion);
-
-        mMirrorViewGeometryVsyncCallback =
-                l -> {
-                    if (isActivated() && mMirrorSurface != null && calculateSourceBounds(
-                            mMagnificationFrame, mScale)) {
-                        // The final destination for the magnification surface should be at 0,0
-                        // since the ViewRootImpl's position will change
-                        mTmpRect.set(0, 0, mMagnificationFrame.width(),
-                                mMagnificationFrame.height());
-                        mTransaction.setGeometry(mMirrorSurface, mSourceBounds, mTmpRect,
-                                Surface.ROTATION_0).apply();
-
-                        // Notify source bounds change when the magnifier is not animating.
-                        if (!mAnimationController.isAnimating()) {
-                            mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId,
-                                    mSourceBounds);
-                        }
-                    }
-                };
         mUpdateStateDescriptionRunnable = () -> {
             if (isActivated()) {
                 mMirrorView.setStateDescription(formatStateDescription(mScale));
             }
         };
-        mWindowInsetChangeRunnable = this::onWindowInsetChanged;
     }
 
     private void setupMagnificationSizeScaleOptions() {
@@ -448,13 +494,21 @@
         if (mMirrorView != null) {
             mHandler.removeCallbacks(mMirrorViewRunnable);
             mMirrorView.removeOnLayoutChangeListener(mMirrorViewLayoutChangeListener);
-            mWm.removeView(mMirrorView);
+            if (!Flags.createWindowlessWindowMagnifier()) {
+                mWm.removeView(mMirrorView);
+            }
             mMirrorView = null;
         }
 
         if (mMirrorWindowControl != null) {
             mMirrorWindowControl.destroyControl();
         }
+
+        if (mSurfaceControlViewHost != null) {
+            mSurfaceControlViewHost.release();
+            mSurfaceControlViewHost = null;
+        }
+
         mMirrorViewBounds.setEmpty();
         mSourceBounds.setEmpty();
         updateSystemUIStateIfNeeded();
@@ -551,7 +605,11 @@
         if (!isActivated()) return;
         LayoutParams params = (LayoutParams) mMirrorView.getLayoutParams();
         params.accessibilityTitle = getAccessibilityWindowTitle();
-        mWm.updateViewLayout(mMirrorView, params);
+        if (Flags.createWindowlessWindowMagnifier()) {
+            mSurfaceControlViewHost.relayout(params);
+        } else {
+            mWm.updateViewLayout(mMirrorView, params);
+        }
     }
 
     /**
@@ -602,6 +660,11 @@
     }
 
     private void createMirrorWindow() {
+        if (Flags.createWindowlessWindowMagnifier()) {
+            createWindowlessMirrorWindow();
+            return;
+        }
+
         // The window should be the size the mirrored surface will be but also add room for the
         // border and the drag handle.
         int windowWidth = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin;
@@ -652,6 +715,68 @@
         addDragTouchListeners();
     }
 
+    private void createWindowlessMirrorWindow() {
+        // The window should be the size the mirrored surface will be but also add room for the
+        // border and the drag handle.
+        int windowWidth = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin;
+        int windowHeight = mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin;
+
+        // TODO delete TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, it shouldn't be needed anymore
+
+        LayoutParams params = new LayoutParams(
+                windowWidth, windowHeight,
+                LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
+                LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.TRANSPARENT);
+        params.receiveInsetsIgnoringZOrder = true;
+        params.setTitle(mContext.getString(R.string.magnification_window_title));
+        params.accessibilityTitle = getAccessibilityWindowTitle();
+        params.setTrustedOverlay();
+
+        mMirrorView = LayoutInflater.from(mContext).inflate(R.layout.window_magnifier_view, null);
+        mMirrorSurfaceView = mMirrorView.findViewById(R.id.surface_view);
+
+        mMirrorBorderView = mMirrorView.findViewById(R.id.magnification_inner_border);
+
+        // Allow taps to go through to the mirror SurfaceView below.
+        mMirrorSurfaceView.addOnLayoutChangeListener(mMirrorSurfaceViewLayoutChangeListener);
+
+        mMirrorView.addOnLayoutChangeListener(mMirrorViewLayoutChangeListener);
+        mMirrorView.setAccessibilityDelegate(new MirrorWindowA11yDelegate());
+        mMirrorView.setOnApplyWindowInsetsListener((v, insets) -> {
+            if (!mHandler.hasCallbacks(mWindowInsetChangeRunnable)) {
+                mHandler.post(mWindowInsetChangeRunnable);
+            }
+            return v.onApplyWindowInsets(insets);
+        });
+
+        mSurfaceControlViewHost = mScvhSupplier.get();
+        mSurfaceControlViewHost.setView(mMirrorView, params);
+        SurfaceControl surfaceControl = mSurfaceControlViewHost
+                .getSurfacePackage().getSurfaceControl();
+
+        int x = mMagnificationFrame.left - mMirrorSurfaceMargin;
+        int y = mMagnificationFrame.top - mMirrorSurfaceMargin;
+        mTransaction
+                .setCrop(surfaceControl, new Rect(0, 0, windowWidth, windowHeight))
+                .setPosition(surfaceControl, x, y)
+                .setLayer(surfaceControl, Integer.MAX_VALUE)
+                .show(surfaceControl)
+                .apply();
+
+        mMirrorViewBounds.set(x, y, x + windowWidth, y + windowHeight);
+
+        AccessibilityManager accessibilityManager = mContext
+                .getSystemService(AccessibilityManager.class);
+        accessibilityManager.attachAccessibilityOverlayToDisplay(mDisplayId, surfaceControl);
+
+        SurfaceHolder holder = mMirrorSurfaceView.getHolder();
+        holder.addCallback(this);
+        holder.setFormat(PixelFormat.RGBA_8888);
+        addDragTouchListeners();
+    }
+
     private void onWindowInsetChanged() {
         if (updateSystemGestureInsetsTop()) {
             updateSystemUIStateIfNeeded();
@@ -659,6 +784,11 @@
     }
 
     private void applyTapExcludeRegion() {
+        if (Flags.createWindowlessWindowMagnifier()) {
+            applyTouchableRegion();
+            return;
+        }
+
         // Sometimes this can get posted and run after deleteWindowMagnification() is called.
         if (mMirrorView == null) return;
 
@@ -709,6 +839,51 @@
         return regionInsideDragBorder;
     }
 
+    private void applyTouchableRegion() {
+        // Sometimes this can get posted and run after deleteWindowMagnification() is called.
+        if (mMirrorView == null) return;
+
+        var surfaceControl = mSurfaceControlViewHost.getRootSurfaceControl();
+        surfaceControl.setTouchableRegion(calculateTouchableRegion());
+    }
+
+    private Region calculateTouchableRegion() {
+        Region touchableRegion = new Region(0, 0, mMirrorView.getWidth(), mMirrorView.getHeight());
+
+        Region regionInsideDragBorder = new Region(mBorderDragSize, mBorderDragSize,
+                mMirrorView.getWidth() - mBorderDragSize,
+                mMirrorView.getHeight() - mBorderDragSize);
+        touchableRegion.op(regionInsideDragBorder, Region.Op.DIFFERENCE);
+
+        Rect dragArea = new Rect();
+        mDragView.getHitRect(dragArea);
+
+        Rect topLeftArea = new Rect();
+        mTopLeftCornerView.getHitRect(topLeftArea);
+
+        Rect topRightArea = new Rect();
+        mTopRightCornerView.getHitRect(topRightArea);
+
+        Rect bottomLeftArea = new Rect();
+        mBottomLeftCornerView.getHitRect(bottomLeftArea);
+
+        Rect bottomRightArea = new Rect();
+        mBottomRightCornerView.getHitRect(bottomRightArea);
+
+        Rect closeArea = new Rect();
+        mCloseView.getHitRect(closeArea);
+
+        // Add touchable regions for drag and close
+        touchableRegion.op(dragArea, Region.Op.UNION);
+        touchableRegion.op(topLeftArea, Region.Op.UNION);
+        touchableRegion.op(topRightArea, Region.Op.UNION);
+        touchableRegion.op(bottomLeftArea, Region.Op.UNION);
+        touchableRegion.op(bottomRightArea, Region.Op.UNION);
+        touchableRegion.op(closeArea, Region.Op.UNION);
+
+        return touchableRegion;
+    }
+
     private String getAccessibilityWindowTitle() {
         return mResources.getString(com.android.internal.R.string.android_system_label);
     }
@@ -852,8 +1027,84 @@
      * {@link #mMagnificationFrame}.
      */
     private void modifyWindowMagnification(boolean computeWindowSize) {
-        mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
-        updateMirrorViewLayout(computeWindowSize);
+        if (Flags.createWindowlessWindowMagnifier()) {
+            updateMirrorSurfaceGeometry();
+            updateWindowlessMirrorViewLayout(computeWindowSize);
+        } else {
+            mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
+            updateMirrorViewLayout(computeWindowSize);
+        }
+    }
+
+    /**
+     * Updates {@link #mMirrorSurface}'s geometry. This modifies {@link #mTransaction} but does not
+     * apply it.
+     */
+    @UiThread
+    private void updateMirrorSurfaceGeometry() {
+        if (isActivated() && mMirrorSurface != null
+                && calculateSourceBounds(mMagnificationFrame, mScale)) {
+            // The final destination for the magnification surface should be at 0,0
+            // since the ViewRootImpl's position will change
+            mTmpRect.set(0, 0, mMagnificationFrame.width(), mMagnificationFrame.height());
+            mTransaction.setGeometry(mMirrorSurface, mSourceBounds, mTmpRect, Surface.ROTATION_0);
+
+            // Notify source bounds change when the magnifier is not animating.
+            if (!mAnimationController.isAnimating()) {
+                mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId, mSourceBounds);
+            }
+        }
+    }
+
+    /**
+     * Updates the position of {@link mSurfaceControlViewHost} and layout params of MirrorView based
+     * on the position and size of {@link #mMagnificationFrame}.
+     *
+     * @param computeWindowSize set to {@code true} to compute window size with
+     * {@link #mMagnificationFrame}.
+     */
+    @UiThread
+    private void updateWindowlessMirrorViewLayout(boolean computeWindowSize) {
+        if (!isActivated()) {
+            return;
+        }
+
+        final int width = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin;
+        final int height = mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin;
+
+        final int minX = -mOuterBorderSize;
+        final int maxX = mWindowBounds.right - width + mOuterBorderSize;
+        final int x = MathUtils.clamp(mMagnificationFrame.left - mMirrorSurfaceMargin, minX, maxX);
+
+        final int minY = -mOuterBorderSize;
+        final int maxY = mWindowBounds.bottom - height + mOuterBorderSize;
+        final int y = MathUtils.clamp(mMagnificationFrame.top - mMirrorSurfaceMargin, minY, maxY);
+
+        if (computeWindowSize) {
+            LayoutParams params = (LayoutParams) mMirrorView.getLayoutParams();
+            params.width = width;
+            params.height = height;
+            mSurfaceControlViewHost.relayout(params);
+            mTransaction.setCrop(mSurfaceControlViewHost.getSurfacePackage().getSurfaceControl(),
+                    new Rect(0, 0, width, height));
+        }
+
+        mMirrorViewBounds.set(x, y, x + width, y + height);
+        mTransaction.setPosition(
+                mSurfaceControlViewHost.getSurfacePackage().getSurfaceControl(), x, y);
+        if (computeWindowSize) {
+            mSurfaceControlViewHost.getRootSurfaceControl().applyTransactionOnDraw(mTransaction);
+        } else {
+            mTransaction.apply();
+        }
+
+        // If they are not dragging the handle, we can move the drag handle immediately without
+        // disruption. But if they are dragging it, we avoid moving until the end of the drag.
+        if (!mIsDragging) {
+            mMirrorView.post(this::maybeRepositionButton);
+        }
+
+        mMirrorViewRunnable.run();
     }
 
     /**
@@ -1094,7 +1345,7 @@
 
     /**
      * Enables window magnification with specified parameters. If the given scale is <strong>less
-     * than or equal to 1.0f<strong>, then
+     * than or equal to 1.0f</strong>, then
      * {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
      * be consistent with the behavior of display magnification.
      *
@@ -1110,7 +1361,7 @@
 
     /**
      * Enables window magnification with specified parameters. If the given scale is <strong>less
-     * than 1.0f<strong>, then
+     * than 1.0f</strong>, then
      * {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
      * be consistent with the behavior of display magnification.
      *
@@ -1426,10 +1677,8 @@
         final FrameLayout.LayoutParams layoutParams =
                 (FrameLayout.LayoutParams) mDragView.getLayoutParams();
 
-        mMirrorView.getBoundsOnScreen(mTmpRect);
-
         final int newGravity;
-        if (mTmpRect.right >= screenEdgeX) {
+        if (mMirrorViewBounds.right >= screenEdgeX) {
             newGravity = Gravity.BOTTOM | Gravity.LEFT;
         } else {
             newGravity = Gravity.BOTTOM | Gravity.RIGHT;
@@ -1449,8 +1698,8 @@
         mSettingsPanelVisibility = settingsPanelIsShown;
 
         mDragView.setBackground(mContext.getResources().getDrawable(settingsPanelIsShown
-                ? R.drawable.accessibility_window_magnification_drag_handle_background_change
-                : R.drawable.accessibility_window_magnification_drag_handle_background));
+                ? R.drawable.accessibility_window_magnification_drag_handle_background_change_inset
+                : R.drawable.accessibility_window_magnification_drag_handle_background_inset));
 
         PorterDuffColorFilter filter = new PorterDuffColorFilter(
                 mContext.getColor(settingsPanelIsShown
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java
index 568b24d..7fd72ec 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java
@@ -16,127 +16,138 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
+import static android.R.id.empty;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.util.ArrayMap;
+import android.util.Pair;
 import android.view.MotionEvent;
 
 import androidx.annotation.NonNull;
 import androidx.dynamicanimation.animation.DynamicAnimation;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Flags;
+import com.android.wm.shell.common.bubbles.DismissCircleView;
 import com.android.wm.shell.common.bubbles.DismissView;
 import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
 
+import java.util.Map;
+import java.util.Objects;
+
 /**
  * Controls the interaction between {@link MagnetizedObject} and
  * {@link MagnetizedObject.MagneticTarget}.
  */
 class DragToInteractAnimationController {
-    private static final boolean ENABLE_FLING_TO_DISMISS_MENU = false;
     private static final float COMPLETELY_OPAQUE = 1.0f;
     private static final float COMPLETELY_TRANSPARENT = 0.0f;
     private static final float CIRCLE_VIEW_DEFAULT_SCALE = 1.0f;
     private static final float ANIMATING_MAX_ALPHA = 0.7f;
 
+    private final DragToInteractView mInteractView;
     private final DismissView mDismissView;
     private final MenuView mMenuView;
-    private final ValueAnimator mDismissAnimator;
-    private final MagnetizedObject<?> mMagnetizedObject;
-    private float mMinDismissSize;
+
+    /**
+     * MagnetizedObject cannot differentiate between its MagnetizedTargets,
+     * so we need an object & an animator for every interactable.
+     */
+    private final ArrayMap<Integer, Pair<MagnetizedObject<MenuView>, ValueAnimator>> mInteractMap;
+
+    private float mMinInteractSize;
     private float mSizePercent;
 
+    DragToInteractAnimationController(DragToInteractView interactView, MenuView menuView) {
+        mDismissView = null;
+        mInteractView = interactView;
+        mInteractView.setPivotX(interactView.getWidth() / 2.0f);
+        mInteractView.setPivotY(interactView.getHeight() / 2.0f);
+        mMenuView = menuView;
+
+        updateResources();
+
+        mInteractMap = new ArrayMap<>();
+        interactView.getInteractMap().forEach((viewId, pair) -> {
+            DismissCircleView circleView = pair.getFirst();
+            createMagnetizedObjectAndAnimator(circleView);
+        });
+    }
+
     DragToInteractAnimationController(DismissView dismissView, MenuView menuView) {
         mDismissView = dismissView;
+        mInteractView = null;
         mDismissView.setPivotX(dismissView.getWidth() / 2.0f);
         mDismissView.setPivotY(dismissView.getHeight() / 2.0f);
         mMenuView = menuView;
 
         updateResources();
 
-        mDismissAnimator = ValueAnimator.ofFloat(COMPLETELY_OPAQUE, COMPLETELY_TRANSPARENT);
-        mDismissAnimator.addUpdateListener(dismissAnimation -> {
-            final float animatedValue = (float) dismissAnimation.getAnimatedValue();
-            final float scaleValue = Math.max(animatedValue, mSizePercent);
-            dismissView.getCircle().setScaleX(scaleValue);
-            dismissView.getCircle().setScaleY(scaleValue);
-
-            menuView.setAlpha(Math.max(animatedValue, ANIMATING_MAX_ALPHA));
-        });
-
-        mDismissAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
-                super.onAnimationEnd(animation, isReverse);
-
-                if (isReverse) {
-                    mDismissView.getCircle().setScaleX(CIRCLE_VIEW_DEFAULT_SCALE);
-                    mDismissView.getCircle().setScaleY(CIRCLE_VIEW_DEFAULT_SCALE);
-                    mMenuView.setAlpha(COMPLETELY_OPAQUE);
-                }
-            }
-        });
-
-        mMagnetizedObject =
-                new MagnetizedObject<MenuView>(mMenuView.getContext(), mMenuView,
-                        new MenuAnimationController.MenuPositionProperty(
-                                DynamicAnimation.TRANSLATION_X),
-                        new MenuAnimationController.MenuPositionProperty(
-                                DynamicAnimation.TRANSLATION_Y)) {
-                    @Override
-                    public void getLocationOnScreen(MenuView underlyingObject, int[] loc) {
-                        underlyingObject.getLocationOnScreen(loc);
-                    }
-
-                    @Override
-                    public float getHeight(MenuView underlyingObject) {
-                        return underlyingObject.getHeight();
-                    }
-
-                    @Override
-                    public float getWidth(MenuView underlyingObject) {
-                        return underlyingObject.getWidth();
-                    }
-                };
-
-        final MagnetizedObject.MagneticTarget magneticTarget = new MagnetizedObject.MagneticTarget(
-                dismissView.getCircle(), (int) mMinDismissSize);
-        mMagnetizedObject.addTarget(magneticTarget);
-        mMagnetizedObject.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_MENU);
+        mInteractMap = new ArrayMap<>();
+        createMagnetizedObjectAndAnimator(dismissView.getCircle());
     }
 
-    void showDismissView(boolean show) {
-        if (show) {
-            mDismissView.show();
-        } else {
-            mDismissView.hide();
+    void showInteractView(boolean show) {
+        if (Flags.floatingMenuDragToEdit() && mInteractView != null) {
+            if (show) {
+                mInteractView.show();
+            } else {
+                mInteractView.hide();
+            }
+        } else if (mDismissView != null) {
+            if (show) {
+                mDismissView.show();
+            } else {
+                mDismissView.hide();
+            }
         }
     }
 
     void setMagnetListener(MagnetizedObject.MagnetListener magnetListener) {
-        mMagnetizedObject.setMagnetListener(magnetListener);
+        mInteractMap.forEach((viewId, pair) -> {
+            MagnetizedObject<?> magnetizedObject = pair.first;
+            magnetizedObject.setMagnetListener(magnetListener);
+        });
     }
 
     @VisibleForTesting
-    MagnetizedObject.MagnetListener getMagnetListener() {
-        return mMagnetizedObject.getMagnetListener();
+    MagnetizedObject.MagnetListener getMagnetListener(int id) {
+        return Objects.requireNonNull(mInteractMap.get(id)).first.getMagnetListener();
     }
 
     void maybeConsumeDownMotionEvent(MotionEvent event) {
-        mMagnetizedObject.maybeConsumeMotionEvent(event);
+        mInteractMap.forEach((viewId, pair) -> {
+            MagnetizedObject<?> magnetizedObject = pair.first;
+            magnetizedObject.maybeConsumeMotionEvent(event);
+        });
+    }
+
+    private int maybeConsumeMotionEvent(MotionEvent event) {
+        for (Map.Entry<Integer, Pair<MagnetizedObject<MenuView>, ValueAnimator>> set:
+                mInteractMap.entrySet()) {
+            MagnetizedObject<MenuView> magnetizedObject = set.getValue().first;
+            if (magnetizedObject.maybeConsumeMotionEvent(event)) {
+                return set.getKey();
+            }
+        }
+        return empty;
     }
 
     /**
-     * This used to pass {@link MotionEvent#ACTION_DOWN} to the magnetized object to check if it was
-     * within the magnetic field. It should be used in the {@link MenuListViewTouchHandler}.
+     * This used to pass {@link MotionEvent#ACTION_DOWN} to the magnetized objects
+     * to check if it was within a magnetic field.
+     * It should be used in the {@link MenuListViewTouchHandler}.
      *
      * @param event that move the magnetized object which is also the menu list view.
-     * @return true if the location of the motion events moves within the magnetic field of a
-     * target, but false if didn't set
+     * @return id of a target if the location of the motion events moves
+     * within the field of the target, otherwise it returns{@link android.R.id#empty}.
+     * <p>
      * {@link DragToInteractAnimationController#setMagnetListener(MagnetizedObject.MagnetListener)}.
      */
-    boolean maybeConsumeMoveMotionEvent(MotionEvent event) {
-        return mMagnetizedObject.maybeConsumeMotionEvent(event);
+    int maybeConsumeMoveMotionEvent(MotionEvent event) {
+        return maybeConsumeMotionEvent(event);
     }
 
     /**
@@ -144,31 +155,93 @@
      * within the magnetic field. It should be used in the {@link MenuListViewTouchHandler}.
      *
      * @param event that move the magnetized object which is also the menu list view.
-     * @return true if the location of the motion events moves within the magnetic field of a
-     * target, but false if didn't set
+     * @return id of a target if the location of the motion events moves
+     * within the field of the target, otherwise it returns{@link android.R.id#empty}.
      * {@link DragToInteractAnimationController#setMagnetListener(MagnetizedObject.MagnetListener)}.
      */
-    boolean maybeConsumeUpMotionEvent(MotionEvent event) {
-        return mMagnetizedObject.maybeConsumeMotionEvent(event);
+    int maybeConsumeUpMotionEvent(MotionEvent event) {
+        return maybeConsumeMotionEvent(event);
     }
 
-    void animateDismissMenu(boolean scaleUp) {
+    void animateInteractMenu(int targetViewId, boolean scaleUp) {
+        Pair<MagnetizedObject<MenuView>, ValueAnimator> value = mInteractMap.get(targetViewId);
+        if (value == null) {
+            return;
+        }
+        ValueAnimator animator = value.second;
         if (scaleUp) {
-            mDismissAnimator.start();
+            animator.start();
         } else {
-            mDismissAnimator.reverse();
+            animator.reverse();
         }
     }
 
     void updateResources() {
-        final float maxDismissSize = mDismissView.getResources().getDimensionPixelSize(
+        final float maxInteractSize = mMenuView.getResources().getDimensionPixelSize(
                 com.android.wm.shell.R.dimen.dismiss_circle_size);
-        mMinDismissSize = mDismissView.getResources().getDimensionPixelSize(
+        mMinInteractSize = mMenuView.getResources().getDimensionPixelSize(
                 com.android.wm.shell.R.dimen.dismiss_circle_small);
-        mSizePercent = mMinDismissSize / maxDismissSize;
+        mSizePercent = mMinInteractSize / maxInteractSize;
     }
 
-    interface DismissCallback {
-        void onDismiss();
+    /**
+     * Creates a magnetizedObject & valueAnimator pair for the provided circleView,
+     * and adds them to the interactMap.
+     *
+     * @param circleView circleView to create objects for.
+     */
+    private void createMagnetizedObjectAndAnimator(DismissCircleView circleView) {
+        MagnetizedObject<MenuView> magnetizedObject = new MagnetizedObject<MenuView>(
+                mMenuView.getContext(), mMenuView,
+                new MenuAnimationController.MenuPositionProperty(
+                        DynamicAnimation.TRANSLATION_X),
+                new MenuAnimationController.MenuPositionProperty(
+                        DynamicAnimation.TRANSLATION_Y)) {
+            @Override
+            public void getLocationOnScreen(MenuView underlyingObject, @NonNull int[] loc) {
+                underlyingObject.getLocationOnScreen(loc);
+            }
+
+            @Override
+            public float getHeight(MenuView underlyingObject) {
+                return underlyingObject.getHeight();
+            }
+
+            @Override
+            public float getWidth(MenuView underlyingObject) {
+                return underlyingObject.getWidth();
+            }
+        };
+        // Avoid unintended selection of an object / option
+        magnetizedObject.setFlingToTargetEnabled(false);
+        magnetizedObject.addTarget(new MagnetizedObject.MagneticTarget(
+                circleView, (int) mMinInteractSize));
+
+        final ValueAnimator animator =
+                ValueAnimator.ofFloat(COMPLETELY_OPAQUE, COMPLETELY_TRANSPARENT);
+
+        animator.addUpdateListener(dismissAnimation -> {
+            final float animatedValue = (float) dismissAnimation.getAnimatedValue();
+            final float scaleValue = Math.max(animatedValue, mSizePercent);
+            circleView.setScaleX(scaleValue);
+            circleView.setScaleY(scaleValue);
+
+            mMenuView.setAlpha(Math.max(animatedValue, ANIMATING_MAX_ALPHA));
+        });
+
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
+                super.onAnimationEnd(animation, isReverse);
+
+                if (isReverse) {
+                    circleView.setScaleX(CIRCLE_VIEW_DEFAULT_SCALE);
+                    circleView.setScaleY(CIRCLE_VIEW_DEFAULT_SCALE);
+                    mMenuView.setAlpha(COMPLETELY_OPAQUE);
+                }
+            }
+        });
+
+        mInteractMap.put(circleView.getId(), new Pair<>(magnetizedObject, animator));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractView.kt b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractView.kt
new file mode 100644
index 0000000..0ef3d20
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractView.kt
@@ -0,0 +1,322 @@
+/*
+ * 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.systemui.accessibility.floatingmenu
+
+import android.animation.ObjectAnimator
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
+import android.util.ArrayMap
+import android.util.IntProperty
+import android.util.Log
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowInsets
+import android.view.WindowManager
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import android.widget.Space
+import androidx.annotation.ColorRes
+import androidx.annotation.DimenRes
+import androidx.annotation.DrawableRes
+import androidx.core.content.ContextCompat
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
+import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
+import com.android.wm.shell.R
+import com.android.wm.shell.animation.PhysicsAnimator
+import com.android.wm.shell.common.bubbles.DismissCircleView
+import com.android.wm.shell.common.bubbles.DismissView
+
+/**
+ * View that handles interactions between DismissCircleView and BubbleStackView.
+ *
+ * @note [setup] method should be called after initialisation
+ */
+class DragToInteractView(context: Context) : FrameLayout(context) {
+    /**
+     * The configuration is used to provide module specific resource ids
+     *
+     * @see [setup] method
+     */
+    data class Config(
+        /** dimen resource id of the dismiss target circle view size */
+        @DimenRes val targetSizeResId: Int,
+        /** dimen resource id of the icon size in the dismiss target */
+        @DimenRes val iconSizeResId: Int,
+        /** dimen resource id of the bottom margin for the dismiss target */
+        @DimenRes var bottomMarginResId: Int,
+        /** dimen resource id of the height for dismiss area gradient */
+        @DimenRes val floatingGradientHeightResId: Int,
+        /** color resource id of the dismiss area gradient color */
+        @ColorRes val floatingGradientColorResId: Int,
+        /** drawable resource id of the dismiss target background */
+        @DrawableRes val backgroundResId: Int,
+        /** drawable resource id of the icon for the dismiss target */
+        @DrawableRes val iconResId: Int
+    )
+
+    companion object {
+        private const val SHOULD_SETUP = "The view isn't ready. Should be called after `setup`"
+        private val TAG = DragToInteractView::class.simpleName
+    }
+
+    // START DragToInteractView modification
+    // We could technically access each DismissCircleView from their Animator,
+    // but the animators only store a weak reference to their targets. This is safer.
+    var interactMap = ArrayMap<Int, Pair<DismissCircleView, PhysicsAnimator<DismissCircleView>>>()
+    // END DragToInteractView modification
+    var isShowing = false
+    var config: Config? = null
+
+    private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
+    private val INTERACT_SCRIM_FADE_MS = 200L
+    private var wm: WindowManager =
+        context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+    private var gradientDrawable: GradientDrawable? = null
+
+    private val GRADIENT_ALPHA: IntProperty<GradientDrawable> =
+        object : IntProperty<GradientDrawable>("alpha") {
+            override fun setValue(d: GradientDrawable, percent: Int) {
+                d.alpha = percent
+            }
+            override fun get(d: GradientDrawable): Int {
+                return d.alpha
+            }
+        }
+
+    init {
+        clipToPadding = false
+        clipChildren = false
+        visibility = View.INVISIBLE
+
+        // START DragToInteractView modification
+        // Resources included within implementation as we aren't concerned with decoupling them.
+        setup(
+            Config(
+                targetSizeResId = R.dimen.dismiss_circle_size,
+                iconSizeResId = R.dimen.dismiss_target_x_size,
+                bottomMarginResId = R.dimen.floating_dismiss_bottom_margin,
+                floatingGradientHeightResId = R.dimen.floating_dismiss_gradient_height,
+                floatingGradientColorResId = android.R.color.system_neutral1_900,
+                backgroundResId = R.drawable.dismiss_circle_background,
+                iconResId = R.drawable.pip_ic_close_white
+            )
+        )
+        // END DragToInteractView modification
+    }
+
+    /**
+     * Sets up view with the provided resource ids.
+     *
+     * Decouples resource dependency in order to be used externally (e.g. Launcher). Usually called
+     * with default params in module specific extension:
+     *
+     * @see [DismissView.setup] in DismissViewExt.kt
+     */
+    fun setup(config: Config) {
+        this.config = config
+
+        // Setup layout
+        layoutParams =
+            LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                resources.getDimensionPixelSize(config.floatingGradientHeightResId),
+                Gravity.BOTTOM
+            )
+        updatePadding()
+
+        // Setup gradient
+        gradientDrawable = createGradient(color = config.floatingGradientColorResId)
+        background = gradientDrawable
+
+        // START DragToInteractView modification
+
+        // Setup LinearLayout. Added to organize multiple circles.
+        val linearLayout = LinearLayout(context)
+        linearLayout.layoutParams =
+            LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT
+            )
+        linearLayout.weightSum = 0f
+        addView(linearLayout)
+
+        // Setup DismissCircleView. Code block replaced with repeatable functions
+        addSpace(linearLayout)
+        addCircle(
+            config,
+            com.android.systemui.res.R.id.action_remove_menu,
+            R.drawable.pip_ic_close_white,
+            linearLayout
+        )
+        addCircle(
+            config,
+            com.android.systemui.res.R.id.action_edit,
+            com.android.systemui.res.R.drawable.ic_screenshot_edit,
+            linearLayout
+        )
+        // END DragToInteractView modification
+    }
+
+    /** Animates this view in. */
+    fun show() {
+        if (isShowing) return
+        val gradientDrawable = checkExists(gradientDrawable) ?: return
+        isShowing = true
+        visibility = View.VISIBLE
+        val alphaAnim =
+            ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA, gradientDrawable.alpha, 255)
+        alphaAnim.duration = INTERACT_SCRIM_FADE_MS
+        alphaAnim.start()
+
+        // START DragToInteractView modification
+        interactMap.forEach {
+            val animator = it.value.second
+            animator.cancel()
+            animator.spring(DynamicAnimation.TRANSLATION_Y, 0f, spring).start()
+        }
+        // END DragToInteractView modification
+    }
+
+    /**
+     * Animates this view out, as well as the circle that encircles the bubbles, if they were
+     * dragged into the target and encircled.
+     */
+    fun hide() {
+        if (!isShowing) return
+        val gradientDrawable = checkExists(gradientDrawable) ?: return
+        isShowing = false
+        val alphaAnim =
+            ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA, gradientDrawable.alpha, 0)
+        alphaAnim.duration = INTERACT_SCRIM_FADE_MS
+        alphaAnim.start()
+
+        // START DragToInteractView modification
+        interactMap.forEach {
+            val animator = it.value.second
+            animator
+                .spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(), spring)
+                .withEndActions({ visibility = View.INVISIBLE })
+                .start()
+        }
+        // END DragToInteractView modification
+    }
+
+    /** Cancels the animator for the dismiss target. */
+    fun cancelAnimators() {
+        // START DragToInteractView modification
+        interactMap.forEach {
+            val animator = it.value.second
+            animator.cancel()
+        }
+        // END DragToInteractView modification
+    }
+
+    fun updateResources() {
+        val config = checkExists(config) ?: return
+        updatePadding()
+        layoutParams.height = resources.getDimensionPixelSize(config.floatingGradientHeightResId)
+        val targetSize = resources.getDimensionPixelSize(config.targetSizeResId)
+
+        // START DragToInteractView modification
+        interactMap.forEach {
+            val circle = it.value.first
+            circle.layoutParams.width = targetSize
+            circle.layoutParams.height = targetSize
+            circle.requestLayout()
+        }
+        // END DragToInteractView modification
+    }
+
+    private fun createGradient(@ColorRes color: Int): GradientDrawable {
+        val gradientColor = ContextCompat.getColor(context, color)
+        val alpha = 0.7f * 255
+        val gradientColorWithAlpha =
+            Color.argb(
+                alpha.toInt(),
+                Color.red(gradientColor),
+                Color.green(gradientColor),
+                Color.blue(gradientColor)
+            )
+        val gd =
+            GradientDrawable(
+                GradientDrawable.Orientation.BOTTOM_TOP,
+                intArrayOf(gradientColorWithAlpha, Color.TRANSPARENT)
+            )
+        gd.setDither(true)
+        gd.alpha = 0
+        return gd
+    }
+
+    private fun updatePadding() {
+        val config = checkExists(config) ?: return
+        val insets: WindowInsets = wm.currentWindowMetrics.windowInsets
+        val navInset = insets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars())
+        setPadding(
+            0,
+            0,
+            0,
+            navInset.bottom + resources.getDimensionPixelSize(config.bottomMarginResId)
+        )
+    }
+
+    /**
+     * Checks if the value is set up and exists, if not logs an exception. Used for convenient
+     * logging in case `setup` wasn't called before
+     *
+     * @return value provided as argument
+     */
+    private fun <T> checkExists(value: T?): T? {
+        if (value == null) Log.e(TAG, SHOULD_SETUP)
+        return value
+    }
+
+    // START DragToInteractView modification
+    private fun addSpace(parent: LinearLayout) {
+        val space = Space(context)
+        // Spaces are weighted equally to space out circles evenly
+        space.layoutParams =
+            LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                1f
+            )
+        parent.addView(space)
+        parent.weightSum = parent.weightSum + 1f
+    }
+
+    private fun addCircle(config: Config, id: Int, iconResId: Int, parent: LinearLayout) {
+        val targetSize = resources.getDimensionPixelSize(config.targetSizeResId)
+        val circleLayoutParams = LinearLayout.LayoutParams(targetSize, targetSize, 0f)
+        circleLayoutParams.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
+        val circle = DismissCircleView(context)
+        circle.id = id
+        circle.setup(config.backgroundResId, iconResId, config.iconSizeResId)
+        circle.layoutParams = circleLayoutParams
+
+        // Initial position with circle offscreen so it's animated up
+        circle.translationY =
+            resources.getDimensionPixelSize(config.floatingGradientHeightResId).toFloat()
+
+        interactMap[circle.id] = Pair(circle, PhysicsAnimator.getInstance(circle))
+        parent.addView(circle)
+        addSpace(parent)
+    }
+    // END DragToInteractView modification
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index a270558..d3e85e0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -37,7 +37,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
 import com.android.systemui.Flags;
 
 import java.util.HashMap;
@@ -73,7 +72,6 @@
     private final ValueAnimator mFadeOutAnimator;
     private final Handler mHandler;
     private boolean mIsFadeEffectEnabled;
-    private DragToInteractAnimationController.DismissCallback mDismissCallback;
     private Runnable mSpringAnimationsEndAction;
 
     // Cache the animations state of {@link DynamicAnimation.TRANSLATION_X} and {@link
@@ -170,11 +168,6 @@
         mSpringAnimationsEndAction = runnable;
     }
 
-    void setDismissCallback(
-            DragToInteractAnimationController.DismissCallback dismissCallback) {
-        mDismissCallback = dismissCallback;
-    }
-
     void moveToTopLeftPosition() {
         mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ false);
         final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
@@ -205,13 +198,6 @@
         constrainPositionAndUpdate(position, /* writeToPosition = */ true);
     }
 
-    void removeMenu() {
-        Preconditions.checkArgument(mDismissCallback != null,
-                "The dismiss callback should be initialized first.");
-
-        mDismissCallback.onDismiss();
-    }
-
     void flingMenuThenSpringToEdge(float x, float velocityX, float velocityY) {
         final boolean shouldMenuFlingLeft = isOnLeftSide()
                 ? velocityX < ESCAPE_VELOCITY
@@ -334,8 +320,6 @@
             moveToEdgeAndHide();
             return true;
         }
-
-        fadeOutIfEnabled();
         return false;
     }
 
@@ -453,8 +437,6 @@
         mMenuView.onBoundsInParentChanged((int) position.x, (int) position.y);
         constrainPositionAndUpdate(position, writeToPosition);
 
-        fadeOutIfEnabled();
-
         if (mSpringAnimationsEndAction != null) {
             mSpringAnimationsEndAction.run();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
index 0538e7d..4a06ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
@@ -21,7 +21,6 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY;
 import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE;
 import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
 
 import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
 import static com.android.systemui.accessibility.floatingmenu.MenuFadeEffectInfoKt.DEFAULT_FADE_EFFECT_IS_ENABLED;
@@ -47,6 +46,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Prefs;
@@ -182,7 +182,7 @@
     }
 
     void loadMenuTargetFeatures(OnInfoReady<List<AccessibilityTarget>> callback) {
-        callback.onReady(getTargets(mContext, ACCESSIBILITY_BUTTON));
+        callback.onReady(getTargets(mContext, ShortcutConstants.UserShortcutType.SOFTWARE));
     }
 
     void loadMenuSizeType(OnInfoReady<Integer> callback) {
@@ -223,7 +223,7 @@
 
     private void onTargetFeaturesChanged() {
         mSettingsContentsCallback.onTargetFeaturesChanged(
-                getTargets(mContext, ACCESSIBILITY_BUTTON));
+                getTargets(mContext, ShortcutConstants.UserShortcutType.SOFTWARE));
     }
 
     private Position getStartPosition() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegate.java
index 9c22a77..975a602 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegate.java
@@ -27,6 +27,7 @@
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
 
+import com.android.systemui.Flags;
 import com.android.systemui.res.R;
 
 /**
@@ -35,15 +36,18 @@
  */
 class MenuItemAccessibilityDelegate extends RecyclerViewAccessibilityDelegate.ItemDelegate {
     private final MenuAnimationController mAnimationController;
+    private final MenuViewLayer mMenuViewLayer;
 
     MenuItemAccessibilityDelegate(@NonNull RecyclerViewAccessibilityDelegate recyclerViewDelegate,
-            MenuAnimationController animationController) {
+            MenuAnimationController animationController, MenuViewLayer menuViewLayer) {
         super(recyclerViewDelegate);
         mAnimationController = animationController;
+        mMenuViewLayer = menuViewLayer;
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+    public void onInitializeAccessibilityNodeInfo(
+            @NonNull View host, @NonNull AccessibilityNodeInfoCompat info) {
         super.onInitializeAccessibilityNodeInfo(host, info);
 
         final Resources res = host.getResources();
@@ -90,6 +94,15 @@
                         R.id.action_remove_menu,
                         res.getString(R.string.accessibility_floating_button_action_remove_menu));
         info.addAction(removeMenu);
+
+        if (Flags.floatingMenuDragToEdit()) {
+            final AccessibilityNodeInfoCompat.AccessibilityActionCompat edit =
+                    new AccessibilityNodeInfoCompat.AccessibilityActionCompat(
+                            R.id.action_edit,
+                            res.getString(
+                                    R.string.accessibility_floating_button_action_remove_menu));
+            info.addAction(edit);
+        }
     }
 
     @Override
@@ -132,8 +145,8 @@
             return true;
         }
 
-        if (action == R.id.action_remove_menu) {
-            mAnimationController.removeMenu();
+        if (action == R.id.action_remove_menu || action == R.id.action_edit) {
+            mMenuViewLayer.dispatchAccessibilityAction(action);
             return true;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
index 52e7b91..7519168 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
+import static android.R.id.empty;
+
 import android.graphics.PointF;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -78,10 +80,9 @@
                         mMenuAnimationController.onDraggingStart();
                     }
 
-                    mDragToInteractAnimationController.showDismissView(/* show= */ true);
-
-                    if (!mDragToInteractAnimationController.maybeConsumeMoveMotionEvent(
-                            motionEvent)) {
+                    mDragToInteractAnimationController.showInteractView(/* show= */ true);
+                    if (mDragToInteractAnimationController.maybeConsumeMoveMotionEvent(motionEvent)
+                            == empty) {
                         mMenuAnimationController.moveToPositionX(mMenuTranslationDown.x + dx);
                         mMenuAnimationController.moveToPositionYIfNeeded(
                                 mMenuTranslationDown.y + dy);
@@ -94,21 +95,19 @@
                     final float endX = mMenuTranslationDown.x + dx;
                     mIsDragging = false;
 
-                    if (mMenuAnimationController.maybeMoveToEdgeAndHide(endX)) {
-                        mDragToInteractAnimationController.showDismissView(/* show= */ false);
-                        mMenuAnimationController.fadeOutIfEnabled();
+                    mDragToInteractAnimationController.showInteractView(/* show= */ false);
 
+                    if (mMenuAnimationController.maybeMoveToEdgeAndHide(endX)) {
+                        mMenuAnimationController.fadeOutIfEnabled();
                         return true;
                     }
 
-                    if (!mDragToInteractAnimationController.maybeConsumeUpMotionEvent(
-                            motionEvent)) {
+                    if (mDragToInteractAnimationController.maybeConsumeUpMotionEvent(motionEvent)
+                            == empty) {
                         mVelocityTracker.computeCurrentVelocity(VELOCITY_UNIT_SECONDS);
                         mMenuAnimationController.flingMenuThenSpringToEdge(endX,
                                 mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
-                        mDragToInteractAnimationController.showDismissView(/* show= */ false);
                     }
-
                     // Avoid triggering the listener of the item.
                     return true;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index 76808cb..035ccbd 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -21,24 +21,28 @@
 import android.annotation.SuppressLint;
 import android.content.ComponentCallbacks;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.GradientDrawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.SettingsStringUtil;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
-import androidx.core.view.AccessibilityDelegateCompat;
 import androidx.lifecycle.Observer;
 import androidx.recyclerview.widget.DiffUtil;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
 
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.systemui.Flags;
+import com.android.systemui.util.settings.SecureSettings;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -72,26 +76,20 @@
     private final MenuAnimationController mMenuAnimationController;
     private OnTargetFeaturesChangeListener mFeaturesChangeListener;
     private OnMoveToTuckedListener mMoveToTuckedListener;
+    private SecureSettings mSecureSettings;
 
-    MenuView(Context context, MenuViewModel menuViewModel, MenuViewAppearance menuViewAppearance) {
+    MenuView(Context context, MenuViewModel menuViewModel, MenuViewAppearance menuViewAppearance,
+            SecureSettings secureSettings) {
         super(context);
 
         mMenuViewModel = menuViewModel;
         mMenuViewAppearance = menuViewAppearance;
+        mSecureSettings = secureSettings;
         mMenuAnimationController = new MenuAnimationController(this, menuViewAppearance);
         mAdapter = new AccessibilityTargetAdapter(mTargetFeatures);
         mTargetFeaturesView = new RecyclerView(context);
         mTargetFeaturesView.setAdapter(mAdapter);
         mTargetFeaturesView.setLayoutManager(new LinearLayoutManager(context));
-        mTargetFeaturesView.setAccessibilityDelegateCompat(
-                new RecyclerViewAccessibilityDelegate(mTargetFeaturesView) {
-                    @NonNull
-                    @Override
-                    public AccessibilityDelegateCompat getItemDelegate() {
-                        return new MenuItemAccessibilityDelegate(/* recyclerViewDelegate= */ this,
-                                mMenuAnimationController);
-                    }
-                });
         setLayoutParams(new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
         // Avoid drawing out of bounds of the parent view
         setClipToOutline(true);
@@ -228,15 +226,15 @@
             // onArrivalAtPosition() is called at the end of the animation.
         } else {
             mMenuAnimationController.moveToPosition(position);
-            onArrivalAtPosition(); // no animation, so we call this immediately.
+            onArrivalAtPosition(true); // no animation, so we call this immediately.
         }
     }
 
-    void onArrivalAtPosition() {
+    void onArrivalAtPosition(boolean moveToEdgeIfTucked) {
         final PointF position = getMenuPosition();
         onBoundsInParentChanged((int) position.x, (int) position.y);
 
-        if (isMoveToTucked()) {
+        if (isMoveToTucked() && moveToEdgeIfTucked) {
             mMenuAnimationController.moveToEdgeAndHide();
         }
     }
@@ -278,6 +276,7 @@
         if (mFeaturesChangeListener != null) {
             mFeaturesChangeListener.onChange(newTargetFeatures);
         }
+
         mMenuAnimationController.fadeOutIfEnabled();
     }
 
@@ -306,6 +305,10 @@
         return mMenuViewAppearance.getMenuPosition();
     }
 
+    RecyclerView getTargetFeaturesView() {
+        return mTargetFeaturesView;
+    }
+
     void persistPositionAndUpdateEdge(Position percentagePosition) {
         mMenuViewModel.updateMenuSavingPosition(percentagePosition);
         mMenuViewAppearance.setPercentagePosition(percentagePosition);
@@ -424,6 +427,35 @@
         onPositionChanged();
     }
 
+    void gotoEditScreen() {
+        if (!Flags.floatingMenuDragToEdit()) {
+            return;
+        }
+        mMenuAnimationController.flingMenuThenSpringToEdge(
+                getMenuPosition().x, 100f, 0f);
+        mContext.startActivity(getIntentForEditScreen());
+    }
+
+    Intent getIntentForEditScreen() {
+        List<String> targets = new SettingsStringUtil.ColonDelimitedSet.OfStrings(
+                mSecureSettings.getStringForUser(
+                        Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
+                        UserHandle.USER_CURRENT)).stream().toList();
+
+        Intent intent = new Intent(
+                Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS);
+        Bundle args = new Bundle();
+        Bundle fragmentArgs = new Bundle();
+        fragmentArgs.putStringArray("targets", targets.toArray(new String[0]));
+        args.putBundle(":settings:show_fragment_args", fragmentArgs);
+        // TODO: b/318748373 - The fragment should set its own title using the targets
+        args.putString(
+                ":settings:show_fragment_title", "Accessibility Shortcut");
+        intent.replaceExtras(args);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        return intent;
+    }
+
     private InstantInsetLayerDrawable getContainerViewInsetLayer() {
         return (InstantInsetLayerDrawable) getBackground();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 97999cc..f2e9531 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -17,7 +17,6 @@
 package com.android.systemui.accessibility.floatingmenu;
 
 import static android.view.WindowInsets.Type.ime;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
 
 import static androidx.core.view.WindowInsetsCompat.Type;
 
@@ -59,8 +58,12 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.core.view.AccessibilityDelegateCompat;
 import androidx.lifecycle.Observer;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto;
@@ -94,6 +97,8 @@
     private final MenuListViewTouchHandler mMenuListViewTouchHandler;
     private final MenuMessageView mMessageView;
     private final DismissView mDismissView;
+    private final DragToInteractView mDragToInteractView;
+
     private final MenuViewAppearance mMenuViewAppearance;
     private final MenuAnimationController mMenuAnimationController;
     private final AccessibilityManager mAccessibilityManager;
@@ -149,7 +154,7 @@
 
             final List<ComponentName> hardwareKeyShortcutComponents =
                     mAccessibilityManager.getAccessibilityShortcutTargets(
-                                    ACCESSIBILITY_SHORTCUT_KEY)
+                                    ShortcutConstants.UserShortcutType.HARDWARE)
                             .stream()
                             .map(ComponentName::unflattenFromString)
                             .toList();
@@ -178,7 +183,10 @@
     };
 
     MenuViewLayer(@NonNull Context context, WindowManager windowManager,
-            AccessibilityManager accessibilityManager, IAccessibilityFloatingMenu floatingMenu,
+            AccessibilityManager accessibilityManager,
+            MenuViewModel menuViewModel,
+            MenuViewAppearance menuViewAppearance, MenuView menuView,
+            IAccessibilityFloatingMenu floatingMenu,
             SecureSettings secureSettings) {
         super(context);
 
@@ -190,43 +198,52 @@
         mFloatingMenu = floatingMenu;
         mSecureSettings = secureSettings;
 
-        mMenuViewModel = new MenuViewModel(context, accessibilityManager, secureSettings);
-        mMenuViewAppearance = new MenuViewAppearance(context, windowManager);
-        mMenuView = new MenuView(context, mMenuViewModel, mMenuViewAppearance);
+        mMenuViewModel = menuViewModel;
+        mMenuViewAppearance = menuViewAppearance;
+        mMenuView = menuView;
+        RecyclerView targetFeaturesView = mMenuView.getTargetFeaturesView();
+        targetFeaturesView.setAccessibilityDelegateCompat(
+                new RecyclerViewAccessibilityDelegate(targetFeaturesView) {
+                    @NonNull
+                    @Override
+                    public AccessibilityDelegateCompat getItemDelegate() {
+                        return new MenuItemAccessibilityDelegate(/* recyclerViewDelegate= */ this,
+                                mMenuAnimationController, MenuViewLayer.this);
+                    }
+                });
         mMenuAnimationController = mMenuView.getMenuAnimationController();
-        if (Flags.floatingMenuDragToHide()) {
-            mMenuAnimationController.setDismissCallback(this::hideMenuAndShowNotification);
-        } else {
-            mMenuAnimationController.setDismissCallback(this::hideMenuAndShowMessage);
-        }
         mMenuAnimationController.setSpringAnimationsEndAction(this::onSpringAnimationsEndAction);
         mDismissView = new DismissView(context);
+        mDragToInteractView = new DragToInteractView(context);
         DismissViewUtils.setup(mDismissView);
+        mDismissView.getCircle().setId(R.id.action_remove_menu);
         mNotificationFactory = new MenuNotificationFactory(context);
         mNotificationManager = context.getSystemService(NotificationManager.class);
-        mDragToInteractAnimationController = new DragToInteractAnimationController(
-                mDismissView, mMenuView);
+
+        if (Flags.floatingMenuDragToEdit()) {
+            mDragToInteractAnimationController = new DragToInteractAnimationController(
+                    mDragToInteractView, mMenuView);
+        } else {
+            mDragToInteractAnimationController = new DragToInteractAnimationController(
+                    mDismissView, mMenuView);
+        }
         mDragToInteractAnimationController.setMagnetListener(new MagnetizedObject.MagnetListener() {
             @Override
             public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
-                mDragToInteractAnimationController.animateDismissMenu(/* scaleUp= */ true);
+                mDragToInteractAnimationController.animateInteractMenu(
+                        target.getTargetView().getId(), /* scaleUp= */ true);
             }
 
             @Override
             public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
                     float velocityX, float velocityY, boolean wasFlungOut) {
-                mDragToInteractAnimationController.animateDismissMenu(/* scaleUp= */ false);
+                mDragToInteractAnimationController.animateInteractMenu(
+                        target.getTargetView().getId(), /* scaleUp= */ false);
             }
 
             @Override
             public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
-                if (Flags.floatingMenuDragToHide()) {
-                    hideMenuAndShowNotification();
-                } else {
-                    hideMenuAndShowMessage();
-                }
-                mDismissView.hide();
-                mDragToInteractAnimationController.animateDismissMenu(/* scaleUp= */ false);
+                dispatchAccessibilityAction(target.getTargetView().getId());
             }
         });
 
@@ -262,7 +279,11 @@
         });
 
         addView(mMenuView, LayerIndex.MENU_VIEW);
-        addView(mDismissView, LayerIndex.DISMISS_VIEW);
+        if (Flags.floatingMenuDragToEdit()) {
+            addView(mDragToInteractView, LayerIndex.DISMISS_VIEW);
+        } else {
+            addView(mDismissView, LayerIndex.DISMISS_VIEW);
+        }
         addView(mMessageView, LayerIndex.MESSAGE_VIEW);
 
         if (Flags.floatingMenuAnimatedTuck()) {
@@ -272,6 +293,7 @@
 
     @Override
     public void onConfigurationChanged(@NonNull Configuration newConfig) {
+        mDragToInteractView.updateResources();
         mDismissView.updateResources();
         mDragToInteractAnimationController.updateResources();
     }
@@ -424,10 +446,27 @@
             }
         }
         if (Flags.floatingMenuImeDisplacementAnimation()) {
-            mMenuView.onArrivalAtPosition();
+            mMenuView.onArrivalAtPosition(false);
         }
     }
 
+    void dispatchAccessibilityAction(int id) {
+        if (id == R.id.action_remove_menu) {
+            if (Flags.floatingMenuDragToHide()) {
+                hideMenuAndShowNotification();
+            } else {
+                hideMenuAndShowMessage();
+            }
+        } else if (id == R.id.action_edit
+                && Flags.floatingMenuDragToEdit()) {
+            mMenuView.gotoEditScreen();
+        }
+        mDismissView.hide();
+        mDragToInteractView.hide();
+        mDragToInteractAnimationController.animateInteractMenu(
+                id, /* scaleUp= */ false);
+    }
+
     private CharSequence getMigrationMessage() {
         final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -475,7 +514,8 @@
         mEduTooltipView = Optional.empty();
     }
 
-    private void hideMenuAndShowMessage() {
+    @VisibleForTesting
+    void hideMenuAndShowMessage() {
         final int delayTime = mAccessibilityManager.getRecommendedTimeoutMillis(
                 SHOW_MESSAGE_DELAY_MS,
                 AccessibilityManager.FLAG_CONTENT_TEXT
@@ -485,7 +525,8 @@
         mMenuAnimationController.startShrinkAnimation(() -> mMenuView.setVisibility(GONE));
     }
 
-    private void hideMenuAndShowNotification() {
+    @VisibleForTesting
+    void hideMenuAndShowNotification() {
         mMenuAnimationController.startShrinkAnimation(() -> mMenuView.setVisibility(GONE));
         showNotification();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
index 1f54952..bc9d1ff 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
@@ -39,7 +39,16 @@
     MenuViewLayerController(Context context, WindowManager windowManager,
             AccessibilityManager accessibilityManager, SecureSettings secureSettings) {
         mWindowManager = windowManager;
-        mMenuViewLayer = new MenuViewLayer(context, windowManager, accessibilityManager, this,
+
+        MenuViewModel menuViewModel = new MenuViewModel(
+                context, accessibilityManager, secureSettings);
+        MenuViewAppearance menuViewAppearance = new MenuViewAppearance(context, windowManager);
+
+        mMenuViewLayer = new MenuViewLayer(context, windowManager, accessibilityManager,
+                menuViewModel,
+                menuViewAppearance,
+                new MenuView(context, menuViewModel, menuViewAppearance, secureSettings),
+                this,
                 secureSettings);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index fdccad1..8ca083f 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -30,11 +30,16 @@
 import com.android.systemui.authentication.shared.model.AuthenticationWipeModel.WipeTarget
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.time.SystemClock
 import javax.inject.Inject
 import kotlin.math.max
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.SharedFlow
@@ -44,6 +49,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
 
 /**
  * Hosts application business logic related to user authentication.
@@ -57,6 +63,7 @@
 @Inject
 constructor(
     @Application private val applicationScope: CoroutineScope,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
     private val repository: AuthenticationRepository,
     private val selectedUserInteractor: SelectedUserInteractor,
 ) {
@@ -227,6 +234,11 @@
         if (authenticationResult.isSuccessful) {
             repository.reportAuthenticationAttempt(isSuccessful = true)
             _onAuthenticationResult.emit(true)
+
+            // Force a garbage collection in an attempt to erase any credentials left in memory.
+            // Do it after a 5-sec delay to avoid making the bouncer dismiss animation janky.
+            initiateGarbageCollection(delay = 5.seconds)
+
             return AuthenticationResult.SUCCEEDED
         }
 
@@ -312,6 +324,15 @@
         }
     }
 
+    private suspend fun initiateGarbageCollection(delay: Duration) {
+        applicationScope.launch(backgroundDispatcher) {
+            delay(delay)
+            System.gc()
+            System.runFinalization()
+            System.gc()
+        }
+    }
+
     companion object {
         const val TAG = "AuthenticationInteractor"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 71d0e7d..d2c6227 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -25,6 +25,7 @@
 import android.hardware.biometrics.BiometricSourceType
 import android.util.DisplayMetrics
 import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.repeatOnLifecycle
 import com.android.app.animation.Interpolators
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
@@ -35,7 +36,11 @@
 import com.android.systemui.biometrics.data.repository.FacePropertyRepository
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.AuthRippleInteractor
+import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.res.R
@@ -78,6 +83,7 @@
     private val logger: KeyguardLogger,
     private val biometricUnlockController: BiometricUnlockController,
     private val lightRevealScrim: LightRevealScrim,
+    private val authRippleInteractor: AuthRippleInteractor,
     private val facePropertyRepository: FacePropertyRepository,
     rippleView: AuthRippleView?
 ) :
@@ -100,6 +106,22 @@
         init()
     }
 
+    init {
+        if (DeviceEntryUdfpsRefactor.isEnabled) {
+            rippleView?.repeatWhenAttached {
+                repeatOnLifecycle(androidx.lifecycle.Lifecycle.State.CREATED) {
+                    authRippleInteractor.showUnlockRipple.collect { biometricUnlockSource ->
+                        if (biometricUnlockSource == BiometricUnlockSource.FINGERPRINT_SENSOR) {
+                            showUnlockRippleInternal(BiometricSourceType.FINGERPRINT)
+                        } else {
+                            showUnlockRippleInternal(BiometricSourceType.FACE)
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     @VisibleForTesting
     public override fun onViewAttached() {
         authController.addCallback(authControllerCallback)
@@ -111,7 +133,9 @@
         keyguardStateController.addCallback(this)
         wakefulnessLifecycle.addObserver(this)
         commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
-        biometricUnlockController.addListener(biometricModeListener)
+        if (!DeviceEntryUdfpsRefactor.isEnabled) {
+            biometricUnlockController.addListener(biometricModeListener)
+        }
     }
 
     private val biometricModeListener =
@@ -119,8 +143,9 @@
             override fun onBiometricUnlockedWithKeyguardDismissal(
                     biometricSourceType: BiometricSourceType?
             ) {
+                DeviceEntryUdfpsRefactor.assertInLegacyMode()
                 if (biometricSourceType != null) {
-                    showUnlockRipple(biometricSourceType)
+                    showUnlockRippleInternal(biometricSourceType)
                 } else {
                     logger.log(TAG,
                             LogLevel.ERROR,
@@ -143,7 +168,13 @@
         notificationShadeWindowController.setForcePluginOpen(false, this)
     }
 
-    fun showUnlockRipple(biometricSourceType: BiometricSourceType) {
+     @Deprecated("Update authRippleInteractor.showUnlockRipple instead of calling this.")
+     fun showUnlockRipple(biometricSourceType: BiometricSourceType) {
+         DeviceEntryUdfpsRefactor.assertInLegacyMode()
+         showUnlockRippleInternal(biometricSourceType)
+     }
+
+    private fun showUnlockRippleInternal(biometricSourceType: BiometricSourceType) {
         val keyguardNotShowing = !keyguardStateController.isShowing
         val unlockNotAllowed = !keyguardUpdateMonitor
                 .isUnlockingWithBiometricAllowed(biometricSourceType)
@@ -377,12 +408,12 @@
                     }
                     "fingerprint" -> {
                         pw.println("fingerprint ripple sensorLocation=$fingerprintSensorLocation")
-                        showUnlockRipple(BiometricSourceType.FINGERPRINT)
+                        showUnlockRippleInternal(BiometricSourceType.FINGERPRINT)
                     }
                     "face" -> {
                         // note: only shows when about to proceed to the home screen
                         pw.println("face ripple sensorLocation=$faceSensorLocation")
-                        showUnlockRipple(BiometricSourceType.FACE)
+                        showUnlockRippleInternal(BiometricSourceType.FACE)
                     }
                     "custom" -> {
                         if (args.size != 3 ||
@@ -409,7 +440,7 @@
             pw.println("  custom <x-location: int> <y-location: int>")
         }
 
-        fun invalidCommand(pw: PrintWriter) {
+        private fun invalidCommand(pw: PrintWriter) {
             pw.println("invalid command")
             help(pw)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
index c36e0e2..80d37b4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -121,11 +121,13 @@
             if (it.isAttachedToWindow) {
                 lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
                 lottie?.pauseAnimation()
+                lottie?.removeAllLottieOnCompositionLoadedListener()
                 windowManager.get().removeView(it)
             }
         }
 
         overlayView = layoutInflater.get().inflate(R.layout.sidefps_view, null, false)
+
         val overlayViewModel =
             SideFpsOverlayViewModel(
                 applicationContext,
@@ -163,8 +165,10 @@
 
                 val lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
                 lottie.addLottieOnCompositionLoadedListener { composition: LottieComposition ->
-                    viewModel.setLottieBounds(composition.bounds)
-                    overlayView.visibility = View.VISIBLE
+                    if (overlayView.visibility != View.VISIBLE) {
+                        viewModel.setLottieBounds(composition.bounds)
+                        overlayView.visibility = View.VISIBLE
+                    }
                 }
                 it.alpha = 0f
                 val overlayShowAnimator =
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 8e14778..5c9c997 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -26,6 +26,7 @@
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
 
 /** Holds UI state and handles user input for the password bouncer UI. */
 class PasswordBouncerViewModel(
@@ -48,9 +49,6 @@
 
     override val lockoutMessageId = R.string.kg_too_many_failed_password_attempts_dialog_message
 
-    /** Whether the input method editor (for example, the software keyboard) is visible. */
-    private var isImeVisible: Boolean = false
-
     /** Whether the text field element currently has focus. */
     private val isTextFieldFocused = MutableStateFlow(false)
 
@@ -65,7 +63,6 @@
 
     override fun onHidden() {
         super.onHidden()
-        isImeVisible = false
         isTextFieldFocused.value = false
     }
 
@@ -97,16 +94,9 @@
         }
     }
 
-    /**
-     * Notifies that the input method editor (for example, the software keyboard) has been shown or
-     * hidden.
-     */
-    suspend fun onImeVisibilityChanged(isVisible: Boolean) {
-        if (isImeVisible && !isVisible && isInputEnabled.value) {
-            interactor.onImeHiddenByUser()
-        }
-
-        isImeVisible = isVisible
+    /** Notifies that the user has dismissed the software keyboard (IME). */
+    fun onImeDismissed() {
+        viewModelScope.launch { interactor.onImeHiddenByUser() }
     }
 
     /** Notifies that the password text field has gained or lost focus. */
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
new file mode 100644
index 0000000..f7ba5a4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.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.communal
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dock.DockManager
+import com.android.systemui.dock.retrieveIsDocked
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.FlowPreview
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.onEach
+
+/**
+ * A [CoreStartable] responsible for automatically navigating between communal scenes when certain
+ * conditions are met.
+ */
+@OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
+@SysUISingleton
+class CommunalSceneStartable
+@Inject
+constructor(
+    private val dockManager: DockManager,
+    private val communalInteractor: CommunalInteractor,
+    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+    @Application private val applicationScope: CoroutineScope,
+    @Background private val bgScope: CoroutineScope,
+) : CoreStartable {
+    override fun start() {
+        // Handle automatically switching based on keyguard state.
+        keyguardTransitionInteractor.startedKeyguardTransitionStep
+            .mapLatest(::determineSceneAfterTransition)
+            .filterNotNull()
+            // TODO(b/322787129): Also set a custom transition animation here to avoid the regular
+            // slide-in animation when setting the scene programmatically
+            .onEach { nextScene -> communalInteractor.onSceneChanged(nextScene) }
+            .launchIn(applicationScope)
+
+        // Handle automatically switching to communal when docked.
+        dockManager
+            .retrieveIsDocked()
+            // Allow some time after docking to ensure the dream doesn't start. If the dream
+            // starts, then we don't want to automatically transition to glanceable hub.
+            .debounce(DOCK_DEBOUNCE_DELAY)
+            .sample(keyguardTransitionInteractor.startedKeyguardState, ::Pair)
+            .onEach { (docked, lastStartedState) ->
+                if (docked && lastStartedState == KeyguardState.LOCKSCREEN) {
+                    communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+                }
+            }
+            .launchIn(bgScope)
+    }
+
+    private suspend fun determineSceneAfterTransition(
+        lastStartedTransition: TransitionStep,
+    ): CommunalSceneKey? {
+        val to = lastStartedTransition.to
+        val from = lastStartedTransition.from
+        val docked = dockManager.isDocked
+
+        return when {
+            to == KeyguardState.DREAMING -> CommunalSceneKey.Blank
+            docked && to == KeyguardState.LOCKSCREEN && from != KeyguardState.GLANCEABLE_HUB -> {
+                CommunalSceneKey.Communal
+            }
+            to == KeyguardState.GONE -> CommunalSceneKey.Blank
+            !docked && !KeyguardState.deviceIsAwakeInState(to) -> {
+                // If the user taps the screen and wakes the device within this timeout, we don't
+                // want to dismiss the hub
+                delay(AWAKE_DEBOUNCE_DELAY)
+                CommunalSceneKey.Blank
+            }
+            else -> null
+        }
+    }
+
+    companion object {
+        val AWAKE_DEBOUNCE_DELAY = 5.seconds
+        val DOCK_DEBOUNCE_DELAY = 1.seconds
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
index 3287ed4..f36547b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
@@ -27,21 +27,17 @@
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
 import com.android.systemui.communal.widgets.WidgetConfigurator
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
 import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.util.kotlin.getValue
 import java.util.Optional
 import javax.inject.Inject
 import kotlin.coroutines.cancellation.CancellationException
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
@@ -67,18 +63,15 @@
      * @param widgetIdToPriorityMap mapping of the widget ids to the priority of the widget.
      */
     fun updateWidgetOrder(widgetIdToPriorityMap: Map<Int, Int>) {}
-
-    /** Update whether the app widget host should be active. */
-    fun updateAppWidgetHostActive(active: Boolean)
 }
 
 @SysUISingleton
 class CommunalWidgetRepositoryImpl
 @Inject
 constructor(
-    private val appWidgetManager: Optional<AppWidgetManager>,
+    appWidgetManagerOptional: Optional<AppWidgetManager>,
     private val appWidgetHost: CommunalAppWidgetHost,
-    @Application private val applicationScope: CoroutineScope,
+    @Background private val bgScope: CoroutineScope,
     @Background private val bgDispatcher: CoroutineDispatcher,
     private val communalWidgetHost: CommunalWidgetHost,
     private val communalWidgetDao: CommunalWidgetDao,
@@ -90,41 +83,22 @@
 
     private val logger = Logger(logBuffer, TAG)
 
-    override fun updateAppWidgetHostActive(active: Boolean) {
-        if (active == isHostActive.value) {
-            return
-        }
+    private val appWidgetManager by appWidgetManagerOptional
 
-        if (active) {
-            appWidgetHost.startListening()
-        } else {
-            appWidgetHost.stopListening()
-        }
-        isHostActive.value = active
-    }
-
-    private val isHostActive = MutableStateFlow(false)
-
-    @OptIn(ExperimentalCoroutinesApi::class)
     override val communalWidgets: Flow<List<CommunalWidgetContentModel>> =
-        isHostActive.flatMapLatest { isHostActive ->
-            if (!isHostActive || !appWidgetManager.isPresent) {
-                return@flatMapLatest flowOf(emptyList())
-            }
-            communalWidgetDao
-                .getWidgets()
-                .map { it.map(::mapToContentModel) }
-                // As this reads from a database and triggers IPCs to AppWidgetManager,
-                // it should be executed in the background.
-                .flowOn(bgDispatcher)
-        }
+        communalWidgetDao
+            .getWidgets()
+            .map { it.mapNotNull(::mapToContentModel) }
+            // As this reads from a database and triggers IPCs to AppWidgetManager,
+            // it should be executed in the background.
+            .flowOn(bgDispatcher)
 
     override fun addWidget(
         provider: ComponentName,
         priority: Int,
         configurator: WidgetConfigurator?
     ) {
-        applicationScope.launch(bgDispatcher) {
+        bgScope.launch {
             val id = communalWidgetHost.allocateIdAndBindWidget(provider)
             if (id == null) {
                 logger.e("Failed to allocate widget id to ${provider.flattenToString()}")
@@ -170,7 +144,7 @@
     }
 
     override fun deleteWidget(widgetId: Int) {
-        applicationScope.launch(bgDispatcher) {
+        bgScope.launch {
             communalWidgetDao.deleteWidgetById(widgetId)
             appWidgetHost.deleteAppWidgetId(widgetId)
             logger.i("Deleted widget with id $widgetId.")
@@ -178,7 +152,7 @@
     }
 
     override fun updateWidgetOrder(widgetIdToPriorityMap: Map<Int, Int>) {
-        applicationScope.launch(bgDispatcher) {
+        bgScope.launch {
             communalWidgetDao.updateWidgetOrder(widgetIdToPriorityMap)
             logger.i({ "Updated the order of widget list with ids: $str1." }) {
                 str1 = widgetIdToPriorityMap.toString()
@@ -189,11 +163,12 @@
     @WorkerThread
     private fun mapToContentModel(
         entry: Map.Entry<CommunalItemRank, CommunalWidgetItem>
-    ): CommunalWidgetContentModel {
+    ): CommunalWidgetContentModel? {
         val (_, widgetId) = entry.value
+        val providerInfo = appWidgetManager?.getAppWidgetInfo(widgetId) ?: return null
         return CommunalWidgetContentModel(
             appWidgetId = widgetId,
-            providerInfo = appWidgetManager.get().getAppWidgetInfo(widgetId),
+            providerInfo = providerInfo,
             priority = entry.key.rank,
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index c36f7fa..80fee64 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -33,23 +33,23 @@
 import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
 import com.android.systemui.communal.widgets.WidgetConfigurator
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.smartspace.data.repository.SmartspaceRepository
 import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.not
+import com.android.systemui.util.kotlin.BooleanFlowOperators.or
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.stateIn
 
 /** Encapsulates business-logic related to communal mode. */
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -57,7 +57,6 @@
 class CommunalInteractor
 @Inject
 constructor(
-    @Application applicationScope: CoroutineScope,
     private val communalRepository: CommunalRepository,
     private val widgetRepository: CommunalWidgetRepository,
     private val communalPrefsRepository: CommunalPrefsRepository,
@@ -68,38 +67,24 @@
     private val appWidgetHost: CommunalAppWidgetHost,
     private val editWidgetsActivityStarter: EditWidgetsActivityStarter
 ) {
+    private val _editModeOpen = MutableStateFlow(false)
+
+    /** Whether edit mode is currently open. */
+    val editModeOpen: StateFlow<Boolean> = _editModeOpen.asStateFlow()
+
     /** Whether communal features are enabled. */
     val isCommunalEnabled: Boolean
         get() = communalRepository.isCommunalEnabled
 
-    /** A {@link StateFlow} that tracks whether communal features are enabled. */
-    val communalEnabledState: StateFlow<Boolean>
-        get() = communalRepository.communalEnabledState
-
     /** Whether communal features are enabled and available. */
-    val isCommunalAvailable: StateFlow<Boolean> =
-        flowOf(isCommunalEnabled)
-            .flatMapLatest { enabled ->
-                if (enabled)
-                    combine(
-                        keyguardInteractor.isEncryptedOrLockdown,
-                        userRepository.selectedUserInfo,
-                        keyguardInteractor.isKeyguardVisible,
-                        keyguardInteractor.isDreaming,
-                    ) { isEncryptedOrLockdown, selectedUserInfo, isKeyguardVisible, isDreaming ->
-                        !isEncryptedOrLockdown &&
-                            selectedUserInfo.isMain &&
-                            (isKeyguardVisible || isDreaming)
-                    }
-                else flowOf(false)
-            }
-            .distinctUntilChanged()
-            .onEach { available -> widgetRepository.updateAppWidgetHostActive(available) }
-            .stateIn(
-                scope = applicationScope,
-                started = SharingStarted.WhileSubscribed(),
-                initialValue = false,
+    val isCommunalAvailable: Flow<Boolean> =
+        and(
+                communalRepository.communalEnabledState,
+                userRepository.selectedUserInfo.map { it.isMain },
+                not(keyguardInteractor.isEncryptedOrLockdown),
+                or(keyguardInteractor.isKeyguardVisible, keyguardInteractor.isDreaming)
             )
+            .distinctUntilChanged()
 
     /**
      * Target scene as requested by the underlying [SceneTransitionLayout] or through
@@ -166,9 +151,13 @@
         communalRepository.setDesiredScene(newScene)
     }
 
+    fun setEditModeOpen(isOpen: Boolean) {
+        _editModeOpen.value = isOpen
+    }
+
     /** Show the widget editor Activity. */
-    fun showWidgetEditor() {
-        editWidgetsActivityStarter.startActivity()
+    fun showWidgetEditor(preselectedKey: String? = null) {
+        editWidgetsActivityStarter.startActivity(preselectedKey)
     }
 
     /** Dismiss the CTA tile from the hub in view mode. */
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index acd6cb0..ae019a1 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -128,4 +128,6 @@
             }
         }
     }
+
+    fun isWidget() = this is Widget
 }
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 1e64d3f..a87ebd7 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
@@ -33,18 +33,16 @@
     private val communalInteractor: CommunalInteractor,
     val mediaHost: MediaHost,
 ) {
-    val isCommunalAvailable: StateFlow<Boolean> = communalInteractor.isCommunalAvailable
-
     val currentScene: StateFlow<CommunalSceneKey> = communalInteractor.desiredScene
 
     /** Whether widgets are currently being re-ordered. */
     open val reorderingWidgets: StateFlow<Boolean> = MutableStateFlow(false)
 
-    private val _selectedIndex: MutableStateFlow<Int?> = MutableStateFlow(null)
+    private val _selectedKey: MutableStateFlow<String?> = MutableStateFlow(null)
 
-    /** The index of the currently selected item, or null if no item selected. */
-    val selectedIndex: StateFlow<Int?>
-        get() = _selectedIndex
+    /** The key of the currently selected item, or null if no item selected. */
+    val selectedKey: StateFlow<String?>
+        get() = _selectedKey
 
     fun onSceneChanged(scene: CommunalSceneKey) {
         communalInteractor.onSceneChanged(scene)
@@ -94,8 +92,8 @@
      */
     open fun onReorderWidgets(widgetIdToPriorityMap: Map<Int, Int>) {}
 
-    /** Called as the UI requests opening the widget editor. */
-    open fun onOpenWidgetEditor() {}
+    /** Called as the UI requests opening the widget editor with an optional preselected widget. */
+    open fun onOpenWidgetEditor(preselectedKey: String? = null) {}
 
     /** Called as the UI requests to dismiss the CTA tile. */
     open fun onDismissCtaTile() {}
@@ -109,8 +107,8 @@
     /** Called as the user cancels dragging a widget to reorder. */
     open fun onReorderWidgetCancel() {}
 
-    /** Set the index of the currently selected item */
-    fun setSelectedIndex(index: Int?) {
-        _selectedIndex.value = index
+    /** Set the key of the currently selected item */
+    fun setSelectedKey(key: String?) {
+        _selectedKey.value = key
     }
 }
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 237a0c0..ebcfb8b 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
@@ -29,7 +29,6 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
 
 /** The view model for communal hub in edit mode. */
 @SysUISingleton
@@ -44,10 +43,9 @@
 
     // Only widgets are editable. The CTA tile comes last in the list and remains visible.
     override val communalContent: Flow<List<CommunalContentModel>> =
-        communalInteractor.widgetContent
-            // Clear the selected index when the list is updated.
-            .onEach { setSelectedIndex(null) }
-            .map { widgets -> widgets + listOf(CommunalContentModel.CtaTileInEditMode()) }
+        communalInteractor.widgetContent.map { widgets ->
+            widgets + listOf(CommunalContentModel.CtaTileInEditMode())
+        }
 
     private val _reorderingWidgets = MutableStateFlow(false)
 
@@ -61,7 +59,7 @@
 
     override fun onReorderWidgetStart() {
         // Clear selection status
-        setSelectedIndex(null)
+        setSelectedKey(null)
         _reorderingWidgets.value = true
         uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START)
     }
@@ -75,4 +73,7 @@
         _reorderingWidgets.value = false
         uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_CANCEL)
     }
+
+    /** Sets whether edit mode is currently open */
+    fun setEditModeOpen(isOpen: Boolean) = communalInteractor.setEditModeOpen(isOpen)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index a909383..d7a3705 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -81,7 +81,8 @@
         }
     }
 
-    override fun onOpenWidgetEditor() = communalInteractor.showWidgetEditor()
+    override fun onOpenWidgetEditor(preselectedKey: String?) =
+        communalInteractor.showWidgetEditor(preselectedKey)
 
     override fun onDismissCtaTile() {
         scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
new file mode 100644
index 0000000..586df32
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.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.communal.widgets
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.kotlin.BooleanFlowOperators.or
+import com.android.systemui.util.kotlin.pairwise
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.withContext
+
+@SysUISingleton
+class CommunalAppWidgetHostStartable
+@Inject
+constructor(
+    private val appWidgetHost: CommunalAppWidgetHost,
+    private val communalInteractor: CommunalInteractor,
+    @Background private val bgScope: CoroutineScope,
+    @Main private val uiDispatcher: CoroutineDispatcher
+) : CoreStartable {
+    override fun start() {
+        or(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen)
+            // Only trigger updates on state changes, ignoring the initial false value.
+            .pairwise(false)
+            .filter { (previous, new) -> previous != new }
+            .onEach { (_, shouldListen) -> updateAppWidgetHostActive(shouldListen) }
+            .launchIn(bgScope)
+    }
+
+    private suspend fun updateAppWidgetHostActive(active: Boolean) =
+        // Always ensure this is called on the main/ui thread.
+        withContext(uiDispatcher) {
+            if (active) {
+                appWidgetHost.startListening()
+            } else {
+                appWidgetHost.stopListening()
+            }
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index c7a14f9..54c709d 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -29,6 +29,7 @@
 import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.communal.shared.log.CommunalUiEvent
+import com.android.systemui.communal.shared.model.CommunalSceneKey
 import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
 import com.android.systemui.compose.ComposeFacade.setCommunalEditWidgetActivityContent
 import javax.inject.Inject
@@ -47,6 +48,7 @@
         private const val EXTRA_FILTER_STRATEGY = "filter_strategy"
         private const val FILTER_STRATEGY_GLANCEABLE_HUB = 1
         private const val TAG = "EditWidgetsActivity"
+        const val EXTRA_PRESELECTED_KEY = "preselected_key"
     }
 
     private val widgetConfigurator by lazy { widgetConfiguratorFactory.create(this) }
@@ -86,10 +88,15 @@
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
+        communalViewModel.setEditModeOpen(true)
+
         val windowInsetsController = window.decorView.windowInsetsController
         windowInsetsController?.hide(WindowInsets.Type.systemBars())
         window.setDecorFitsSystemWindows(false)
 
+        val preselectedKey = intent.getStringExtra(EXTRA_PRESELECTED_KEY)
+        communalViewModel.setSelectedKey(preselectedKey)
+
         setCommunalEditWidgetActivityContent(
             activity = this,
             viewModel = communalViewModel,
@@ -120,6 +127,7 @@
             },
             onEditDone = {
                 try {
+                    communalViewModel.onSceneChanged(CommunalSceneKey.Communal)
                     checkNotNull(windowManagerService).lockNow(/* options */ null)
                     finish()
                 } catch (e: RemoteException) {
@@ -138,13 +146,16 @@
 
     override fun onStart() {
         super.onStart()
-
         uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_EDIT_MODE_SHOWN)
     }
 
     override fun onStop() {
         super.onStop()
-
         uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_EDIT_MODE_GONE)
     }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        communalViewModel.setEditModeOpen(false)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
index 55acad0..d1843af 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
@@ -18,12 +18,13 @@
 
 import android.content.Context
 import android.content.Intent
+import com.android.systemui.communal.widgets.EditWidgetsActivity.Companion.EXTRA_PRESELECTED_KEY
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.plugins.ActivityStarter
 import javax.inject.Inject
 
 interface EditWidgetsActivityStarter {
-    fun startActivity()
+    fun startActivity(preselectedKey: String? = null)
 }
 
 class EditWidgetsActivityStarterImpl
@@ -33,10 +34,11 @@
     private val activityStarter: ActivityStarter,
 ) : EditWidgetsActivityStarter {
 
-    override fun startActivity() {
+    override fun startActivity(preselectedKey: String?) {
         activityStarter.startActivityDismissingKeyguard(
             Intent(applicationContext, EditWidgetsActivity::class.java)
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK),
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+                .apply { preselectedKey?.let { putExtra(EXTRA_PRESELECTED_KEY, preselectedKey) } },
             /* onlyProvisioned = */ true,
             /* dismissShade = */ true,
         )
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 5c38264..3072f74 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -24,6 +24,7 @@
 import com.android.systemui.plugins.PluginsModule;
 import com.android.systemui.unfold.UnfoldTransitionModule;
 import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
+import com.android.systemui.util.kotlin.GlobalCoroutinesModule;
 
 import dagger.Module;
 import dagger.Provides;
@@ -47,6 +48,7 @@
         AndroidInternalsModule.class,
         FrameworkServicesModule.class,
         GlobalConcurrencyModule.class,
+        GlobalCoroutinesModule.class,
         UnfoldTransitionModule.class,
         PluginsModule.class,
 })
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 50f861f..e9d1e94 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -63,6 +63,7 @@
 import com.android.systemui.statusbar.policy.SensorPrivacyController;
 import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
 import com.android.systemui.toast.ToastModule;
+import com.android.systemui.unfold.UnfoldTransitionModule;
 import com.android.systemui.volume.dagger.VolumeModule;
 import com.android.systemui.wallpapers.dagger.WallpaperModule;
 
@@ -107,6 +108,7 @@
         ShadeModule.class,
         StartCentralSurfacesModule.class,
         SceneContainerFrameworkModule.class,
+        UnfoldTransitionModule.Startables.class,
         ToastModule.class,
         VolumeModule.class,
         WallpaperModule.class
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 8d82b55..9504cfcd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -24,7 +24,9 @@
 import com.android.systemui.back.domain.interactor.BackActionInteractor
 import com.android.systemui.biometrics.BiometricNotificationService
 import com.android.systemui.clipboardoverlay.ClipboardListener
+import com.android.systemui.communal.CommunalSceneStartable
 import com.android.systemui.communal.log.CommunalLoggerStartable
+import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable
 import com.android.systemui.controls.dagger.StartControlsStartableModule
 import com.android.systemui.dagger.qualifiers.PerUser
 import com.android.systemui.dreams.AssistantAttentionMonitor
@@ -49,7 +51,6 @@
 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.KeyguardLiftController
 import com.android.systemui.statusbar.phone.ScrimController
 import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener
 import com.android.systemui.stylus.StylusUsiPowerStartable
@@ -223,12 +224,6 @@
     @ClassKey(WMShell::class)
     abstract fun bindWMShell(sysui: WMShell): CoreStartable
 
-    /** Inject into KeyguardLiftController.  */
-    @Binds
-    @IntoMap
-    @ClassKey(KeyguardLiftController::class)
-    abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
-
     /** Inject into MediaTttSenderCoordinator. */
     @Binds
     @IntoMap
@@ -324,4 +319,16 @@
     @IntoMap
     @ClassKey(CommunalLoggerStartable::class)
     abstract fun bindCommunalLoggerStartable(impl: CommunalLoggerStartable): CoreStartable
+
+    @Binds
+    @IntoMap
+    @ClassKey(CommunalSceneStartable::class)
+    abstract fun bindCommunalSceneStartable(impl: CommunalSceneStartable): CoreStartable
+
+    @Binds
+    @IntoMap
+    @ClassKey(CommunalAppWidgetHostStartable::class)
+    abstract fun bindCommunalAppWidgetHostStartable(
+        impl: CommunalAppWidgetHostStartable
+    ): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 92300ef..2587e2d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -66,6 +66,7 @@
 import com.android.systemui.log.table.TableLogBuffer;
 import com.android.systemui.mediaprojection.appselector.MediaProjectionModule;
 import com.android.systemui.mediaprojection.taskswitcher.MediaProjectionTaskSwitcherModule;
+import com.android.systemui.model.SceneContainerPlugin;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.motiontool.MotionToolModule;
 import com.android.systemui.navigationbar.NavigationBarComponent;
@@ -133,7 +134,7 @@
 import com.android.systemui.util.EventLogModule;
 import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
 import com.android.systemui.util.dagger.UtilModule;
-import com.android.systemui.util.kotlin.CoroutinesModule;
+import com.android.systemui.util.kotlin.SysUICoroutinesModule;
 import com.android.systemui.util.reference.ReferenceModule;
 import com.android.systemui.util.sensors.SensorModule;
 import com.android.systemui.util.settings.SettingsUtilModule;
@@ -182,7 +183,6 @@
         ConfigurationControllerModule.class,
         ConnectivityModule.class,
         ControlsModule.class,
-        CoroutinesModule.class,
         DemoModeModule.class,
         DeviceEntryModule.class,
         DisableFlagsModule.class,
@@ -228,6 +228,7 @@
         StatusBarWindowModule.class,
         SystemPropertiesFlagsModule.class,
         SysUIConcurrencyModule.class,
+        SysUICoroutinesModule.class,
         SysUIUnfoldModule.class,
         TelephonyRepositoryModule.class,
         TemporaryDisplayModule.class,
@@ -268,8 +269,11 @@
 
     @SysUISingleton
     @Provides
-    static SysUiState provideSysUiState(DisplayTracker displayTracker, DumpManager dumpManager) {
-        final SysUiState state = new SysUiState(displayTracker);
+    static SysUiState provideSysUiState(
+            DisplayTracker displayTracker,
+            DumpManager dumpManager,
+            SceneContainerPlugin sceneContainerPlugin) {
+        final SysUiState state = new SysUiState(displayTracker, sceneContainerPlugin);
         dumpManager.registerDumpable(state);
         return state;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
index 7a70c4a..cf7d601 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -40,8 +40,7 @@
 import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
 import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.BiometricType
 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
@@ -63,10 +62,6 @@
 import com.android.systemui.user.data.model.SelectionStatus
 import com.android.systemui.user.data.repository.UserRepository
 import com.google.errorprone.annotations.CompileTimeConstant
-import java.io.PrintWriter
-import java.util.Arrays
-import java.util.stream.Collectors
-import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
@@ -88,6 +83,10 @@
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import java.io.PrintWriter
+import java.util.Arrays
+import java.util.stream.Collectors
+import javax.inject.Inject
 
 /**
  * API to run face authentication and detection for device entry / on keyguard (as opposed to the
@@ -165,7 +164,6 @@
     @FaceAuthTableLog private val faceAuthLog: TableLogBuffer,
     private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val displayStateInteractor: DisplayStateInteractor,
-    private val featureFlags: FeatureFlags,
     dumpManager: DumpManager,
 ) : DeviceEntryFaceAuthRepository, Dumpable {
     private var authCancellationSignal: CancellationSignal? = null
@@ -315,7 +313,7 @@
         // or device starts going to sleep.
         merge(
                 powerInteractor.isAsleep,
-                if (featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                if (KeyguardWmStateRefactor.isEnabled) {
                     keyguardTransitionInteractor.isInTransitionToState(KeyguardState.GONE)
                 } else {
                     keyguardRepository.keyguardDoneAnimationsFinished.map { true }
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt
index 08e8c2d..8283438 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt
@@ -8,35 +8,26 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
-import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.user.data.repository.UserRepository
-import com.android.systemui.util.kotlin.sample
 import dagger.Binds
 import dagger.Module
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.withContext
 
 /** Interface for classes that can access device-entry-related application state. */
 interface DeviceEntryRepository {
-    /** Whether the device is immediately entering the device after a biometric unlock. */
-    val enteringDeviceFromBiometricUnlock: Flow<BiometricUnlockSource>
-
     /**
      * Whether the device is unlocked.
      *
@@ -85,12 +76,6 @@
     keyguardStateController: KeyguardStateController,
     keyguardRepository: KeyguardRepository,
 ) : DeviceEntryRepository {
-    override val enteringDeviceFromBiometricUnlock =
-        keyguardRepository.biometricUnlockState
-            .filter { BiometricUnlockModel.dismissesKeyguard(it) }
-            .sample(
-                keyguardRepository.biometricUnlockSource.filterNotNull(),
-            )
 
     private val _isUnlocked = MutableStateFlow(false)
 
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt
new file mode 100644
index 0000000..337fe1e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.systemui.deviceentry.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/** Business logic for device entry auth ripple interactions. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class AuthRippleInteractor
+@Inject
+constructor(
+    deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+) {
+    private val showUnlockRippleFromDeviceEntryIcon: Flow<BiometricUnlockSource> =
+        deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfpsSupported ->
+            if (isUdfpsSupported) {
+                deviceEntrySourceInteractor.deviceEntryFromDeviceEntryIcon.map {
+                    BiometricUnlockSource.FINGERPRINT_SENSOR
+                }
+            } else {
+                emptyFlow()
+            }
+        }
+
+    private val showUnlockRippleFromBiometricUnlock: Flow<BiometricUnlockSource> =
+        deviceEntrySourceInteractor.deviceEntryFromBiometricSource
+    val showUnlockRipple: Flow<BiometricUnlockSource> =
+        merge(
+            showUnlockRippleFromDeviceEntryIcon,
+            showUnlockRippleFromBiometricUnlock,
+        )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
index 649a971..782bce4 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
@@ -46,7 +46,7 @@
 class DeviceEntryHapticsInteractor
 @Inject
 constructor(
-    deviceEntryInteractor: DeviceEntryInteractor,
+    deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
     deviceEntryFingerprintAuthInteractor: DeviceEntryFingerprintAuthInteractor,
     deviceEntryBiometricAuthInteractor: DeviceEntryBiometricAuthInteractor,
     fingerprintPropertyRepository: FingerprintPropertyRepository,
@@ -80,7 +80,7 @@
             }
 
     val playSuccessHaptic: Flow<Unit> =
-        deviceEntryInteractor.enteringDeviceFromBiometricUnlock
+        deviceEntrySourceInteractor.deviceEntryFromBiometricSource
             .sample(
                 combine(
                     powerButtonSideFpsEnrolled,
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 0985357..73389cb 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
@@ -23,7 +23,6 @@
 import com.android.systemui.deviceentry.data.repository.DeviceEntryFaceAuthRepository
 import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
 import com.android.systemui.keyguard.data.repository.TrustRepository
-import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.SceneKey
@@ -31,7 +30,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.collectLatest
@@ -55,7 +53,7 @@
 @Inject
 constructor(
     @Application private val applicationScope: CoroutineScope,
-    repository: DeviceEntryRepository,
+    private val repository: DeviceEntryRepository,
     private val authenticationInteractor: AuthenticationInteractor,
     private val sceneInteractor: SceneInteractor,
     deviceEntryFaceAuthRepository: DeviceEntryFaceAuthRepository,
@@ -63,9 +61,6 @@
     flags: SceneContainerFlags,
     deviceUnlockedInteractor: DeviceUnlockedInteractor,
 ) {
-    val enteringDeviceFromBiometricUnlock: Flow<BiometricUnlockSource> =
-        repository.enteringDeviceFromBiometricUnlock
-
     /**
      * Whether the device is unlocked.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt
new file mode 100644
index 0000000..d4f76a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.systemui.deviceentry.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+
+/**
+ * Hosts application business logic related to the source of the user entering the device. Note: The
+ * source of the user entering the device isn't equivalent to the reason the device is unlocked.
+ *
+ * For example, the user successfully enters the device when they dismiss the lockscreen via a
+ * bypass biometric or, if the device is already unlocked, by triggering an affordance that
+ * dismisses the lockscreen.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DeviceEntrySourceInteractor
+@Inject
+constructor(
+    keyguardInteractor: KeyguardInteractor,
+) {
+    val deviceEntryFromBiometricSource: Flow<BiometricUnlockSource> =
+        keyguardInteractor.biometricUnlockState
+            .filter { BiometricUnlockModel.dismissesKeyguard(it) }
+            .sample(
+                keyguardInteractor.biometricUnlockSource.filterNotNull(),
+            )
+
+    private val attemptEnterDeviceFromDeviceEntryIcon: MutableSharedFlow<Unit> = MutableSharedFlow()
+    val deviceEntryFromDeviceEntryIcon: Flow<Unit> =
+        attemptEnterDeviceFromDeviceEntryIcon
+            .sample(keyguardInteractor.isKeyguardDismissible)
+            .filter { it } // only send events if the keyguard is dismissible
+            .map {} // map to Unit
+
+    suspend fun attemptEnterDeviceFromDeviceEntryIcon() {
+        attemptEnterDeviceFromDeviceEntryIcon.emit(Unit)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinder.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinder.kt
new file mode 100644
index 0000000..1fd7d00
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinder.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.deviceentry.ui.binder
+
+import android.content.pm.PackageManager
+import android.hardware.Sensor
+import android.hardware.TriggerEvent
+import android.hardware.TriggerEventListener
+import com.android.keyguard.ActiveUnlockConfig
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.CoreStartable
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.util.Assert
+import com.android.systemui.util.sensors.AsyncSensorManager
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNot
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+/**
+ * Triggers face auth and active unlock on lift when the device is showing the lock screen or
+ * bouncer. Only initialized if face auth is supported on the device. Not to be confused with the
+ * lift to wake gesture which is handled by {@link com.android.server.policy.PhoneWindowManager}.
+ */
+@SysUISingleton
+class LiftToRunFaceAuthBinder
+@Inject
+constructor(
+    @Application private val scope: CoroutineScope,
+    private val packageManager: PackageManager,
+    private val asyncSensorManager: AsyncSensorManager,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    keyguardInteractor: KeyguardInteractor,
+    primaryBouncerInteractor: PrimaryBouncerInteractor,
+    alternateBouncerInteractor: AlternateBouncerInteractor,
+    private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
+    powerInteractor: PowerInteractor,
+) : CoreStartable {
+
+    private var pickupSensor: Sensor? = null
+    private val isListening: MutableStateFlow<Boolean> = MutableStateFlow(false)
+    private val stoppedListening: Flow<Unit> = isListening.filterNot { it }.map {} // map to Unit
+
+    private val onAwakeKeyguard: Flow<Boolean> =
+        combine(
+            powerInteractor.isInteractive,
+            keyguardInteractor.isKeyguardVisible,
+        ) { isInteractive, isKeyguardVisible ->
+            isInteractive && isKeyguardVisible
+        }
+    private val bouncerShowing: Flow<Boolean> =
+        combine(
+            primaryBouncerInteractor.isShowing,
+            alternateBouncerInteractor.isVisible,
+        ) { primaryBouncerShowing, alternateBouncerShowing ->
+            primaryBouncerShowing || alternateBouncerShowing
+        }
+    private val listenForPickupSensor: Flow<Boolean> =
+        combine(
+            stoppedListening,
+            bouncerShowing,
+            onAwakeKeyguard,
+        ) { _, bouncerShowing, onAwakeKeyguard ->
+            (onAwakeKeyguard || bouncerShowing) &&
+                deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
+        }
+
+    override fun start() {
+        if (packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+            init()
+        }
+    }
+
+    private fun init() {
+        pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
+        scope.launch {
+            listenForPickupSensor.collect { listenForPickupSensor ->
+                updateListeningState(listenForPickupSensor)
+            }
+        }
+    }
+
+    private val listener: TriggerEventListener =
+        object : TriggerEventListener() {
+            override fun onTrigger(event: TriggerEvent?) {
+                Assert.isMainThread()
+                deviceEntryFaceAuthInteractor.onDeviceLifted()
+                keyguardUpdateMonitor.requestActiveUnlock(
+                    ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE,
+                    "KeyguardLiftController"
+                )
+
+                // Not listening anymore since trigger events unregister themselves
+                isListening.value = false
+            }
+        }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.println("LiftToRunFaceAuthBinder:")
+        pw.println("  pickupSensor: $pickupSensor")
+        pw.println("  isListening: ${isListening.value}")
+    }
+
+    private fun updateListeningState(shouldListen: Boolean) {
+        if (pickupSensor == null) {
+            return
+        }
+        if (shouldListen != isListening.value) {
+            isListening.value = shouldListen
+
+            if (shouldListen) {
+                asyncSensorManager.requestTriggerSensor(listener, pickupSensor)
+            } else {
+                asyncSensorManager.cancelTriggerSensor(listener, pickupSensor)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index d2883cc..c69c9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -220,19 +220,6 @@
     @JvmField
     val WALLPAPER_PICKER_PREVIEW_ANIMATION = releasedFlag("wallpaper_picker_preview_animation")
 
-    /**
-     * TODO(b/278086361): Tracking bug
-     * Complete rewrite of the interactions between System UI and Window Manager involving keyguard
-     * state. When enabled, calls to ActivityTaskManagerService from System UI will exclusively
-     * occur from [WmLockscreenVisibilityManager] rather than the legacy KeyguardViewMediator.
-     *
-     * This flag is under development; some types of unlock may not animate properly if you enable
-     * it.
-     */
-    @JvmField
-    val KEYGUARD_WM_STATE_REFACTOR: UnreleasedFlag =
-            unreleasedFlag("keyguard_wm_state_refactor")
-
     // 300 - power menu
     // TODO(b/254512600): Tracking Bug
     @JvmField val POWER_MENU_LITE = releasedFlag("power_menu_lite")
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
deleted file mode 100644
index 5deea9b..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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;
-
-import android.content.Context;
-import android.view.WindowManager;
-
-import com.android.systemui.statusbar.phone.SystemUIDialog;
-
-public class BluetoothDialog extends SystemUIDialog {
-
-    public BluetoothDialog(Context context) {
-        super(context);
-
-        getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
-        setShowForAllUsers(true);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialogDelegate.java
new file mode 100644
index 0000000..98642d7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialogDelegate.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.view.WindowManager;
+
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import javax.inject.Inject;
+
+public class BluetoothDialogDelegate implements SystemUIDialog.Delegate{
+
+    private final SystemUIDialog.Factory mSystemUIDialogFactory;
+    @Inject
+    public BluetoothDialogDelegate(SystemUIDialog.Factory systemUIDialogFactory) {
+        mSystemUIDialogFactory = systemUIDialogFactory;
+    }
+
+    @Override
+    public SystemUIDialog createDialog() {
+        SystemUIDialog dialog = mSystemUIDialogFactory.create(this);
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+        dialog.setShowForAllUsers(true);
+        return dialog;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 1cdbe6f..17e3ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -52,6 +52,7 @@
 import com.android.systemui.CoreStartable;
 import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.util.settings.SecureSettings;
 
 import java.io.PrintWriter;
@@ -109,6 +110,7 @@
 
     private final Provider<LocalBluetoothManager> mBluetoothManagerProvider;
     private final SecureSettings mSecureSettings;
+    private final BluetoothDialogDelegate mBluetoothDialogDelegate;
 
     private boolean mEnabled;
     private String mKeyboardName;
@@ -121,16 +123,20 @@
     private int mInTabletMode = InputManager.SWITCH_STATE_UNKNOWN;
     private int mScanAttempt = 0;
     private ScanCallback mScanCallback;
-    private BluetoothDialog mDialog;
+    private SystemUIDialog mDialog;
 
     private int mState;
 
     @Inject
-    public KeyboardUI(Context context, Provider<LocalBluetoothManager> bluetoothManagerProvider,
-            SecureSettings secureSettings) {
+    public KeyboardUI(
+            Context context,
+            Provider<LocalBluetoothManager> bluetoothManagerProvider,
+            SecureSettings secureSettings,
+            BluetoothDialogDelegate bluetoothDialogDelegate) {
         mContext = context;
         this.mBluetoothManagerProvider = bluetoothManagerProvider;
         mSecureSettings = secureSettings;
+        mBluetoothDialogDelegate = bluetoothDialogDelegate;
     }
 
     @Override
@@ -437,7 +443,7 @@
                             new BluetoothDialogClickListener();
                     DialogInterface.OnDismissListener dismissListener =
                             new BluetoothDialogDismissListener();
-                    mDialog = new BluetoothDialog(mContext);
+                    mDialog = mBluetoothDialogDelegate.createDialog();
                     mDialog.setTitle(R.string.enable_bluetooth_title);
                     mDialog.setMessage(R.string.enable_bluetooth_message);
                     mDialog.setPositiveButton(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
index 4ed8120..5ef5ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
@@ -43,4 +43,13 @@
             { "new sticky keys state received: $str1" }
         )
     }
-}
\ No newline at end of file
+
+    fun logNewSettingValue(enabled: Boolean) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { bool1 = enabled },
+            { "sticky key setting changed, new state: ${if (bool1) "enabled" else "disabled"}" }
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
index 34d2888..ec29bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
@@ -19,8 +19,10 @@
 import android.hardware.input.InputManager
 import android.hardware.input.InputManager.StickyModifierStateListener
 import android.hardware.input.StickyModifierState
+import android.provider.Settings
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
 import com.android.systemui.keyboard.stickykeys.shared.model.Locked
@@ -30,14 +32,19 @@
 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL
 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META
 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
 import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
 import javax.inject.Inject
 
 interface StickyKeysRepository {
@@ -45,11 +52,15 @@
     val settingEnabled: Flow<Boolean>
 }
 
+@SysUISingleton
+@OptIn(ExperimentalCoroutinesApi::class)
 class StickyKeysRepositoryImpl
 @Inject
 constructor(
     private val inputManager: InputManager,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val secureSettings: SecureSettings,
+    userRepository: UserRepository,
     private val stickyKeysLogger: StickyKeysLogger,
 ) : StickyKeysRepository {
 
@@ -66,8 +77,26 @@
             .onEach { stickyKeysLogger.logNewStickyKeysReceived(it) }
             .flowOn(backgroundDispatcher)
 
-    // TODO(b/319837892): Implement reading actual setting
-    override val settingEnabled: StateFlow<Boolean> = MutableStateFlow(true)
+    override val settingEnabled: Flow<Boolean> =
+        userRepository.selectedUserInfo
+            .flatMapLatest { stickyKeySettingObserver(it.id) }
+            .flowOn(backgroundDispatcher)
+
+    private fun stickyKeySettingObserver(userId: Int): Flow<Boolean> {
+        return secureSettings
+            .observerFlow(userId, SETTING_KEY)
+            .onStart { emit(Unit) }
+            .map { isSettingEnabledForCurrentUser(userId) }
+            .distinctUntilChanged()
+            .onEach { stickyKeysLogger.logNewSettingValue(it) }
+    }
+
+    private fun isSettingEnabledForCurrentUser(userId: Int) =
+        secureSettings.getIntForUser(
+            /* name= */ SETTING_KEY,
+            /* default= */ 0,
+            /* userHandle= */ userId
+        ) != 0
 
     private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> {
         val keys = linkedMapOf<ModifierKey, Locked>()
@@ -88,5 +117,6 @@
 
     companion object {
         const val TAG = "StickyKeysRepositoryImpl"
+        const val SETTING_KEY = Settings.Secure.ACCESSIBILITY_STICKY_KEYS
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index e2ab20e..f10b87e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -77,7 +77,6 @@
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.dagger.qualifiers.Application;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier;
 import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindViewBinder;
 import com.android.systemui.keyguard.ui.binder.WindowManagerLockscreenVisibilityViewBinder;
@@ -329,7 +328,7 @@
         mFlags = featureFlags;
         mPowerInteractor = powerInteractor;
 
-        if (mFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+        if (KeyguardWmStateRefactor.isEnabled()) {
             WindowManagerLockscreenVisibilityViewBinder.bind(
                     wmLockscreenVisibilityViewModel,
                     wmLockscreenVisibilityManager,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 01ba0d2..53c81e5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -419,7 +419,7 @@
      */
     fun canPerformInWindowLauncherAnimations(): Boolean {
         // TODO(b/278086361): Refactor in-window animations.
-        return !featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR) &&
+        return !KeyguardWmStateRefactor.isEnabled &&
                 isSupportedLauncherUnderneath() &&
                 // If the launcher is underneath, but we're about to launch an activity, don't do
                 // the animations since they won't be visible.
@@ -866,7 +866,7 @@
         }
 
         surfaceBehindRemoteAnimationTargets?.forEach { surfaceBehindRemoteAnimationTarget ->
-            if (!featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (!KeyguardWmStateRefactor.isEnabled) {
                 val surfaceHeight: Int =
                         surfaceBehindRemoteAnimationTarget.screenSpaceBounds.height()
 
@@ -1005,7 +1005,7 @@
         if (keyguardStateController.isShowing) {
             // Hide the keyguard, with no fade out since we animated it away during the unlock.
 
-            if (!featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (!KeyguardWmStateRefactor.isEnabled) {
                 keyguardViewController.hide(
                         surfaceBehindRemoteAnimationStartTime,
                         0 /* fadeOutDuration */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 50caf17..794befa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -139,7 +139,6 @@
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.flags.SystemPropertiesHelper;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -175,8 +174,6 @@
 import com.android.systemui.wallpapers.data.repository.WallpaperRepository;
 import com.android.wm.shell.keyguard.KeyguardTransitions;
 
-import dagger.Lazy;
-
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -186,6 +183,7 @@
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
+import dagger.Lazy;
 import kotlinx.coroutines.CoroutineDispatcher;
 
 /**
@@ -1051,7 +1049,7 @@
                 IRemoteAnimationFinishedCallback finishedCallback) {
             Trace.beginSection("mExitAnimationRunner.onAnimationStart#startKeyguardExitAnimation");
             startKeyguardExitAnimation(transit, apps, wallpapers, nonApps, finishedCallback);
-            if (mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (KeyguardWmStateRefactor.isEnabled()) {
                 mWmLockscreenVisibilityManager.get().onKeyguardGoingAwayRemoteAnimationStart(
                         transit, apps, wallpapers, nonApps, finishedCallback);
             }
@@ -1061,7 +1059,7 @@
         @Override // Binder interface
         public void onAnimationCancelled() {
             cancelKeyguardExitAnimation();
-            if (mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (KeyguardWmStateRefactor.isEnabled()) {
                 mWmLockscreenVisibilityManager.get().onKeyguardGoingAwayRemoteAnimationCancelled();
             }
         }
@@ -2186,6 +2184,10 @@
      */
     public void showDismissibleKeyguard() {
         if (mFoldGracePeriodProvider.isEnabled()) {
+            if (!mUpdateMonitor.isDeviceProvisioned()) {
+                Log.d(TAG, "Device not provisioned, so ignore request to show keyguard.");
+                return;
+            }
             Bundle showKeyguardUnlocked = new Bundle();
             showKeyguardUnlocked.putBoolean(OPTION_SHOW_DISMISSIBLE, true);
             showKeyguard(showKeyguardUnlocked);
@@ -2757,7 +2759,7 @@
         mUiBgExecutor.execute(() -> {
             Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ")");
 
-            if (mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (KeyguardWmStateRefactor.isEnabled()) {
                 // Handled in WmLockscreenVisibilityManager if flag is enabled.
                 return;
             }
@@ -2811,7 +2813,7 @@
             setShowingLocked(true, hidingOrGoingAway /* force */);
             mHiding = false;
 
-            if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (!KeyguardWmStateRefactor.isEnabled()) {
                 // Handled directly in StatusBarKeyguardViewManager if enabled.
                 mKeyguardViewControllerLazy.get().show(options);
             }
@@ -2888,7 +2890,7 @@
             mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(true);
 
             // Handled in WmLockscreenVisibilityManager if flag is enabled.
-            if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (!KeyguardWmStateRefactor.isEnabled()) {
                     // Don't actually hide the Keyguard at the moment, wait for window manager 
                     // until it tells us it's safe to do so with startKeyguardExitAnimation.
 		    // Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager 
@@ -2994,7 +2996,7 @@
             } else {
                 Log.d(TAG, "Hiding keyguard while occluded. Just hide the keyguard view and exit.");
 
-                if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                if (!KeyguardWmStateRefactor.isEnabled()) {
                     mKeyguardViewControllerLazy.get().hide(
                             mSystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
                             mHideAnimation.getDuration());
@@ -3030,7 +3032,7 @@
                 // If the flag is enabled, remote animation state is handled in
                 // WmLockscreenVisibilityManager.
                 if (finishedCallback != null
-                        && !mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                        && !KeyguardWmStateRefactor.isEnabled()) {
                     // There will not execute animation, send a finish callback to ensure the remote
                     // animation won't hang there.
                     try {
@@ -3056,7 +3058,7 @@
                         new IRemoteAnimationFinishedCallback() {
                             @Override
                             public void onAnimationFinished() throws RemoteException {
-                                if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                                if (!KeyguardWmStateRefactor.isEnabled()) {
                                     try {
                                         finishedCallback.onAnimationFinished();
                                     } catch (RemoteException e) {
@@ -3088,7 +3090,7 @@
             // it will dismiss the panel in that case.
             } else if (!mStatusBarStateController.leaveOpenOnKeyguardHide()
                     && apps != null && apps.length > 0) {
-                if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                if (!KeyguardWmStateRefactor.isEnabled()) {
                     // Handled in WmLockscreenVisibilityManager. Other logic in this class will
                     // short circuit when this is null.
                     mSurfaceBehindRemoteAnimationFinishedCallback = finishedCallback;
@@ -3112,7 +3114,7 @@
                         createInteractionJankMonitorConf(
                                 CUJ_LOCKSCREEN_UNLOCK_ANIMATION, "RemoteAnimationDisabled"));
 
-                if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                if (!KeyguardWmStateRefactor.isEnabled()) {
                     // Handled directly in StatusBarKeyguardViewManager if enabled.
                     mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration);
                 }
@@ -3131,7 +3133,7 @@
                         Slog.e(TAG, "Keyguard exit without a corresponding app to show.");
 
                         try {
-                            if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                            if (!KeyguardWmStateRefactor.isEnabled()) {
                                 finishedCallback.onAnimationFinished();
                             }
                         } catch (RemoteException e) {
@@ -3163,7 +3165,7 @@
                         @Override
                         public void onAnimationEnd(Animator animation) {
                             try {
-                                if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                                if (!KeyguardWmStateRefactor.isEnabled()) {
                                     finishedCallback.onAnimationFinished();
                                 }
                             } catch (RemoteException e) {
@@ -3176,7 +3178,7 @@
                         @Override
                         public void onAnimationCancel(Animator animation) {
                             try {
-                                if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+                                if (!KeyguardWmStateRefactor.isEnabled()) {
                                     finishedCallback.onAnimationFinished();
                                 }
                             } catch (RemoteException e) {
@@ -3341,7 +3343,7 @@
                 flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
             }
 
-            if (!mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+            if (!KeyguardWmStateRefactor.isEnabled()) {
                 // Handled in WmLockscreenVisibilityManager.
                 mActivityTaskManagerService.keyguardGoingAway(flags);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardWmStateRefactor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardWmStateRefactor.kt
new file mode 100644
index 0000000..ddccc5d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardWmStateRefactor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the keyguard wm state refactor flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object KeyguardWmStateRefactor {
+    /** The aconfig flag name */
+    const val FLAG_NAME = Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
+
+    /** A token used for dependency declaration */
+    val token: FlagToken
+        get() = FlagToken(FLAG_NAME, isEnabled)
+
+    /** Is the refactor enabled */
+    @JvmStatic
+    inline val isEnabled
+        get() = Flags.keyguardWmStateRefactor()
+
+    /**
+     * Called to ensure code is only run when the flag is enabled. This protects users from the
+     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+     * build to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+    /**
+     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+     * the flag is enabled to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 13e3835..e16f8dc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -51,7 +51,7 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager;
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardDataQuickAffordanceModule;
-import com.android.systemui.keyguard.data.repository.KeyguardFaceAuthModule;
+import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthModule;
 import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
 import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
@@ -104,7 +104,7 @@
             FalsingModule.class,
             KeyguardDataQuickAffordanceModule.class,
             KeyguardRepositoryModule.class,
-            KeyguardFaceAuthModule.class,
+            DeviceEntryFaceAuthModule.class,
             KeyguardDisplayModule.class,
             StartKeyguardTransitionModule.class,
             ResourceTrimmerModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthModule.kt
similarity index 85%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthModule.kt
index fede479..4cd544f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthModule.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.deviceentry.data.repository.DeviceEntryFaceAuthRepositoryImpl
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
 import com.android.systemui.deviceentry.domain.interactor.SystemUIDeviceEntryFaceAuthInteractor
+import com.android.systemui.deviceentry.ui.binder.LiftToRunFaceAuthBinder
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.TableLogBufferFactory
 import dagger.Binds
@@ -32,7 +33,7 @@
 import dagger.multibindings.IntoMap
 
 @Module
-interface KeyguardFaceAuthModule {
+interface DeviceEntryFaceAuthModule {
     @Binds
     fun deviceEntryFaceAuthRepository(
         impl: DeviceEntryFaceAuthRepositoryImpl
@@ -41,13 +42,20 @@
     @Binds
     @IntoMap
     @ClassKey(SystemUIDeviceEntryFaceAuthInteractor::class)
-    fun bind(impl: SystemUIDeviceEntryFaceAuthInteractor): CoreStartable
+    fun bindSystemUIDeviceEntryFaceAuthInteractor(
+        impl: SystemUIDeviceEntryFaceAuthInteractor
+    ): CoreStartable
 
     @Binds
     fun keyguardFaceAuthInteractor(
         impl: SystemUIDeviceEntryFaceAuthInteractor
     ): DeviceEntryFaceAuthInteractor
 
+    @Binds
+    @IntoMap
+    @ClassKey(LiftToRunFaceAuthBinder::class)
+    fun bindLiftToRunFaceAuthBinder(impl: LiftToRunFaceAuthBinder): CoreStartable
+
     companion object {
         @Provides
         @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 1437194..64e2870 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -101,7 +101,7 @@
      * Whether the device is locked or unlocked right now. This is true when keyguard has been
      * dismissed or can be dismissed by a swipe
      */
-    val isKeyguardUnlocked: StateFlow<Boolean>
+    val isKeyguardDismissible: StateFlow<Boolean>
 
     /**
      * Observable for the signal that keyguard is about to go away.
@@ -388,7 +388,7 @@
             }
             .distinctUntilChanged()
 
-    override val isKeyguardUnlocked: StateFlow<Boolean> =
+    override val isKeyguardDismissible: StateFlow<Boolean> =
         conflatedCallbackFlow {
                 val callback =
                     object : KeyguardStateController.Callback {
@@ -396,7 +396,7 @@
                             trySendWithFailureLogging(
                                 keyguardStateController.isUnlocked,
                                 TAG,
-                                "updated isKeyguardUnlocked due to onUnlockedChanged"
+                                "updated isKeyguardDismissible due to onUnlockedChanged"
                             )
                         }
 
@@ -404,7 +404,7 @@
                             trySendWithFailureLogging(
                                 keyguardStateController.isUnlocked,
                                 TAG,
-                                "updated isKeyguardUnlocked due to onKeyguardShowingChanged"
+                                "updated isKeyguardDismissible due to onKeyguardShowingChanged"
                             )
                         }
                     }
@@ -567,17 +567,17 @@
                 val callback =
                     object : KeyguardUpdateMonitorCallback() {
                         override fun onStrongAuthStateChanged(userId: Int) {
-                            trySend(userId)
+                            trySendWithFailureLogging(userId, TAG, "strong auth state change")
                         }
                     }
-
                 keyguardUpdateMonitor.registerCallback(callback)
-
                 awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
             }
             .filter { userId -> userId == userTracker.userId }
             .onStart { emit(userTracker.userId) }
             .mapLatest { userId -> keyguardUpdateMonitor.isEncryptedOrLockdown(userId) }
+            // KeyguardUpdateMonitor#registerCallback needs to be called on the main thread.
+            .flowOn(mainDispatcher)
 
     override fun isKeyguardShowing(): Boolean {
         return keyguardStateController.isShowing
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 8b2b45f..3965648 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -23,7 +23,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
@@ -230,7 +230,7 @@
                     combine(
                         startedKeyguardTransitionStep,
                         keyguardInteractor.statusBarState,
-                        keyguardInteractor.isKeyguardUnlocked,
+                        keyguardInteractor.isKeyguardDismissible,
                         ::Triple
                     ),
                     ::toQuad
@@ -307,7 +307,7 @@
     }
 
     private fun listenForLockscreenToGone() {
-        if (flags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+        if (KeyguardWmStateRefactor.isEnabled) {
             return
         }
 
@@ -324,7 +324,7 @@
     }
 
     private fun listenForLockscreenToGoneDragging() {
-        if (flags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+        if (KeyguardWmStateRefactor.isEnabled) {
             return
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 33b6373..acbd9fb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -23,7 +23,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
@@ -217,7 +217,7 @@
     }
 
     private fun listenForPrimaryBouncerToGone() {
-        if (flags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+        if (KeyguardWmStateRefactor.isEnabled) {
             // This is handled in KeyguardSecurityContainerController and
             // StatusBarKeyguardViewManager, which calls the transition interactor to kick off a
             // transition vs. listening to legacy state flags.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 36bd905..22d11d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
 import com.android.systemui.keyguard.shared.model.DozeStateModel
 import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
@@ -162,8 +163,8 @@
     /** Whether the keyguard is showing or not. */
     val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
 
-    /** Whether the keyguard is unlocked or not. */
-    val isKeyguardUnlocked: Flow<Boolean> = repository.isKeyguardUnlocked
+    /** Whether the keyguard is dismissible or not. */
+    val isKeyguardDismissible: Flow<Boolean> = repository.isKeyguardDismissible
 
     /** Whether the keyguard is occluded (covered by an activity). */
     val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
@@ -194,6 +195,9 @@
     /** Observable for the [StatusBarState] */
     val statusBarState: Flow<StatusBarState> = repository.statusBarState
 
+    /** Source of the most recent biometric unlock, such as fingerprint or face. */
+    val biometricUnlockSource: Flow<BiometricUnlockSource?> = repository.biometricUnlockSource
+
     /**
      * Observable for [BiometricUnlockModel] when biometrics like face or any fingerprint (rear,
      * side, under display) is used to unlock the device.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 3888345..a1f9425 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -56,6 +56,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
@@ -102,10 +103,10 @@
             quickAffordanceAlwaysVisible(position),
             keyguardInteractor.isDozing,
             keyguardInteractor.isKeyguardShowing,
-            shadeInteractor.anyExpansion,
+            shadeInteractor.anyExpansion.map { it < 1.0f }.distinctUntilChanged(),
             biometricSettingsRepository.isCurrentUserInLockdown,
-        ) { affordance, isDozing, isKeyguardShowing, qsExpansion, isUserInLockdown ->
-            if (!isDozing && isKeyguardShowing && (qsExpansion < 1.0f) && !isUserInLockdown) {
+        ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible, isUserInLockdown ->
+            if (!isDozing && isKeyguardShowing && isQuickSettingsVisible && !isUserInLockdown) {
                 affordance
             } else {
                 KeyguardQuickAffordanceModel.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index a02e8ac..873cc84 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -19,6 +19,7 @@
 
 import android.annotation.SuppressLint
 import android.content.res.ColorStateList
+import android.util.StateSet
 import android.view.HapticFeedbackConstants
 import android.view.View
 import androidx.lifecycle.Lifecycle
@@ -32,6 +33,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.statusbar.VibratorHelper
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.launch
 
@@ -48,6 +50,7 @@
     @SuppressLint("ClickableViewAccessibility")
     @JvmStatic
     fun bind(
+        applicationScope: CoroutineScope,
         view: DeviceEntryIconView,
         viewModel: DeviceEntryIconViewModel,
         fgViewModel: DeviceEntryForegroundViewModel,
@@ -69,7 +72,7 @@
                         view,
                         HapticFeedbackConstants.CONFIRM,
                     )
-                    viewModel.onLongPress()
+                    applicationScope.launch { viewModel.onLongPress() }
                 }
             }
 
@@ -111,6 +114,8 @@
 
         fgIconView.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
+                // Start with an empty state
+                fgIconView.setImageState(StateSet.NOTHING, /* merge */ false)
                 launch {
                     fgViewModel.viewModel.collect { viewModel ->
                         fgIconView.setImageState(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt
deleted file mode 100644
index 2feaa2e..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.systemui.keyguard.ui.binder
-
-import android.os.Trace
-import androidx.constraintlayout.widget.ConstraintLayout
-import androidx.constraintlayout.widget.ConstraintSet
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
-import com.android.systemui.lifecycle.repeatWhenAttached
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.launch
-
-/**
- * Binds the existing blueprint to the constraint layout that previews keyguard.
- *
- * This view binder should only inflate and add relevant views and apply the constraints. Actual
- * data binding should be done in {@link KeyguardPreviewRenderer}
- */
-class PreviewKeyguardBlueprintViewBinder {
-    companion object {
-
-        /**
-         * Binds the existing blueprint to the constraint layout that previews keyguard.
-         *
-         * @param constraintLayout The root view to bind to
-         * @param viewModel The instance of the view model that contains flows we collect on.
-         * @param finishedAddViewCallback Called when we have finished inflating the views.
-         */
-        fun bind(
-            constraintLayout: ConstraintLayout,
-            viewModel: KeyguardBlueprintViewModel,
-            finishedAddViewCallback: () -> Unit
-        ): DisposableHandle {
-            return constraintLayout.repeatWhenAttached {
-                repeatOnLifecycle(Lifecycle.State.CREATED) {
-                    launch {
-                        viewModel.blueprint.collect { blueprint ->
-                            val prevBluePrint = viewModel.currentBluePrint
-                            Trace.beginSection("PreviewKeyguardBlueprint#applyBlueprint")
-
-                            ConstraintSet().apply {
-                                clone(constraintLayout)
-                                val emptyLayout = ConstraintSet.Layout()
-                                knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
-                                blueprint.applyConstraints(this)
-                                // Add and remove views of sections that are not contained by the
-                                // other.
-                                blueprint.replaceViews(
-                                    prevBluePrint,
-                                    constraintLayout,
-                                    bindData = false
-                                )
-                                applyTo(constraintLayout)
-                            }
-
-                            viewModel.currentBluePrint = blueprint
-                            finishedAddViewCallback.invoke()
-                            Trace.endSection()
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
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 841bad4..a0c0095 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
@@ -41,6 +41,7 @@
 import android.widget.FrameLayout
 import android.widget.TextView
 import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
 import androidx.core.view.isInvisible
 import com.android.keyguard.ClockEventController
 import com.android.keyguard.KeyguardClockSwitch
@@ -54,15 +55,12 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
 import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
-import com.android.systemui.keyguard.ui.binder.PreviewKeyguardBlueprintViewBinder
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
@@ -124,19 +122,18 @@
     private val broadcastDispatcher: BroadcastDispatcher,
     private val lockscreenSmartspaceController: LockscreenSmartspaceController,
     private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
-    private val featureFlags: FeatureFlagsClassic,
     private val falsingManager: FalsingManager,
     private val vibratorHelper: VibratorHelper,
     private val indicationController: KeyguardIndicationController,
     private val keyguardRootViewModel: KeyguardRootViewModel,
     @Assisted bundle: Bundle,
-    private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
     private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
     private val chipbarCoordinator: ChipbarCoordinator,
     private val screenOffAnimationController: ScreenOffAnimationController,
     private val shadeInteractor: ShadeInteractor,
     private val secureSettings: SecureSettings,
     private val communalTutorialViewModel: CommunalTutorialIndicatorViewModel,
+    private val defaultShortcutsSection: DefaultShortcutsSection,
 ) {
     val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
     private val width: Int = bundle.getInt(KEY_VIEW_WIDTH)
@@ -393,32 +390,32 @@
 
         setUpUdfps(previewContext, rootView)
 
-        disposables.add(
-            PreviewKeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) {
-                if (keyguardBottomAreaRefactor()) {
-                    setupShortcuts(keyguardRootView)
-                }
+        if (keyguardBottomAreaRefactor()) {
+            setupShortcuts(keyguardRootView)
+        }
 
-                if (!shouldHideClock) {
-                    setUpClock(previewContext, rootView)
-                    KeyguardPreviewClockViewBinder.bind(
-                        largeClockHostView,
-                        smallClockHostView,
-                        clockViewModel,
-                    )
-                }
+        if (!shouldHideClock) {
+            setUpClock(previewContext, rootView)
+            KeyguardPreviewClockViewBinder.bind(
+                largeClockHostView,
+                smallClockHostView,
+                clockViewModel,
+            )
+        }
 
-                setUpSmartspace(previewContext, rootView)
-                smartSpaceView?.let {
-                    KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel)
-                }
-
-                setupCommunalTutorialIndicator(keyguardRootView)
-            }
-        )
+        setUpSmartspace(previewContext, rootView)
+        smartSpaceView?.let { KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel) }
+        setupCommunalTutorialIndicator(keyguardRootView)
     }
 
     private fun setupShortcuts(keyguardRootView: ConstraintLayout) {
+        // Add shortcuts
+        val cs = ConstraintSet()
+        cs.clone(keyguardRootView)
+        defaultShortcutsSection.addViews(keyguardRootView)
+        defaultShortcutsSection.applyConstraints(cs)
+        cs.applyTo(keyguardRootView)
+
         keyguardRootView.findViewById<LaunchableImageView?>(R.id.start_button)?.let { imageView ->
             shortcutsBindings.add(
                 KeyguardQuickAffordanceViewBinder.bind(
@@ -476,53 +473,40 @@
     }
 
     private fun setUpClock(previewContext: Context, parentView: ViewGroup) {
-        largeClockHostView =
-            if (KeyguardShadeMigrationNssl.isEnabled) {
-                parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view_large)
-            } else {
-                val hostView = FrameLayout(previewContext)
-                hostView.layoutParams =
-                    FrameLayout.LayoutParams(
-                        FrameLayout.LayoutParams.MATCH_PARENT,
-                        FrameLayout.LayoutParams.MATCH_PARENT,
-                    )
-                parentView.addView(hostView)
-                hostView
-            }
+        val resources = parentView.resources
+        largeClockHostView = FrameLayout(previewContext)
+        largeClockHostView.layoutParams =
+            FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.MATCH_PARENT,
+                FrameLayout.LayoutParams.MATCH_PARENT,
+            )
+        parentView.addView(largeClockHostView)
         largeClockHostView.isInvisible = true
 
-        smallClockHostView =
-            if (KeyguardShadeMigrationNssl.isEnabled) {
-                parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view)
-            } else {
-                val resources = parentView.resources
-                val hostView = FrameLayout(previewContext)
-                val layoutParams =
-                    FrameLayout.LayoutParams(
-                        FrameLayout.LayoutParams.WRAP_CONTENT,
-                        resources.getDimensionPixelSize(
-                            com.android.systemui.customization.R.dimen.small_clock_height
-                        )
-                    )
-                layoutParams.topMargin =
-                    KeyguardPreviewSmartspaceViewModel.getStatusBarHeight(resources) +
-                        resources.getDimensionPixelSize(
-                            com.android.systemui.customization.R.dimen.small_clock_padding_top
-                        )
-                hostView.layoutParams = layoutParams
-
-                hostView.setPaddingRelative(
-                    resources.getDimensionPixelSize(
-                        com.android.systemui.customization.R.dimen.clock_padding_start
-                    ),
-                    0,
-                    0,
-                    0
+        smallClockHostView = FrameLayout(previewContext)
+        val layoutParams =
+            FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.WRAP_CONTENT,
+                resources.getDimensionPixelSize(
+                    com.android.systemui.customization.R.dimen.small_clock_height
                 )
-                hostView.clipChildren = false
-                parentView.addView(hostView)
-                hostView
-            }
+            )
+        layoutParams.topMargin =
+            KeyguardPreviewSmartspaceViewModel.getStatusBarHeight(resources) +
+                resources.getDimensionPixelSize(
+                    com.android.systemui.customization.R.dimen.small_clock_padding_top
+                )
+        smallClockHostView.layoutParams = layoutParams
+        smallClockHostView.setPaddingRelative(
+            resources.getDimensionPixelSize(
+                com.android.systemui.customization.R.dimen.clock_padding_start
+            ),
+            0,
+            0,
+            0
+        )
+        smallClockHostView.clipChildren = false
+        parentView.addView(smallClockHostView)
         smallClockHostView.isInvisible = true
 
         // TODO (b/283465254): Move the listeners to KeyguardClockRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 0bf9ad0..3fc9b42 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -31,6 +31,7 @@
 import com.android.keyguard.LockIconViewController
 import com.android.systemui.Flags.keyguardBottomAreaRefactor
 import com.android.systemui.biometrics.AuthController
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -46,6 +47,7 @@
 import com.android.systemui.statusbar.VibratorHelper
 import dagger.Lazy
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
 /** Includes the device entry icon. */
@@ -53,6 +55,7 @@
 class DefaultDeviceEntrySection
 @Inject
 constructor(
+    @Application private val applicationScope: CoroutineScope,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val authController: AuthController,
     private val windowManager: WindowManager,
@@ -91,6 +94,7 @@
         if (DeviceEntryUdfpsRefactor.isEnabled) {
             constraintLayout.findViewById<DeviceEntryIconView?>(deviceEntryIconViewId)?.let {
                 DeviceEntryIconViewBinder.bind(
+                    applicationScope,
                     it,
                     deviceEntryIconViewModel.get(),
                     deviceEntryForegroundViewModel.get(),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
index 400d0dc..a651c10 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
@@ -87,7 +87,8 @@
             return
         }
         // This moves the existing NSSL view to a different parent, as the controller is a
-        // singleton and recreating it has other bad side effects
+        // singleton and recreating it has other bad side effects.
+        // In the SceneContainer, this is done by the NotificationSection composable.
         notificationPanelView.findViewById<View?>(R.id.notification_stack_scroller)?.let {
             (it.parent as ViewGroup).removeView(it)
             sharedNotificationContainer.addNotificationStackScrollLayout(it)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index eacaa40..a3d5453 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -20,6 +20,7 @@
 import android.animation.IntEvaluator
 import com.android.keyguard.KeyguardViewController
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntrySourceInteractor
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -56,6 +57,7 @@
     private val sceneContainerFlags: SceneContainerFlags,
     private val keyguardViewController: Lazy<KeyguardViewController>,
     private val deviceEntryInteractor: DeviceEntryInteractor,
+    private val deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
 ) {
     private val intEvaluator = IntEvaluator()
     private val floatEvaluator = FloatEvaluator()
@@ -208,14 +210,13 @@
             }
         }
 
-    fun onLongPress() {
-        // TODO (b/309804148): play auth ripple via an interactor
-
+    suspend fun onLongPress() {
         if (sceneContainerFlags.isEnabled()) {
             deviceEntryInteractor.attemptDeviceEntry()
         } else {
             keyguardViewController.get().showPrimaryBouncer(/* scrim */ true)
         }
+        deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon()
     }
 
     private fun DeviceEntryIconView.IconType.toAccessibilityHintType():
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
index a3029b2..23ee00d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
@@ -146,7 +146,7 @@
                 null,
                 UserHandle.ALL
             )
-            userTracker.addCallback(userTrackerCallback, backgroundExecutor)
+            userTracker.addCallback(userTrackerCallback, mainExecutor)
             loadSavedComponents()
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
index 11d0be5..a618490 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.mediaprojection
 
-import android.os.IBinder
+import android.app.ActivityOptions.LaunchCookie
 import android.os.Parcel
 import android.os.Parcelable
 
@@ -24,12 +24,12 @@
  * Class that represents an area that should be captured. Currently it has only a launch cookie that
  * represents a task but we potentially could add more identifiers e.g. for a pair of tasks.
  */
-data class MediaProjectionCaptureTarget(val launchCookie: IBinder?) : Parcelable {
+data class MediaProjectionCaptureTarget(val launchCookie: LaunchCookie?) : Parcelable {
 
-    constructor(parcel: Parcel) : this(parcel.readStrongBinder())
+    constructor(parcel: Parcel) : this(LaunchCookie.readFromParcel(parcel))
 
     override fun writeToParcel(dest: Parcel, flags: Int) {
-        dest.writeStrongBinder(launchCookie)
+        LaunchCookie.writeToParcel(launchCookie, dest)
     }
 
     override fun describeContents(): Int = 0
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
index 50e9e751..4685c5a 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
@@ -16,6 +16,7 @@
 package com.android.systemui.mediaprojection.appselector
 
 import android.app.ActivityOptions
+import android.app.ActivityOptions.LaunchCookie
 import android.content.Intent
 import android.content.res.Configuration
 import android.content.res.Resources
@@ -24,9 +25,7 @@
 import android.media.projection.MediaProjectionManager.EXTRA_MEDIA_PROJECTION
 import android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL
 import android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_TASK
-import android.os.Binder
 import android.os.Bundle
-import android.os.IBinder
 import android.os.ResultReceiver
 import android.os.UserHandle
 import android.util.Log
@@ -163,9 +162,9 @@
 
         val intent = createIntent(targetInfo)
 
-        val launchToken: IBinder = Binder("media_projection_launch_token")
+        val launchCookie = LaunchCookie("media_projection_launch_token")
         val activityOptions = ActivityOptions.makeBasic()
-        activityOptions.launchCookie = launchToken
+        activityOptions.setLaunchCookie(launchCookie)
 
         val userHandle = mMultiProfilePagerAdapter.activeListAdapter.userHandle
 
@@ -175,7 +174,7 @@
         // is created and ready to be captured.
         val activityStarted =
             activityLauncher.startActivityAsUser(intent, userHandle, activityOptions.toBundle()) {
-                returnSelectedApp(launchToken)
+                returnSelectedApp(launchCookie)
             }
 
         // Rely on the ActivityManager to pop up a dialog regarding app suspension
@@ -233,7 +232,7 @@
         }
     }
 
-    override fun returnSelectedApp(launchCookie: IBinder) {
+    override fun returnSelectedApp(launchCookie: LaunchCookie) {
         taskSelected = true
         if (intent.hasExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER)) {
             // The client requested to return the result in the result receiver instead of
@@ -255,7 +254,7 @@
             val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION)
             val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder)
 
-            projection.launchCookie = launchCookie
+            projection.setLaunchCookie(launchCookie)
 
             val intent = Intent()
             intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder())
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
index 93c3bce..f204b3e 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
@@ -1,6 +1,6 @@
 package com.android.systemui.mediaprojection.appselector
 
-import android.os.IBinder
+import android.app.ActivityOptions.LaunchCookie
 
 /**
  * Interface that allows to continue the media projection flow and return the selected app
@@ -11,5 +11,5 @@
      * Return selected app to the original caller of the media projection app picker.
      * @param launchCookie launch cookie of the launched activity of the target app
      */
-    fun returnSelectedApp(launchCookie: IBinder)
+    fun returnSelectedApp(launchCookie: LaunchCookie)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
index ba837db..a811065 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
@@ -17,10 +17,10 @@
 package com.android.systemui.mediaprojection.appselector.view
 
 import android.app.ActivityOptions
+import android.app.ActivityOptions.LaunchCookie
 import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
 import android.app.IActivityTaskManager
 import android.graphics.Rect
-import android.os.Binder
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -121,7 +121,7 @@
     }
 
     override fun onRecentAppClicked(task: RecentTask, view: View) {
-        val launchCookie = Binder()
+        val launchCookie = LaunchCookie()
         val activityOptions =
             ActivityOptions.makeScaleUpAnimation(
                 view,
@@ -132,7 +132,7 @@
             )
         activityOptions.pendingIntentBackgroundActivityStartMode =
             MODE_BACKGROUND_ACTIVITY_START_ALLOWED
-        activityOptions.launchCookie = launchCookie
+        activityOptions.setLaunchCookie(launchCookie)
         activityOptions.launchDisplayId = task.displayId
 
         activityTaskManager.startActivityFromRecents(task.taskId, activityOptions.toBundle())
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 039372d..8b034b2 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -28,6 +28,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityOptions.LaunchCookie;
 import android.app.AlertDialog;
 import android.app.StatusBarManager;
 import android.content.Context;
@@ -146,6 +147,13 @@
                 final IMediaProjection projection =
                         MediaProjectionServiceHelper.createOrReuseProjection(mUid, mPackageName,
                                 mReviewGrantedConsentRequired);
+
+                LaunchCookie launchCookie = launchingIntent.getParcelableExtra(
+                        MediaProjectionManager.EXTRA_LAUNCH_COOKIE, LaunchCookie.class);
+                if (launchCookie != null) {
+                    projection.setLaunchCookie(launchCookie);
+                }
+
                 // Automatically grant consent if a system-privileged component is recording.
                 final Intent intent = new Intent();
                 intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
new file mode 100644
index 0000000..6eb6226
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.model
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.ObservableTransitionState
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+import dagger.Lazy
+import javax.inject.Inject
+
+/**
+ * A plugin for [SysUiState] that provides overrides for certain state flags that must be pulled
+ * from the scene framework when that framework is enabled.
+ */
+@SysUISingleton
+class SceneContainerPlugin
+@Inject
+constructor(
+    private val interactor: Lazy<SceneInteractor>,
+) {
+    /**
+     * Returns an override value for the given [flag] or `null` if the scene framework isn't enabled
+     * or if the flag value doesn't need to be overridden.
+     */
+    fun flagValueOverride(flag: Int): Boolean? {
+        if (!SceneContainerFlag.isEnabled) {
+            return null
+        }
+
+        val transitionState = interactor.get().transitionState.value
+        val idleTransitionStateOrNull = transitionState as? ObservableTransitionState.Idle
+        val currentSceneOrNull = idleTransitionStateOrNull?.scene
+        return currentSceneOrNull?.let { sceneKey -> EvaluatorByFlag[flag]?.invoke(sceneKey) }
+    }
+
+    companion object {
+
+        /**
+         * Value evaluator function by state flag ID.
+         *
+         * The value evaluator function can be invoked, passing in the current [SceneKey] to know
+         * the override value of the flag ID.
+         *
+         * If the map doesn't contain an entry for a certain flag ID, it means that it doesn't need
+         * to be overridden by the scene framework.
+         */
+        val EvaluatorByFlag =
+            mapOf<Int, (SceneKey) -> Boolean>(
+                SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to { it != SceneKey.Gone },
+                SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to { it == SceneKey.Shade },
+                SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it == SceneKey.QuickSettings },
+                SYSUI_STATE_BOUNCER_SHOWING to { it == SceneKey.Bouncer },
+                SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to { it == SceneKey.Lockscreen },
+            )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
index 3cdcb2c..2dd2327 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
@@ -41,13 +41,15 @@
     public static final boolean DEBUG = false;
 
     private final DisplayTracker mDisplayTracker;
+    private final SceneContainerPlugin mSceneContainerPlugin;
     private @QuickStepContract.SystemUiStateFlags int mFlags;
     private final List<SysUiStateCallback> mCallbacks = new ArrayList<>();
     private int mFlagsToSet = 0;
     private int mFlagsToClear = 0;
 
-    public SysUiState(DisplayTracker displayTracker) {
+    public SysUiState(DisplayTracker displayTracker, SceneContainerPlugin sceneContainerPlugin) {
         mDisplayTracker = displayTracker;
+        mSceneContainerPlugin = sceneContainerPlugin;
     }
 
     /**
@@ -71,6 +73,16 @@
 
     /** Methods to this call can be chained together before calling {@link #commitUpdate(int)}. */
     public SysUiState setFlag(int flag, boolean enabled) {
+        final Boolean overrideOrNull = mSceneContainerPlugin.flagValueOverride(flag);
+        if (overrideOrNull != null && enabled != overrideOrNull) {
+            if (DEBUG) {
+                Log.d(TAG, "setFlag for flag " + flag + " and value " + enabled + " overridden to "
+                        + overrideOrNull + " by scene container plugin");
+            }
+
+            enabled = overrideOrNull;
+        }
+
         if (enabled) {
             mFlagsToSet |= flag;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index d7e062f..7d13397 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -41,6 +41,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -55,12 +56,14 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.systemui.Dumpable;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 import com.android.systemui.recents.OverviewProxyService;
@@ -79,6 +82,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -101,6 +105,7 @@
     private static final String TAG = NavBarHelper.class.getSimpleName();
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Executor mMainExecutor;
     private final AccessibilityManager mAccessibilityManager;
     private final Lazy<AssistManager> mAssistManagerLazy;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -185,7 +190,12 @@
             DisplayTracker displayTracker,
             NotificationShadeWindowController notificationShadeWindowController,
             DumpManager dumpManager,
-            CommandQueue commandQueue) {
+            CommandQueue commandQueue,
+            @Main Executor mainExecutor) {
+        // b/319489709: This component shouldn't be running for a non-primary user
+        if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
+            Log.wtf(TAG, "Unexpected initialization for non-primary user", new Throwable());
+        }
         mContext = context;
         mNotificationShadeWindowController = notificationShadeWindowController;
         mCommandQueue = commandQueue;
@@ -201,6 +211,7 @@
         mWm = wm;
         mDefaultDisplayId = displayTracker.getDefaultDisplayId();
         mEdgeBackGestureHandler = edgeBackGestureHandlerFactory.create(context);
+        mMainExecutor = mainExecutor;
 
         mNavBarMode = navigationModeController.addListener(this);
         mCommandQueue.addCallback(this);
@@ -370,7 +381,7 @@
             // permission
             final List<String> a11yButtonTargets =
                     mAccessibilityManager.getAccessibilityShortcutTargets(
-                            AccessibilityManager.ACCESSIBILITY_BUTTON);
+                            ShortcutConstants.UserShortcutType.SOFTWARE);
             final int requestingServices = a11yButtonTargets.size();
 
             clickable = requestingServices >= 1;
@@ -418,7 +429,11 @@
     @Override
     public void onConnectionChanged(boolean isConnected) {
         if (isConnected) {
-            updateAssistantAvailability();
+            // We add the OPS callback during construction, so if the service is already connected
+            // then we will try to get the AssistManager dependency which itself has an indirect
+            // dependency on NavBarHelper leading to a cycle. For now, we can defer updating the
+            // assistant availability.
+            mMainExecutor.execute(this::updateAssistantAvailability);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index fa03dc2..b3d848c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -34,6 +34,8 @@
 import androidx.core.os.postDelayed
 import androidx.core.view.isVisible
 import androidx.dynamicanimation.animation.DynamicAnimation
+import com.android.internal.jank.Cuj.CUJ_BACK_PANEL_ARROW
+import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.util.LatencyTracker
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.NavigationEdgeBackPlugin
@@ -86,6 +88,7 @@
     private val vibratorHelper: VibratorHelper,
     private val configurationController: ConfigurationController,
     private val latencyTracker: LatencyTracker,
+    private val interactionJankMonitor: InteractionJankMonitor,
 ) : ViewController<BackPanel>(BackPanel(context, latencyTracker)), NavigationEdgeBackPlugin {
 
     /**
@@ -103,6 +106,7 @@
         private val vibratorHelper: VibratorHelper,
         private val configurationController: ConfigurationController,
         private val latencyTracker: LatencyTracker,
+        private val interactionJankMonitor: InteractionJankMonitor,
     ) {
         /** Construct a [BackPanelController]. */
         fun create(context: Context): BackPanelController {
@@ -115,6 +119,7 @@
                     vibratorHelper,
                     configurationController,
                     latencyTracker,
+                    interactionJankMonitor
                 )
             backPanelController.init()
             return backPanelController
@@ -183,7 +188,7 @@
         /* Arrow is animating in */
         ENTRY,
 
-        /* could be entry, neutral, or stretched, releasing will commit back */
+        /* releasing will commit back */
         ACTIVE,
 
         /* releasing will cancel back */
@@ -813,7 +818,7 @@
                     scale =
                         when (currentState) {
                             GestureState.ACTIVE,
-                            GestureState.FLUNG, -> params.activeIndicator.scale
+                            GestureState.FLUNG -> params.activeIndicator.scale
                             GestureState.COMMITTED -> params.committedIndicator.scale
                             else -> params.preThresholdIndicator.scale
                         },
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 21de185..958ace35 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -26,8 +26,6 @@
 import android.database.ContentObserver;
 import android.os.BatteryManager;
 import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
 import android.os.IThermalEventListener;
 import android.os.IThermalService;
 import android.os.PowerManager;
@@ -97,7 +95,6 @@
     private Future mLastShowWarningTask;
     private boolean mEnableSkinTemperatureWarning;
     private boolean mEnableUsbTemperatureAlarm;
-    private final HandlerThread mHandlerThread;
 
     private int mLowBatteryAlertCloseLevel;
     private final int[] mLowBatteryReminderLevels = new int[2];
@@ -170,8 +167,6 @@
         mPowerManager = powerManager;
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mUserTracker = userTracker;
-        mHandlerThread = new HandlerThread("PowerUI");
-        mHandlerThread.start();
     }
 
     public void start() {
@@ -190,8 +185,7 @@
                 false, obs, UserHandle.USER_ALL);
         updateBatteryWarningLevels();
         mReceiver.init();
-        mUserTracker.addCallback(mUserChangedCallback,
-                    new HandlerExecutor(mHandlerThread.getThreadHandler()));
+        mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
         mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
 
         // Check to see if we need to let the user know that the phone previously shut down due
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
index bcd09bd..dc39c97 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager.ResolveInfoFlags
 import android.os.UserHandle
 import android.service.quicksettings.TileService
+import androidx.annotation.GuardedBy
 import com.android.systemui.common.data.repository.PackageChangeRepository
 import com.android.systemui.common.data.shared.model.PackageChangeModel
 import com.android.systemui.dagger.SysUISingleton
@@ -32,12 +33,13 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.util.kotlin.isComponentActuallyEnabled
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
 
 interface InstalledTilesComponentRepository {
 
@@ -49,33 +51,39 @@
 @Inject
 constructor(
     @Application private val applicationContext: Context,
-    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    @Background private val backgroundScope: CoroutineScope,
     private val packageChangeRepository: PackageChangeRepository
 ) : InstalledTilesComponentRepository {
 
-    override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> {
-        /*
-         * In order to query [PackageManager] for different users, this implementation will call
-         * [Context.createContextAsUser] and retrieve the [PackageManager] from that context.
-         */
-        val packageManager =
-            if (applicationContext.userId == userId) {
-                applicationContext.packageManager
-            } else {
-                applicationContext
-                    .createContextAsUser(
-                        UserHandle.of(userId),
-                        /* flags */ 0,
-                    )
-                    .packageManager
+    @GuardedBy("userMap") private val userMap = mutableMapOf<Int, Flow<Set<ComponentName>>>()
+
+    override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> =
+        synchronized(userMap) {
+            userMap.getOrPut(userId) {
+                /*
+                 * In order to query [PackageManager] for different users, this implementation will
+                 * call [Context.createContextAsUser] and retrieve the [PackageManager] from that
+                 * context.
+                 */
+                val packageManager =
+                    if (applicationContext.userId == userId) {
+                        applicationContext.packageManager
+                    } else {
+                        applicationContext
+                            .createContextAsUser(
+                                UserHandle.of(userId),
+                                /* flags */ 0,
+                            )
+                            .packageManager
+                    }
+                packageChangeRepository
+                    .packageChanged(UserHandle.of(userId))
+                    .onStart { emit(PackageChangeModel.Empty) }
+                    .map { reloadComponents(userId, packageManager) }
+                    .distinctUntilChanged()
+                    .shareIn(backgroundScope, SharingStarted.WhileSubscribed(), replay = 1)
             }
-        return packageChangeRepository
-            .packageChanged(UserHandle.of(userId))
-            .onStart { emit(PackageChangeModel.Empty) }
-            .map { reloadComponents(userId, packageManager) }
-            .distinctUntilChanged()
-            .flowOn(backgroundDispatcher)
-    }
+        }
 
     @WorkerThread
     private fun reloadComponents(userId: Int, packageManager: PackageManager): Set<ComponentName> {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index d04e4f5..53f287b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -33,11 +33,13 @@
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.res.R;
 
 import java.util.Objects;
 
@@ -52,7 +54,10 @@
     private boolean mDisabledByPolicy = false;
     private int mTint;
     @Nullable
-    private QSTile.Icon mLastIcon;
+    @VisibleForTesting
+    QSTile.Icon mLastIcon;
+
+    private boolean mIconChangeScheduled;
 
     private ValueAnimator mColorAnimator = new ValueAnimator();
 
@@ -112,6 +117,7 @@
     }
 
     protected void updateIcon(ImageView iv, State state, boolean allowAnimations) {
+        mIconChangeScheduled = false;
         final QSTile.Icon icon = state.iconSupplier != null ? state.iconSupplier.get() : state.icon;
         if (!Objects.equals(icon, iv.getTag(R.id.qs_icon_tag))) {
             boolean shouldAnimate = allowAnimations && shouldAnimate(iv);
@@ -167,7 +173,12 @@
             mState = state.state;
             mDisabledByPolicy = state.disabledByPolicy;
             if (mTint != 0 && allowAnimations && shouldAnimate(iv)) {
-                animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state, allowAnimations));
+                mIconChangeScheduled = true;
+                animateGrayScale(mTint, color, iv, () -> {
+                    if (mIconChangeScheduled) {
+                        updateIcon(iv, state, allowAnimations);
+                    }
+                });
             } else {
                 setTint(iv, color);
                 updateIcon(iv, state, allowAnimations);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index cc53aab..7d86a6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents;
 
+import static android.app.Flags.keyguardPrivateNotifications;
 import static android.content.Intent.ACTION_PACKAGE_ADDED;
 import static android.content.Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
@@ -81,12 +82,13 @@
 import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.util.ScreenshotRequest;
 import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.KeyguardWmStateRefactor;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
 import com.android.systemui.model.SysUiState;
@@ -167,13 +169,16 @@
     private final Optional<UnfoldTransitionProgressForwarder> mUnfoldTransitionProgressForwarder;
     private final UiEventLogger mUiEventLogger;
     private final DisplayTracker mDisplayTracker;
-
     private Region mActiveNavBarRegion;
 
+    private final BroadcastDispatcher mBroadcastDispatcher;
+
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
     private boolean mBound;
     private boolean mIsEnabled;
+
+    private boolean mIsNonPrimaryUser;
     private int mCurrentBoundedUserId = -1;
     private boolean mInputFocusTransferStarted;
     private float mInputFocusTransferStartY;
@@ -419,6 +424,21 @@
         retryConnectionWithBackoff();
     };
 
+    private final BroadcastReceiver mUserEventReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Objects.equals(intent.getAction(), Intent.ACTION_USER_UNLOCKED)) {
+                if (keyguardPrivateNotifications()) {
+                    // Start the overview connection to the launcher service
+                    // Connect if user hasn't connected yet
+                    if (getProxy() == null) {
+                        startConnectionToCurrentUser();
+                    }
+                }
+            }
+        }
+    };
+
     private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -493,10 +513,6 @@
             notifySystemUiStateFlags(mSysUiState.getFlags());
 
             notifyConnectionChanged();
-            if (mDoneUserChanging != null) {
-                mDoneUserChanging.run();
-                mDoneUserChanging = null;
-            }
         }
 
         @Override
@@ -551,14 +567,11 @@
         }
     };
 
-    private Runnable mDoneUserChanging;
     private final UserTracker.Callback mUserChangedCallback =
             new UserTracker.Callback() {
                 @Override
-                public void onUserChanging(int newUser, @NonNull Context userContext,
-                        @NonNull Runnable resultCallback) {
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
                     mConnectionBackoffAttempts = 0;
-                    mDoneUserChanging = resultCallback;
                     internalConnectToCurrentUser("User changed");
                 }
             };
@@ -586,11 +599,13 @@
             FeatureFlags featureFlags,
             SceneContainerFlags sceneContainerFlags,
             DumpManager dumpManager,
-            Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder
+            Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder,
+            BroadcastDispatcher broadcastDispatcher
     ) {
         // b/241601880: This component shouldn't be running for a non-primary user
-        if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
-            Log.e(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
+        mIsNonPrimaryUser = !Process.myUserHandle().equals(UserHandle.SYSTEM);
+        if (mIsNonPrimaryUser) {
+            Log.wtf(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
         }
 
         mContext = context;
@@ -615,8 +630,9 @@
         mUiEventLogger = uiEventLogger;
         mDisplayTracker = displayTracker;
         mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;
+        mBroadcastDispatcher = broadcastDispatcher;
 
-        if (!featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+        if (!KeyguardWmStateRefactor.isEnabled()) {
             mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
         } else {
             mSysuiUnlockAnimationController = inWindowLauncherUnlockAnimationManager;
@@ -635,6 +651,12 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
 
+        if (keyguardPrivateNotifications()) {
+            mBroadcastDispatcher.registerReceiver(mUserEventReceiver,
+                    new IntentFilter(Intent.ACTION_USER_UNLOCKED),
+                    null /* executor */, UserHandle.ALL);
+        }
+
         // Listen for status bar state changes
         statusBarWinController.registerCallback(mStatusBarWindowCallback);
         mScreenshotHelper = new ScreenshotHelper(context);
@@ -772,6 +794,13 @@
     }
 
     private void internalConnectToCurrentUser(String reason) {
+        if (mIsNonPrimaryUser) {
+            // This should not happen, but if any per-user SysUI component has a dependency on OPS,
+            // then this could get triggered
+            Log.w(TAG_OPS, "Skipping connection to overview service due to non-primary user "
+                    + "caller");
+            return;
+        }
         disconnectFromLauncherService(reason);
 
         // If user has not setup yet or already connected, do not try to connect
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 b3d2e09..b9e9fe7 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
@@ -171,28 +171,6 @@
         return repository.setVisible(isVisible)
     }
 
-    /** True if there is a transition happening from and to the specified scenes. */
-    fun transitioning(from: SceneKey, to: SceneKey): StateFlow<Boolean> {
-        fun transitioning(
-            state: ObservableTransitionState,
-            from: SceneKey,
-            to: SceneKey,
-        ): Boolean {
-            return (state as? ObservableTransitionState.Transition)?.let {
-                it.fromScene == from && it.toScene == to
-            }
-                ?: false
-        }
-
-        return transitionState
-            .map { state -> transitioning(state, from, to) }
-            .stateIn(
-                scope = applicationScope,
-                started = SharingStarted.WhileSubscribed(),
-                initialValue = transitioning(transitionState.value, from, to),
-            )
-    }
-
     /**
      * Binds the given flow so the system remembers it.
      *
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 995059d..246ccb1 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
@@ -30,6 +30,7 @@
 import com.android.systemui.dagger.qualifiers.DisplayId
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.model.SceneContainerPlugin
 import com.android.systemui.model.SysUiState
 import com.android.systemui.model.updateFlags
 import com.android.systemui.power.domain.interactor.PowerInteractor
@@ -39,11 +40,6 @@
 import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
 import com.android.systemui.util.asIndenting
@@ -291,12 +287,10 @@
                 .collect { sceneKey ->
                     sysUiState.updateFlags(
                         displayId,
-                        SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to (sceneKey != SceneKey.Gone),
-                        SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to (sceneKey == SceneKey.Shade),
-                        SYSUI_STATE_QUICK_SETTINGS_EXPANDED to (sceneKey == SceneKey.QuickSettings),
-                        SYSUI_STATE_BOUNCER_SHOWING to (sceneKey == SceneKey.Bouncer),
-                        SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to
-                            (sceneKey == SceneKey.Lockscreen),
+                        *SceneContainerPlugin.EvaluatorByFlag.map { (flag, evaluator) ->
+                                flag to evaluator.invoke(sceneKey)
+                            }
+                            .toTypedArray(),
                     )
                 }
         }
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 93cfc5d..2b978b2 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
@@ -97,6 +97,10 @@
                     val legacyView = view.requireViewById<View>(R.id.legacy_window_root)
                     view.addView(createVisibilityToggleView(legacyView))
 
+                    // This moves the SharedNotificationContainer to the WindowRootView just after
+                    //  the SceneContainerView. This SharedNotificationContainer should contain NSSL
+                    //  due to the NotificationStackScrollLayoutSection (legacy) or
+                    //  NotificationSection (scene container) moving it there.
                     if (flags.flexiNotifsEnabled()) {
                         (sharedNotificationContainer.parent as? ViewGroup)?.removeView(
                             sharedNotificationContainer
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 97ec3f9..1c7cc00 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -34,7 +34,7 @@
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.util.kotlin.collectFlow
 import javax.inject.Inject
-import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.Flow
 
 /**
  * Controller that's responsible for the glanceable hub container view and its touch handling.
@@ -110,10 +110,8 @@
         return communalInteractor.isCommunalEnabled && isComposeAvailable()
     }
 
-    /** Returns a {@link StateFlow} that tracks whether communal hub is enabled. */
-    fun enabledState(): StateFlow<Boolean> {
-        return communalInteractor.communalEnabledState
-    }
+    /** Returns a {@link StateFlow} that tracks whether communal hub is available. */
+    fun communalAvailable(): Flow<Boolean> = communalInteractor.isCommunalAvailable
 
     /**
      * Creates the container view containing the glanceable hub UI.
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index c0ceba3..09e4e75 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -66,7 +66,6 @@
 import android.os.Handler;
 import android.os.Trace;
 import android.os.UserManager;
-import android.os.VibrationEffect;
 import android.provider.Settings;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
@@ -256,12 +255,8 @@
     private static final boolean DEBUG_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
     private static final boolean DEBUG_DRAWABLE = false;
-    private static final VibrationEffect ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT =
-            VibrationEffect.get(VibrationEffect.EFFECT_STRENGTH_MEDIUM, false);
     /** The parallax amount of the quick settings translation when dragging down the panel. */
     public static final float QS_PARALLAX_AMOUNT = 0.175f;
-    /** The delay to reset the hint text when the hint animation is finished running. */
-    private static final int HINT_RESET_DELAY_MS = 1200;
     private static final long ANIMATION_DELAY_ICON_FADE_IN =
             ActivityLaunchAnimator.TIMINGS.getTotalDuration()
                     - CollapsedStatusBarFragment.FADE_IN_DURATION
@@ -621,7 +616,7 @@
     private int mDreamingToLockscreenTransitionTranslationY;
     private int mLockscreenToDreamingTransitionTranslationY;
     private int mGoneToDreamingTransitionTranslationY;
-    private SplitShadeStateController mSplitShadeStateController;
+    private final SplitShadeStateController mSplitShadeStateController;
     private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
             mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */);
     private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable =
@@ -636,9 +631,6 @@
         }
     };
 
-    private final Consumer<Boolean> mMultiShadeExpansionConsumer =
-            (Boolean expanded) -> mIsAnyMultiShadeExpanded = expanded;
-
     private final Consumer<TransitionStep> mDreamingToLockscreenTransition =
             (TransitionStep step) -> {
                 mIsOcclusionTransitionRunning =
@@ -3576,11 +3568,6 @@
     }
 
     @Override
-    public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() {
-        return mNotificationStackScrollLayoutController;
-    }
-
-    @Override
     public void disableHeader(int state1, int state2, boolean animated) {
         mShadeHeaderController.disable(state1, state2, animated);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 5ecc54b..19a5840 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -607,7 +607,7 @@
     public void setupCommunalHubLayout() {
         collectFlow(
                 mView,
-                mGlanceableHubContainerController.enabledState(),
+                mGlanceableHubContainerController.communalAvailable(),
                 isEnabled -> {
                     if (isEnabled) {
                         View communalPlaceholder = mView.findViewById(R.id.communal_ui_stub);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index e54286f..4f970b3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -17,7 +17,6 @@
 
 import android.view.ViewPropertyAnimator
 import com.android.systemui.statusbar.GestureRecorder
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.policy.HeadsUpManager
 
@@ -44,9 +43,6 @@
     /** Animates the view from its current alpha to zero then runs the runnable. */
     fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable): ViewPropertyAnimator
 
-    /** Returns the NSSL controller. */
-    val notificationStackScrollLayoutController: NotificationStackScrollLayoutController
-
     /** Set whether the bouncer is showing. */
     fun setBouncerShowing(bouncerShowing: Boolean)
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index 3fd070c..08f2c40 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -109,7 +109,7 @@
      * Returns a flow that uses scene transition progress to and from a scene that is pulled down
      * from the top of the screen to a 0-1 expansion amount float.
      */
-    internal fun sceneBasedExpansion(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
+    fun sceneBasedExpansion(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
         sceneInteractor.transitionState
             .flatMapLatest { state ->
                 when (state) {
@@ -135,7 +135,7 @@
      * Returns a flow that uses scene transition data to determine whether the user is interacting
      * with a scene that is pulled down from the top of the screen.
      */
-    internal fun sceneBasedInteracting(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
+    fun sceneBasedInteracting(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
         sceneInteractor.transitionState
             .map { state ->
                 when (state) {
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 51276c6..314637e 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
@@ -22,12 +22,11 @@
 import android.icu.text.DateFormat
 import android.icu.text.DisplayContext
 import android.os.UserHandle
-import com.android.systemui.res.R
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
 import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
 import java.util.Date
@@ -38,7 +37,6 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
@@ -57,16 +55,6 @@
     val mobileIconsViewModel: MobileIconsViewModel,
     broadcastDispatcher: BroadcastDispatcher,
 ) {
-    /** True if we are transitioning between Shade and QuickSettings scenes, in either direction. */
-    val isTransitioning =
-        combine(
-                sceneInteractor.transitioning(from = SceneKey.Shade, to = SceneKey.QuickSettings),
-                sceneInteractor.transitioning(from = SceneKey.QuickSettings, to = SceneKey.Shade)
-            ) { shadeToQuickSettings, quickSettingsToShade ->
-                shadeToQuickSettings || quickSettingsToShade
-            }
-            .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
-
     /** True if there is exactly one mobile connection. */
     val isSingleCarrier: StateFlow<Boolean> = mobileIconsInteractor.isSingleCarrier
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index d6d3e67..04d9b0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -591,8 +591,10 @@
     }
 
     private void updateLockScreenUserLockedMsg(int userId) {
-        if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)
-                || mKeyguardUpdateMonitor.isEncryptedOrLockdown(userId)) {
+        boolean userUnlocked = mKeyguardUpdateMonitor.isUserUnlocked(userId);
+        boolean encryptedOrLockdown = mKeyguardUpdateMonitor.isEncryptedOrLockdown(userId);
+        mKeyguardLogger.logUpdateLockScreenUserLockedMsg(userId, userUnlocked, encryptedOrLockdown);
+        if (!userUnlocked || encryptedOrLockdown) {
             mRotateTextViewController.updateIndication(
                     INDICATION_TYPE_USER_LOCKED,
                     new KeyguardIndication.Builder()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 24ac70e..2a4753d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -234,10 +234,12 @@
             } else if (profileAvailabilityActions(action)) {
                 updateCurrentProfilesCache();
             } else if (Objects.equals(action, Intent.ACTION_USER_UNLOCKED)) {
-                // Start the overview connection to the launcher service
-                // Connect if user hasn't connected yet
-                if (mOverviewProxyServiceLazy.get().getProxy() == null) {
-                    mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
+                if (!keyguardPrivateNotifications()) {
+                    // Start the overview connection to the launcher service
+                    // Connect if user hasn't connected yet
+                    if (mOverviewProxyServiceLazy.get().getProxy() == null) {
+                        mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
+                    }
                 }
             } else if (Objects.equals(action, NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION)) {
                 final IntentSender intentSender = intent.getParcelableExtra(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 28d4457..fc84973 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -35,6 +35,7 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
@@ -60,6 +61,7 @@
 import com.android.settingslib.mobile.TelephonyIcons;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.Dumpable;
+import com.android.systemui.res.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -71,7 +73,6 @@
 import com.android.systemui.log.core.LogLevel;
 import com.android.systemui.log.dagger.StatusBarNetworkControllerLog;
 import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
-import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -84,8 +85,6 @@
 
 import dalvik.annotation.optimization.NeverCompile;
 
-import kotlin.Unit;
-
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -100,6 +99,8 @@
 
 import javax.inject.Inject;
 
+import kotlin.Unit;
+
 /** Platform implementation of the network controller. **/
 @SysUISingleton
 public class NetworkControllerImpl extends BroadcastReceiver
@@ -349,7 +350,7 @@
         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
         updateAirplaneMode(true /* force callback */);
         mUserTracker = userTracker;
-        mUserTracker.addCallback(mUserChangedCallback, mBgExecutor);
+        mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mMainHandler));
 
         deviceProvisionedController.addCallback(new DeviceProvisionedListener() {
             @Override
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 6e3b15d..c643238 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -52,8 +52,8 @@
             entry: NotificationEntry,
             recoveredBuilder: Notification.Builder,
             logger: NotificationContentInflaterLogger
-    ) {
-        val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return
+    ): Notification.MessagingStyle? {
+        val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return null
         messagingStyle.conversationType =
                 if (entry.ranking.channel.isImportantConversation)
                     Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT
@@ -68,6 +68,7 @@
         }
         messagingStyle.unreadMessageCount =
                 conversationNotificationManager.getUnreadCount(entry, recoveredBuilder)
+        return messagingStyle
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 73decfc..639e23a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -362,8 +362,12 @@
     }
 
     NotifInflater.Params getInflaterParams(NotifUiAdjustment adjustment, String reason) {
-        return new NotifInflater.Params(adjustment.isMinimized(), reason,
-                adjustment.isSnoozeEnabled());
+        return new NotifInflater.Params(
+                adjustment.isMinimized(),
+                reason,
+                adjustment.isSnoozeEnabled(),
+                adjustment.isChildInGroup()
+        );
     }
 
     private void abortInflation(NotificationEntry entry, String reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
index 4483599..c0b187b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
@@ -20,9 +20,9 @@
 import com.android.systemui.statusbar.notification.collection.render.NotifViewController
 
 /**
- * Used by the [PreparationCoordinator].  When notifications are added or updated, the
- * NotifInflater is asked to (re)inflated and prepare their views.  This inflation occurs off the
- * main thread. When the inflation is finished, NotifInflater will trigger its InflationCallback.
+ * Used by the [PreparationCoordinator]. When notifications are added or updated, the NotifInflater
+ * is asked to (re)inflated and prepare their views. This inflation occurs off the main thread. When
+ * the inflation is finished, NotifInflater will trigger its InflationCallback.
  */
 interface NotifInflater {
     /**
@@ -33,7 +33,7 @@
     fun rebindViews(entry: NotificationEntry, params: Params, callback: InflationCallback)
 
     /**
-     * Called to inflate the views of an entry.  Views are not considered inflated until all of its
+     * Called to inflate the views of an entry. Views are not considered inflated until all of its
      * views are bound. Once all views are inflated, the InflationCallback is triggered.
      *
      * @param callback callback called after inflation finishes
@@ -41,25 +41,24 @@
     fun inflateViews(entry: NotificationEntry, params: Params, callback: InflationCallback)
 
     /**
-     * Request to stop the inflation of an entry.  For example, called when a notification is
-     * removed and no longer needs to be inflated.  Returns whether anything may have been aborted.
+     * Request to stop the inflation of an entry. For example, called when a notification is removed
+     * and no longer needs to be inflated. Returns whether anything may have been aborted.
      */
     fun abortInflation(entry: NotificationEntry): Boolean
 
-    /**
-     * Called to let the system remove the content views from the notification row.
-     */
+    /** Called to let the system remove the content views from the notification row. */
     fun releaseViews(entry: NotificationEntry)
 
-    /**
-     * Callback once all the views are inflated and bound for a given NotificationEntry.
-     */
+    /** Callback once all the views are inflated and bound for a given NotificationEntry. */
     interface InflationCallback {
         fun onInflationFinished(entry: NotificationEntry, controller: NotifViewController)
     }
 
-    /**
-     * A class holding parameters used when inflating the notification row
-     */
-    class Params(val isLowPriority: Boolean, val reason: String, val showSnooze: Boolean)
+    /** A class holding parameters used when inflating the notification row */
+    class Params(
+        val isLowPriority: Boolean,
+        val reason: String,
+        val showSnooze: Boolean,
+        val isChildInGroup: Boolean = false,
+    )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
index ee0b008..e1d2cdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
@@ -20,6 +20,7 @@
 import android.app.RemoteInput
 import android.graphics.drawable.Icon
 import android.text.TextUtils
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
 
 /**
  * An immutable object which contains minimal state extracted from an entry that represents state
@@ -34,6 +35,7 @@
     val isSnoozeEnabled: Boolean,
     val isMinimized: Boolean,
     val needsRedaction: Boolean,
+    val isChildInGroup: Boolean,
 ) {
     companion object {
         @JvmStatic
@@ -48,6 +50,11 @@
             oldAdjustment.needsRedaction != newAdjustment.needsRedaction -> true
             areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions) -> true
             newAdjustment.smartReplies != oldAdjustment.smartReplies -> true
+            // TODO(b/217799515): Here we decide whether to re-inflate the row on every group-status
+            //  change if we want to keep the single-line view, the following line should be:
+            //  !oldAdjustment.isChildInGroup && newAdjustment.isChildInGroup -> true
+            AsyncHybridViewInflation.isEnabled &&
+                    oldAdjustment.isChildInGroup != newAdjustment.isChildInGroup -> true
             else -> false
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
index 0585456..6f44c13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
 import com.android.systemui.util.ListenerSet
 import com.android.systemui.util.settings.SecureSettings
 import javax.inject.Inject
@@ -43,7 +44,8 @@
     private val secureSettings: SecureSettings,
     private val lockscreenUserManager: NotificationLockscreenUserManager,
     private val sectionStyleProvider: SectionStyleProvider,
-    private val userTracker: UserTracker
+    private val userTracker: UserTracker,
+    private val groupMembershipManager: GroupMembershipManager,
 ) {
     private val dirtyListeners = ListenerSet<Runnable>()
     private var isSnoozeSettingsEnabled = false
@@ -121,5 +123,6 @@
         isSnoozeEnabled = isSnoozeSettingsEnabled && !entry.isCanceled,
         isMinimized = isEntryMinimized(entry),
         needsRedaction = lockscreenUserManager.needsRedaction(entry),
+        isChildInGroup = groupMembershipManager.isChildInGroup(entry),
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 80ef14b..cd816ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE;
 
 import static java.util.Objects.requireNonNull;
 
@@ -49,6 +50,7 @@
 import com.android.systemui.statusbar.notification.row.RowContentBindStage;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
 import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 
 import javax.inject.Inject;
@@ -127,6 +129,8 @@
             @NonNull NotifInflater.Params params,
             NotificationRowContentBinder.InflationCallback callback)
             throws InflationException {
+        //TODO(b/217799515): Remove the entry parameter from getViewParentForNotification(), this
+        // function returns the NotificationStackScrollLayout regardless of the entry.
         ViewGroup parent = mListContainer.getViewParentForNotification(entry);
 
         if (entry.rowExists()) {
@@ -174,6 +178,9 @@
         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_CONTRACTED);
         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_EXPANDED);
         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
+        if (AsyncHybridViewInflation.isEnabled()) {
+            params.markContentViewsFreeable(FLAG_CONTENT_VIEW_SINGLE_LINE);
+        }
         mRowContentBindStage.requestRebind(entry, null);
     }
 
@@ -254,6 +261,16 @@
             params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
         }
 
+        if (AsyncHybridViewInflation.isEnabled()) {
+            if (inflaterParams.isChildInGroup()) {
+                params.requireContentViews(FLAG_CONTENT_VIEW_SINGLE_LINE);
+            } else {
+                // TODO(b/217799515): here we decide whether to free the single-line view
+                //  when the group status changes
+                params.markContentViewsFreeable(FLAG_CONTENT_VIEW_SINGLE_LINE);
+            }
+        }
+
         params.rebindAllContentViews();
         mLogger.logRequestingRebind(entry, inflaterParams);
         mRowContentBindStage.requestRebind(entry, en -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 61e6f65..8021d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -127,6 +127,9 @@
         }
     }
 
+    /**
+     * Attach the Child Nodes to the parentNode using the structure from specMap
+     */
     private fun attachChildren(
         parentNode: ShadeNode,
         specMap: Map<NodeController, NodeSpec>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
index 342828c..aca8b64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
@@ -6,7 +6,6 @@
 import android.net.Uri
 import android.os.Handler
 import android.os.HandlerExecutor
-import android.os.HandlerThread
 import android.os.UserHandle
 import android.provider.Settings
 import com.android.keyguard.KeyguardUpdateMonitor
@@ -88,7 +87,6 @@
             secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS)
     private val onStateChangedListeners = ListenerSet<Consumer<String>>()
     private var hideSilentNotificationsOnLockscreen: Boolean = false
-    private val handlerThread: HandlerThread = HandlerThread("KeyguardNotificationVis")
 
     private val userTrackerCallback = object : UserTracker.Callback {
         override fun onUserChanged(newUser: Int, userContext: Context) {
@@ -156,9 +154,7 @@
                 notifyStateChanged("onStatusBarUpcomingStateChanged")
             }
         })
-        handlerThread.start()
-        userTracker.addCallback(userTrackerCallback,
-                   HandlerExecutor(handlerThread.getThreadHandler()))
+        userTracker.addCallback(userTrackerCallback, HandlerExecutor(handler))
     }
 
     override fun addOnStateChangedListener(listener: Consumer<String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
index d626c18..8ae324f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
@@ -44,6 +44,7 @@
     /**
      * Execute the stage asynchronously.
      *
+     * @param entry the NotificationEntry to bind
      * @param row notification top-level view to bind views to
      * @param callback callback after stage finishes
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
index 43d99a0..6bc2b2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
@@ -16,19 +16,27 @@
 
 package com.android.systemui.statusbar.notification.row;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.graphics.drawable.Icon;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewStub;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ConversationLayout;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.NotificationFadeAware;
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ConversationAvatar;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.FacePile;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleIcon;
 
 /**
  * A hybrid view which may contain information about one ore more conversations.
@@ -37,6 +45,7 @@
 
     private ImageView mConversationIconView;
     private TextView mConversationSenderName;
+    private ViewStub mConversationFacePileStub;
     private View mConversationFacePile;
     private int mSingleAvatarSize;
     private int mFacePileSize;
@@ -65,7 +74,16 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mConversationIconView = requireViewById(com.android.internal.R.id.conversation_icon);
-        mConversationFacePile = requireViewById(com.android.internal.R.id.conversation_face_pile);
+        if (AsyncHybridViewInflation.isEnabled()) {
+            mConversationFacePileStub =
+                    requireViewById(com.android.internal.R.id.conversation_face_pile);
+        } else {
+            // TODO(b/217799515): This usage is vague because mConversationFacePile represents both
+            //  View and ViewStub at different stages of View inflation, should be removed when
+            //  AsyncHybridViewInflation flag is removed
+            mConversationFacePile =
+                    requireViewById(com.android.internal.R.id.conversation_face_pile);
+        }
         mConversationSenderName = requireViewById(R.id.conversation_notification_sender);
         applyTextColor(mConversationSenderName, mSecondaryTextColor);
         mFacePileSize = getResources()
@@ -85,7 +103,8 @@
 
     @Override
     public void bind(@Nullable CharSequence title, @Nullable CharSequence text,
-            @Nullable View contentView) {
+                     @Nullable View contentView) {
+        AsyncHybridViewInflation.assertInLegacyMode();
         if (!(contentView instanceof ConversationLayout)) {
             super.bind(title, text, contentView);
             return;
@@ -137,6 +156,77 @@
         super.bind(conversationTitle, conversationText, conversationLayout);
     }
 
+    /**
+     * Set the avatar using ConversationAvatar from SingleLineViewModel
+     *
+     * @param conversationAvatar the icon needed for a single-line conversation view, it should be
+     *                           either an instance of SingleIcon or FacePile
+     */
+    public void setAvatar(@NonNull ConversationAvatar conversationAvatar) {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return;
+        if (conversationAvatar instanceof SingleIcon) {
+            SingleIcon avatar = (SingleIcon) conversationAvatar;
+            if (mConversationFacePile != null) mConversationFacePile.setVisibility(GONE);
+            mConversationIconView.setVisibility(VISIBLE);
+            mConversationIconView.setImageDrawable(avatar.getIconDrawable());
+            setSize(mConversationIconView, mSingleAvatarSize);
+            return;
+        }
+
+        // If conversationAvatar is not a SingleIcon, it should be a FacePile.
+        // Bind the face pile with it.
+        FacePile facePileModel = (FacePile) conversationAvatar;
+        mConversationIconView.setVisibility(GONE);
+        // Inflate mConversationFacePile from ViewStub
+        if (mConversationFacePile == null) {
+            mConversationFacePile = mConversationFacePileStub.inflate();
+        }
+        mConversationFacePile.setVisibility(VISIBLE);
+
+        ImageView facePileBottomBg = mConversationFacePile.requireViewById(
+                com.android.internal.R.id.conversation_face_pile_bottom_background);
+        ImageView facePileBottom = mConversationFacePile.requireViewById(
+                com.android.internal.R.id.conversation_face_pile_bottom);
+        ImageView facePileTop = mConversationFacePile.requireViewById(
+                com.android.internal.R.id.conversation_face_pile_top);
+
+        int bottomBackgroundColor = facePileModel.getBottomBackgroundColor();
+        facePileBottomBg.setImageTintList(ColorStateList.valueOf(bottomBackgroundColor));
+
+        facePileBottom.setImageDrawable(facePileModel.getBottomIconDrawable());
+        facePileTop.setImageDrawable(facePileModel.getTopIconDrawable());
+
+        setSize(mConversationFacePile, mFacePileSize);
+        setSize(facePileBottom, mFacePileAvatarSize);
+        setSize(facePileTop, mFacePileAvatarSize);
+        setSize(facePileBottomBg, mFacePileAvatarSize + 2 * mFacePileProtectionWidth);
+
+        mTransformationHelper.addViewTransformingToSimilar(facePileTop);
+        mTransformationHelper.addViewTransformingToSimilar(facePileBottom);
+        mTransformationHelper.addViewTransformingToSimilar(facePileBottomBg);
+
+    }
+
+    /**
+     * bind the text views
+     */
+    public void setText(
+            CharSequence titleText,
+            CharSequence contentText,
+            CharSequence conversationSenderName
+    ) {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return;
+        if (conversationSenderName == null) {
+            mConversationSenderName.setVisibility(GONE);
+        } else {
+            mConversationSenderName.setVisibility(VISIBLE);
+            mConversationSenderName.setText(conversationSenderName);
+        }
+        // TODO (b/217799515): super.bind() doesn't use contentView, remove the contentView
+        //  argument when the flag is removed
+        super.bind(/* title = */ titleText, /* text = */ contentText, /* contentView = */ null);
+    }
+
     private static void setSize(View view, int size) {
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) view.getLayoutParams();
         lp.width = size;
@@ -153,4 +243,9 @@
         super.setNotificationFaded(faded);
         NotificationFadeAware.setLayerTypeForFaded(mConversationFacePile, faded);
     }
+
+    @VisibleForTesting
+    TextView getConversationSenderNameView() {
+        return mConversationSenderName;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
index ddd9bdd..09c0349 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
@@ -32,6 +32,7 @@
 
 import com.android.internal.widget.ConversationLayout;
 import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
 
 /**
  * A class managing hybrid groups that include {@link HybridNotificationView} and the notification
@@ -41,6 +42,8 @@
 
     private final Context mContext;
 
+    private static final String TAG = "HybridGroupManager";
+
     private float mOverflowNumberSize;
     private int mOverflowNumberPadding;
 
@@ -93,21 +96,34 @@
     public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
             View contentView, StatusBarNotification notification,
             ViewGroup parent) {
+        AsyncHybridViewInflation.assertInLegacyMode();
         boolean isNewView = false;
         if (reusableView == null) {
             Trace.beginSection("HybridGroupManager#bindFromNotification");
             reusableView = inflateHybridView(contentView, parent);
             isNewView = true;
         }
-        CharSequence titleText = resolveTitle(notification.getNotification());
-        CharSequence contentText = resolveText(notification.getNotification());
-        reusableView.bind(titleText, contentText, contentView);
+
+        updateReusableView(reusableView, notification, contentView);
         if (isNewView) {
             Trace.endSection();
         }
         return reusableView;
     }
 
+    /**
+     * Update the HybridNotificationView (single-line view)'s appearance
+     */
+    public void updateReusableView(HybridNotificationView reusableView,
+            StatusBarNotification notification, View contentView) {
+        AsyncHybridViewInflation.assertInLegacyMode();
+        final CharSequence titleText = resolveTitle(notification.getNotification());
+        final CharSequence contentText = resolveText(notification.getNotification());
+        if (reusableView != null) {
+            reusableView.bind(titleText, contentText, contentView);
+        }
+    }
+
     @Nullable
     public static CharSequence resolveText(Notification notification) {
         CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
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 f186e66..913d5f6 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
@@ -20,6 +20,7 @@
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_SINGLELINE;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -41,15 +42,19 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ImageMessageConsumer;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.media.controls.util.MediaFeatureFlag;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 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.row.shared.AsyncHybridViewInflation;
+import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineConversationViewBinder;
+import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
@@ -135,7 +140,7 @@
         AsyncInflationTask task = new AsyncInflationTask(
                 mBgExecutor,
                 mInflateSynchronously,
-                contentToBind,
+                /* reInflateFlags = */ contentToBind,
                 mRemoteViewCache,
                 entry,
                 mConversationProcessor,
@@ -145,7 +150,7 @@
                 bindParams.usesIncreasedHeadsUpHeight,
                 callback,
                 mRemoteInputManager.getRemoteViewsOnClickHandler(),
-                mIsMediaInQS,
+                /* isMediaFlagEnabled = */ mIsMediaInQS,
                 mSmartReplyStateInflater,
                 mNotifLayoutInflaterFactoryProvider,
                 mLogger);
@@ -178,6 +183,29 @@
 
         result = inflateSmartReplyViews(result, reInflateFlags, entry, row.getContext(),
                 packageContext, row.getExistingSmartReplyState(), smartRepliesInflater, mLogger);
+        if (AsyncHybridViewInflation.isEnabled()) {
+            boolean isConversation = entry.getRanking().isConversation();
+            Notification.MessagingStyle messagingStyle = null;
+            if (isConversation) {
+                messagingStyle = mConversationProcessor
+                        .processNotification(entry, builder, mLogger);
+            }
+            result.mInflatedSingleLineViewModel = SingleLineViewInflater
+                    .inflateSingleLineViewModel(
+                            entry.getSbn().getNotification(),
+                            messagingStyle,
+                            builder,
+                            row.getContext()
+                    );
+            result.mInflatedSingleLineViewHolder =
+                    SingleLineViewInflater.inflateSingleLineViewHolder(
+                            isConversation,
+                            reInflateFlags,
+                            entry,
+                            row.getContext(),
+                            mLogger
+                    );
+        }
 
         apply(
                 mBgExecutor,
@@ -255,6 +283,15 @@
                     mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC);
                 });
                 break;
+            case FLAG_CONTENT_VIEW_SINGLE_LINE: {
+                if (AsyncHybridViewInflation.isEnabled()) {
+                    row.getPrivateLayout().performWhenContentInactive(
+                            VISIBLE_TYPE_SINGLELINE,
+                            () -> row.getPrivateLayout().setSingleLineView(null)
+                    );
+                }
+                break;
+            }
             default:
                 break;
         }
@@ -282,6 +319,10 @@
         if ((contentViews & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
             row.getPublicLayout().removeContentInactiveRunnable(VISIBLE_TYPE_CONTRACTED);
         }
+        if (AsyncHybridViewInflation.isEnabled()
+                && (contentViews & FLAG_CONTENT_VIEW_SINGLE_LINE) != 0) {
+            row.getPrivateLayout().removeContentInactiveRunnable(VISIBLE_TYPE_SINGLELINE);
+        }
     }
 
     private static InflationProgress inflateSmartReplyViews(
@@ -772,6 +813,25 @@
                 }
                 setRepliesAndActions = true;
             }
+
+            if (AsyncHybridViewInflation.isEnabled()
+                    && (reInflateFlags & FLAG_CONTENT_VIEW_SINGLE_LINE) != 0) {
+                HybridNotificationView viewHolder = result.mInflatedSingleLineViewHolder;
+                SingleLineViewModel viewModel = result.mInflatedSingleLineViewModel;
+                if (viewHolder != null && viewModel != null) {
+                    if (viewModel.isConversation()) {
+                        SingleLineConversationViewBinder.bind(
+                                result.mInflatedSingleLineViewModel,
+                                result.mInflatedSingleLineViewHolder
+                        );
+                    } else {
+                        SingleLineViewBinder.bind(result.mInflatedSingleLineViewModel,
+                                result.mInflatedSingleLineViewHolder);
+                    }
+                    privateLayout.setSingleLineView(result.mInflatedSingleLineViewHolder);
+                }
+            }
+
             if (setRepliesAndActions) {
                 privateLayout.setInflatedSmartReplyState(result.inflatedSmartReplyState);
             }
@@ -941,19 +1001,23 @@
                     // For all of our templates, we want it to be RTL
                     packageContext = new RtlEnabledContext(packageContext);
                 }
-                if (mEntry.getRanking().isConversation()) {
-                    mConversationProcessor.processNotification(mEntry, recoveredBuilder, mLogger);
+                boolean isConversation = mEntry.getRanking().isConversation();
+                Notification.MessagingStyle messagingStyle = null;
+                if (isConversation) {
+                    messagingStyle = mConversationProcessor.processNotification(
+                            mEntry, recoveredBuilder, mLogger);
                 }
                 InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
                         recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
                         mUsesIncreasedHeadsUpHeight, packageContext, mRow,
                         mNotifLayoutInflaterFactoryProvider, mLogger);
+
                 mLogger.logAsyncTaskProgress(mEntry,
                         "getting existing smart reply state (on wrong thread!)");
                 InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState();
                 mLogger.logAsyncTaskProgress(mEntry, "inflating smart reply views");
                 InflationProgress result = inflateSmartReplyViews(
-                        inflationProgress,
+                        /* result = */ inflationProgress,
                         mReInflateFlags,
                         mEntry,
                         mContext,
@@ -962,6 +1026,27 @@
                         mSmartRepliesInflater,
                         mLogger);
 
+                if (AsyncHybridViewInflation.isEnabled()) {
+                    // Inflate the single-line content view's ViewModel and ViewHolder from the
+                    // background thread, the ViewHolder needs to be bind with ViewModel later from
+                    // the main thread.
+                    result.mInflatedSingleLineViewModel = SingleLineViewInflater
+                            .inflateSingleLineViewModel(
+                                    mEntry.getSbn().getNotification(),
+                                    messagingStyle,
+                                    recoveredBuilder,
+                                    mContext
+                            );
+                    result.mInflatedSingleLineViewHolder =
+                            SingleLineViewInflater.inflateSingleLineViewHolder(
+                                    isConversation,
+                                    mReInflateFlags,
+                                    mEntry,
+                                    mContext,
+                                    mLogger
+                            );
+                }
+
                 mLogger.logAsyncTaskProgress(mEntry,
                         "getting row image resolver (on wrong thread!)");
                 final NotificationInlineImageResolver imageResolver = mRow.getImageResolver();
@@ -1078,6 +1163,11 @@
         private InflatedSmartReplyState inflatedSmartReplyState;
         private InflatedSmartReplyViewHolder expandedInflatedSmartReplies;
         private InflatedSmartReplyViewHolder headsUpInflatedSmartReplies;
+
+        // ViewModel for SingleLineView, holds the UI State
+        SingleLineViewModel mInflatedSingleLineViewModel;
+        // Inflated SingleLineViewHolder, SingleLineView that lacks the UI State
+        HybridNotificationView mInflatedSingleLineViewHolder;
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
index 4f5455d..ee9462c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag
 import javax.inject.Inject
 
@@ -99,6 +100,26 @@
         )
     }
 
+    fun logInflateSingleLine(
+        entry: NotificationEntry,
+        @InflationFlag inflationFlags: Int,
+        isConversation: Boolean
+    ) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                int1 = inflationFlags
+                bool1 = isConversation
+            },
+            {
+                "inflateSingleLineView, inflationFlags: ${flagToString(int1)} for $str1, " +
+                    "isConversation: $bool1"
+            }
+        )
+    }
+
     companion object {
         fun flagToString(@InflationFlag flag: Int): String {
             if (flag == 0) {
@@ -121,6 +142,9 @@
             if (flag and FLAG_CONTENT_VIEW_PUBLIC != 0) {
                 l.add("PUBLIC")
             }
+            if (flag and FLAG_CONTENT_VIEW_SINGLE_LINE != 0) {
+                l.add("SINGLE_LINE")
+            }
             return l.joinToString("|")
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index a1718b9..402ea51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -57,6 +57,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
@@ -86,7 +87,7 @@
     public static final int VISIBLE_TYPE_CONTRACTED = 0;
     public static final int VISIBLE_TYPE_EXPANDED = 1;
     public static final int VISIBLE_TYPE_HEADSUP = 2;
-    private static final int VISIBLE_TYPE_SINGLELINE = 3;
+    public static final int VISIBLE_TYPE_SINGLELINE = 3;
     /**
      * Used when there is no content on the view such as when we're a public layout but don't
      * need to show.
@@ -98,6 +99,7 @@
     private final Rect mClipBounds = new Rect();
 
     private int mMinContractedHeight;
+    private int mMinSingleLineHeight;
     private View mContractedChild;
     private View mExpandedChild;
     private View mHeadsUpChild;
@@ -234,6 +236,11 @@
     public void reinflate() {
         mMinContractedHeight = getResources().getDimensionPixelSize(
                 R.dimen.min_notification_layout_height);
+        if (AsyncHybridViewInflation.isEnabled()) {
+            //TODO: set the height with a more reasonable min single-line height
+            mMinSingleLineHeight = getResources().getDimensionPixelSize(
+                    R.dimen.conversation_single_line_face_pile_size);
+        }
     }
 
     public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -540,6 +547,28 @@
         updateShownWrapper(mVisibleType);
     }
 
+    /**
+     * Sets the single-line view. Child may be null to remove the view.
+     * @param child single-line content view to set
+     */
+    public void setSingleLineView(@Nullable HybridNotificationView child) {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return;
+        if (mSingleLineView != null) {
+            mOnContentViewInactiveListeners.remove(mSingleLineView);
+            mSingleLineView.animate().cancel();
+            removeView(mSingleLineView);
+        }
+        if (child == null) {
+            mSingleLineView = null;
+            if (mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE) {
+                mTransformationStartVisibleType = VISIBLE_TYPE_NONE;
+            }
+            return;
+        }
+        addView(child);
+        mSingleLineView = child;
+    }
+
     @Override
     public void onViewAdded(View child) {
         super.onViewAdded(child);
@@ -809,7 +838,17 @@
             return mContractedChild != null
                     ? getViewHeight(VISIBLE_TYPE_CONTRACTED) : mMinContractedHeight;
         } else {
-            return mSingleLineView.getHeight();
+            if (AsyncHybridViewInflation.isEnabled()) {
+                if (mSingleLineView != null) {
+                    return getViewHeight(VISIBLE_TYPE_SINGLELINE);
+                } else {
+                    Log.wtf(TAG, "getMinHeight: mSingleLineView == null");
+                    return mMinSingleLineHeight;
+                }
+            } else {
+                AsyncHybridViewInflation.assertInLegacyMode();
+                return mSingleLineView.getHeight();
+            }
         }
     }
 
@@ -1264,19 +1303,30 @@
     }
 
     private void updateSingleLineView() {
-        if (mIsChildInGroup) {
+        try {
             Trace.beginSection("NotifContentView#updateSingleLineView");
-            boolean isNewView = mSingleLineView == null;
-            mSingleLineView = mHybridGroupManager.bindFromNotification(
-                    mSingleLineView, mContractedChild, mNotificationEntry.getSbn(), this);
-            if (isNewView) {
-                updateViewVisibility(mVisibleType, VISIBLE_TYPE_SINGLELINE,
-                        mSingleLineView, mSingleLineView);
+            if (AsyncHybridViewInflation.isEnabled()) {
+                return;
             }
+            AsyncHybridViewInflation.assertInLegacyMode();
+            if (mIsChildInGroup) {
+                boolean isNewView = mSingleLineView == null;
+                mSingleLineView = mHybridGroupManager.bindFromNotification(
+                        /* reusableView = */ mSingleLineView,
+                        /* contentView = */ mContractedChild,
+                        /* notification = */ mNotificationEntry.getSbn(),
+                        /* parent = */ this
+                );
+                if (isNewView && mSingleLineView != null) {
+                    updateViewVisibility(mVisibleType, VISIBLE_TYPE_SINGLELINE,
+                            mSingleLineView, mSingleLineView);
+                }
+            } else if (mSingleLineView != null) {
+                removeView(mSingleLineView);
+                mSingleLineView = null;
+            }
+        } finally {
             Trace.endSection();
-        } else if (mSingleLineView != null) {
-            removeView(mSingleLineView);
-            mSingleLineView = null;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
index d7b7aa2..736140c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
@@ -80,6 +80,7 @@
                     FLAG_CONTENT_VIEW_EXPANDED,
                     FLAG_CONTENT_VIEW_HEADS_UP,
                     FLAG_CONTENT_VIEW_PUBLIC,
+                    FLAG_CONTENT_VIEW_SINGLE_LINE,
                     FLAG_CONTENT_VIEW_ALL})
     @interface InflationFlag {}
     /**
@@ -102,7 +103,12 @@
      */
     int FLAG_CONTENT_VIEW_PUBLIC = 1 << 3;
 
-    int FLAG_CONTENT_VIEW_ALL = (1 << 4) - 1;
+    /**
+     * The single line notification view. Show when the notification is shown as a child in group.
+     */
+    int FLAG_CONTENT_VIEW_SINGLE_LINE = 1 << 4;
+
+    int FLAG_CONTENT_VIEW_ALL = (1 << 5) - 1;
 
     /**
      * Parameters for content view binding
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 3443da1..99a6f6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -45,13 +45,15 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+
 import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+import com.android.systemui.res.R;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -77,6 +79,9 @@
     private static final LogMaker UNDO_LOG =
             new LogMaker(MetricsEvent.NOTIFICATION_UNDO_SNOOZE)
                     .setType(MetricsEvent.TYPE_ACTION);
+
+    private static final String PARAGRAPH_SEPARATOR = "\u2029";
+
     private NotificationGuts mGutsContainer;
     private NotificationSwipeActionHelper mSnoozeListener;
     private StatusBarNotification mSbn;
@@ -111,8 +116,7 @@
     }
 
     @VisibleForTesting
-    SnoozeOption getDefaultOption()
-    {
+    SnoozeOption getDefaultOption() {
         return mDefaultOption;
     }
 
@@ -130,6 +134,8 @@
         mSelectedOptionText = (TextView) findViewById(R.id.snooze_option_default);
         mUndoButton = (TextView) findViewById(R.id.undo);
         mUndoButton.setOnClickListener(this);
+        mUndoButton.setContentDescription(
+                getContext().getString(R.string.snooze_undo_content_description));
         mExpandButton = (ImageView) findViewById(R.id.expand_button);
         mDivider = findViewById(R.id.divider);
         mDivider.setAlpha(0f);
@@ -163,6 +169,46 @@
                 info.addAction(action);
             }
         }
+
+        mSnoozeView.setAccessibilityDelegate(new AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                // Replace "Double tap to activate" prompt with "Double tap to expand/collapse"
+                AccessibilityAction customClick = new AccessibilityAction(
+                        AccessibilityNodeInfo.ACTION_CLICK, getExpandActionString());
+                info.addAction(customClick);
+            }
+        });
+    }
+
+    /**
+     * Update the content description of the snooze view based on the snooze option and whether the
+     * snooze options are expanded or not.
+     * For example, this will be something like "Collapsed\u2029Snooze for 1 hour". The paragraph
+     * separator is added to introduce a break in speech, to match what TalkBack does by default
+     * when you e.g. press on a notification.
+     */
+    private void updateContentDescription() {
+        mSnoozeView.setContentDescription(
+                getExpandStateString() + PARAGRAPH_SEPARATOR + mSelectedOptionText.getText());
+    }
+
+    /** Returns "collapse" if the snooze options are expanded, or "expand" otherwise. */
+    @NonNull
+    private String getExpandActionString() {
+        return mContext.getString(mExpanded
+                ? com.android.internal.R.string.expand_button_content_description_expanded
+                : com.android.internal.R.string.expand_button_content_description_collapsed);
+    }
+
+
+    /** Returns "expanded" if the snooze options are expanded, or "collapsed" otherwise. */
+    @NonNull
+    private String getExpandStateString() {
+        return mContext.getString(
+                (mExpanded ? com.android.internal.R.string.content_description_expanded
+                        : com.android.internal.R.string.content_description_collapsed));
     }
 
     @Override
@@ -179,6 +225,8 @@
             if (so.getAccessibilityAction() != null
                     && so.getAccessibilityAction().getId() == action) {
                 setSelected(so, true);
+                mSnoozeView.sendAccessibilityEvent(
+                        AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
                 return true;
             }
         }
@@ -290,11 +338,10 @@
         int drawableId = show ? com.android.internal.R.drawable.ic_collapse_notification
                 : com.android.internal.R.drawable.ic_expand_notification;
         mExpandButton.setImageResource(drawableId);
-        mExpandButton.setContentDescription(mContext.getString(show
-                ? com.android.internal.R.string.expand_button_content_description_expanded
-                : com.android.internal.R.string.expand_button_content_description_collapsed));
+        mExpandButton.setContentDescription(getExpandActionString());
         if (mExpanded != show) {
             mExpanded = show;
+            updateContentDescription();
             animateSnoozeOptions(show);
             if (mGutsContainer != null) {
                 mGutsContainer.onHeightChanged();
@@ -335,8 +382,11 @@
     }
 
     private void setSelected(SnoozeOption option, boolean userAction) {
-        mSelectedOption = option;
-        mSelectedOptionText.setText(option.getConfirmation());
+        if (option != mSelectedOption) {
+            mSelectedOption = option;
+            mSelectedOptionText.setText(option.getConfirmation());
+            updateContentDescription();
+        }
         showSnoozeOptions(false);
         hideSelectedOption();
         if (userAction) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
index a52f638..1494c27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
@@ -102,9 +102,9 @@
      * @see InflationFlag
      */
     public void markContentViewsFreeable(@InflationFlag int contentViews) {
-        @InflationFlag int existingContentViews = contentViews &= mContentViews;
+        @InflationFlag int existingFreeableContentViews = contentViews &= mContentViews;
         mContentViews &= ~contentViews;
-        mDirtyContentViews |= existingContentViews;
+        mDirtyContentViews |= existingFreeableContentViews;
     }
 
     public @InflationFlag int getContentViews() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
index b70da00..f4f8374 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
@@ -63,7 +63,10 @@
         @InflationFlag int inflationFlags = params.getContentViews();
         @InflationFlag int invalidatedFlags = params.getDirtyContentViews();
 
+        // Rebind the content views which are needed now, and the corresponding old views are
+        // invalidated
         @InflationFlag int contentToBind = invalidatedFlags & inflationFlags;
+        // Unbind the content views that are not needed
         @InflationFlag int contentToUnbind = inflationFlags ^ FLAG_CONTENT_VIEW_ALL;
 
         // Bind/unbind with parameters
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
new file mode 100644
index 0000000..d6118a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
@@ -0,0 +1,390 @@
+/*
+ * 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.systemui.statusbar.notification.row
+
+import android.app.Notification
+import android.app.Notification.MessagingStyle
+import android.app.Person
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.util.Log
+import android.view.LayoutInflater
+import com.android.app.tracing.traceSection
+import com.android.internal.R
+import com.android.internal.widget.MessagingMessage
+import com.android.internal.widget.PeopleHelper
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.logKey
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ConversationAvatar
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ConversationData
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.FacePile
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleIcon
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel
+
+/** The inflater of SingleLineViewModel and SingleLineViewHolder */
+internal object SingleLineViewInflater {
+    const val TAG = "SingleLineViewInflater"
+
+    /**
+     * Inflate an instance of SingleLineViewModel.
+     *
+     * @param notification the notification to show
+     * @param messagingStyle the MessagingStyle information is only provided for conversation
+     *   notification, not for legacy messaging notifications
+     * @param builder the recovered Notification Builder
+     * @param systemUiContext the context of Android System UI
+     * @return the inflated SingleLineViewModel
+     */
+    @JvmStatic
+    fun inflateSingleLineViewModel(
+        notification: Notification,
+        messagingStyle: MessagingStyle?,
+        builder: Notification.Builder,
+        systemUiContext: Context,
+    ): SingleLineViewModel {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) {
+            return SingleLineViewModel(null, null, null)
+        }
+        peopleHelper.init(systemUiContext)
+        var titleText = HybridGroupManager.resolveTitle(notification)
+        var contentText = HybridGroupManager.resolveText(notification)
+
+        if (messagingStyle == null) {
+            return SingleLineViewModel(
+                titleText = titleText,
+                contentText = contentText,
+                conversationData = null,
+            )
+        }
+
+        val isGroupConversation = messagingStyle.isGroupConversation
+
+        val conversationTextData = messagingStyle.loadConversationTextData(systemUiContext)
+        if (conversationTextData?.conversationTitle?.isNotEmpty() == true) {
+            titleText = conversationTextData.conversationTitle
+        }
+        if (conversationTextData?.conversationText?.isNotEmpty() == true) {
+            contentText = conversationTextData.conversationText
+        }
+
+        val conversationAvatar =
+            messagingStyle.loadConversationAvatar(
+                notification = notification,
+                isGroupConversation = isGroupConversation,
+                builder = builder,
+                systemUiContext = systemUiContext
+            )
+
+        val conversationData =
+            ConversationData(
+                // We don't show the sender's name for one-to-one conversation
+                conversationSenderName =
+                    if (isGroupConversation) conversationTextData?.senderName else null,
+                avatar = conversationAvatar
+            )
+
+        return SingleLineViewModel(
+            titleText = titleText,
+            contentText = contentText,
+            conversationData = conversationData,
+        )
+    }
+
+    /** load conversation text data from the MessagingStyle of conversation notifications */
+    private fun MessagingStyle.loadConversationTextData(
+        systemUiContext: Context
+    ): ConversationTextData? {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) {
+            return null
+        }
+        var conversationText: CharSequence?
+
+        if (messages.isEmpty()) {
+            return null
+        }
+
+        // load the conversation text
+        val lastMessage = messages[messages.lastIndex]
+        conversationText = lastMessage.text
+        if (conversationText == null && lastMessage.isImageMessage()) {
+            conversationText = findBackUpConversationText(lastMessage, systemUiContext)
+        }
+
+        // load the sender's name to display
+        val name = lastMessage.senderPerson?.name
+        val senderName =
+            systemUiContext.resources.getString(
+                R.string.conversation_single_line_name_display,
+                name
+            )
+
+        // We need to find back-up values for those texts if they are needed and empty
+        return ConversationTextData(
+            conversationTitle = conversationTitle
+                    ?: findBackUpConversationTitle(senderName, systemUiContext),
+            conversationText = conversationText,
+            senderName = senderName,
+        )
+    }
+
+    private fun MessagingStyle.Message.isImageMessage(): Boolean = MessagingMessage.hasImage(this)
+
+    /** find a back-up conversation title when the conversation title is null. */
+    private fun MessagingStyle.findBackUpConversationTitle(
+        senderName: CharSequence?,
+        systemUiContext: Context,
+    ): CharSequence {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) {
+            return ""
+        }
+        return if (isGroupConversation) {
+            systemUiContext.resources.getString(R.string.conversation_title_fallback_group_chat)
+        } else {
+            // Is one-to-one, let's try to use the last sender's name
+            // The last back-up is the value of resource: conversation_title_fallback_one_to_one
+            senderName
+                ?: systemUiContext.resources.getString(
+                    R.string.conversation_title_fallback_one_to_one
+                )
+        }
+    }
+
+    /**
+     * find a back-up conversation text when the conversation has null text and is image message.
+     */
+    private fun findBackUpConversationText(
+        message: MessagingStyle.Message,
+        context: Context,
+    ): CharSequence? {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) {
+            return null
+        }
+        // If the message is not an image message, just return empty, the back-up text for showing
+        // will be SingleLineViewModel.contentText
+        if (!message.isImageMessage()) return null
+        // If is image message, return a placeholder
+        return context.resources.getString(R.string.conversation_single_line_image_placeholder)
+    }
+
+    /**
+     * The text data that we load from a conversation notification to show in the single-line views.
+     *
+     * Group conversation single-line view should be formatted as:
+     * [conversationTitle, senderName, conversationText]
+     *
+     * One-to-one single-line view should be formatted as:
+     * [conversationTitle (which is equal to the senderName), conversationText]
+     *
+     * @property conversationTitle the title of the conversation, not necessarily the title of the
+     *   notification row. conversationTitle is non-null, though may be empty, in which case we need
+     *   to show the notification title instead.
+     * @property conversationText the text content of the conversation, single-line will use the
+     *   notification's text when conversationText is null
+     * @property senderName the sender's name to be shown in the row when needed. senderName can be
+     *   null
+     */
+    data class ConversationTextData(
+        val conversationTitle: CharSequence,
+        val conversationText: CharSequence?,
+        val senderName: CharSequence?,
+    )
+
+    private fun groupMessages(
+        messages: List<MessagingStyle.Message>,
+        historicMessages: List<MessagingStyle.Message>,
+    ): List<MutableList<MessagingStyle.Message>> {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) {
+            return listOf()
+        }
+        if (messages.isEmpty() && historicMessages.isEmpty()) return listOf()
+        var currentGroup: MutableList<MessagingStyle.Message>? = null
+        var currentSenderKey: CharSequence? = null
+        val groups = mutableListOf<MutableList<MessagingStyle.Message>>()
+        for (i in 0 until (historicMessages.size + messages.size)) {
+            val message = if (i < historicMessages.size) historicMessages[i] else messages[i]
+
+            val sender = message.senderPerson
+            val senderKey = sender?.getKeyOrName()
+            val isNewGroup = (currentGroup == null) || senderKey != currentSenderKey
+            if (isNewGroup) {
+                currentGroup = mutableListOf()
+                groups.add(currentGroup)
+                currentSenderKey = senderKey
+            }
+            currentGroup?.add(message)
+        }
+        return groups
+    }
+
+    private fun MessagingStyle.loadConversationAvatar(
+        builder: Notification.Builder,
+        notification: Notification,
+        isGroupConversation: Boolean,
+        systemUiContext: Context,
+    ): ConversationAvatar {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) {
+            return SingleIcon(null)
+        }
+        val userKey = user.getKeyOrName()
+        var conversationIcon: Icon? = null
+        var conversationText: CharSequence? = conversationTitle
+
+        val groups = groupMessages(messages, historicMessages)
+        val uniqueNames = peopleHelper.mapUniqueNamesToPrefixWithGroupList(groups)
+
+        if (!isGroupConversation) {
+            // Conversation is one-to-one, load the single icon
+            // Let's resolve the icon / text from the last sender
+            if (shortcutIcon != null) {
+                conversationIcon = shortcutIcon
+            }
+
+            for (i in messages.lastIndex downTo 0) {
+                val message = messages[i]
+                val sender = message.senderPerson
+                val senderKey = sender?.getKeyOrName()
+                if ((sender != null && senderKey != userKey) || i == 0) {
+                    if (conversationText.isNullOrEmpty()) {
+                        // We use the senderName as header text if no conversation title is provided
+                        // (This usually happens for most 1:1 conversations)
+                        conversationText = sender?.name ?: ""
+                    }
+                    if (conversationIcon == null) {
+                        var avatarIcon = sender?.icon
+                        if (avatarIcon == null) {
+                            avatarIcon = builder.getDefaultAvatar(name = conversationText)
+                        }
+                        conversationIcon = avatarIcon
+                    }
+                    break
+                }
+            }
+        }
+
+        if (conversationIcon == null) {
+            conversationIcon = notification.getLargeIcon()
+        }
+
+        // If is one-to-one or the conversation has an icon, return a single icon
+        if (!isGroupConversation || conversationIcon != null) {
+            return SingleIcon(conversationIcon?.loadDrawable(systemUiContext))
+        }
+
+        // Otherwise, let's find the two last conversations to build a face pile:
+        var secondLastIcon: Icon? = null
+        var lastIcon: Icon? = null
+        var lastKey: CharSequence? = null
+
+        for (i in groups.lastIndex downTo 0) {
+            val message = groups[i][0]
+            val sender = message.senderPerson ?: user
+            val senderKey = sender.getKeyOrName()
+            val notUser = senderKey != userKey
+            val notIncluded = senderKey != lastKey
+
+            if ((notUser && notIncluded) || (i == 0 && lastKey == null)) {
+                if (lastIcon == null) {
+                    lastIcon =
+                        sender.icon
+                            ?: builder.getDefaultAvatar(
+                                name = sender.name,
+                                uniqueNames = uniqueNames
+                            )
+                    lastKey = senderKey
+                } else {
+                    secondLastIcon =
+                        sender.icon
+                            ?: builder.getDefaultAvatar(
+                                name = sender.name,
+                                uniqueNames = uniqueNames
+                            )
+                    break
+                }
+            }
+        }
+
+        if (lastIcon == null) {
+            lastIcon = builder.getDefaultAvatar(name = "")
+        }
+
+        if (secondLastIcon == null) {
+            secondLastIcon = builder.getDefaultAvatar(name = "")
+        }
+
+        return FacePile(
+            topIconDrawable = secondLastIcon.loadDrawable(systemUiContext),
+            bottomIconDrawable = lastIcon.loadDrawable(systemUiContext),
+            bottomBackgroundColor = builder.getBackgroundColor(/* isHeader = */ false),
+        )
+    }
+
+    @JvmStatic
+    fun inflateSingleLineViewHolder(
+        isConversation: Boolean,
+        reinflateFlags: Int,
+        entry: NotificationEntry,
+        context: Context,
+        logger: NotificationContentInflaterLogger,
+    ): HybridNotificationView? {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return null
+        if (reinflateFlags and FLAG_CONTENT_VIEW_SINGLE_LINE == 0) {
+            return null
+        }
+
+        logger.logInflateSingleLine(entry, reinflateFlags, isConversation)
+        logger.logAsyncTaskProgress(entry, "inflating single-line content view")
+
+        var view: HybridNotificationView? = null
+
+        traceSection("NotificationContentInflater#inflateSingleLineView") {
+            val inflater = LayoutInflater.from(context)
+            val layoutRes: Int =
+                if (isConversation)
+                    com.android.systemui.res.R.layout.hybrid_conversation_notification
+                else com.android.systemui.res.R.layout.hybrid_notification
+            view = inflater.inflate(layoutRes, /* root = */ null) as HybridNotificationView
+            if (view == null) {
+                Log.wtf(TAG, "Single-line view inflation result is null for entry: ${entry.logKey}")
+            }
+        }
+        return view
+    }
+
+    private fun Notification.Builder.getDefaultAvatar(
+        name: CharSequence?,
+        uniqueNames: PeopleHelper.NameToPrefixMap? = null
+    ): Icon {
+        val layoutColor = getSmallIconColor(/* isHeader = */ false)
+        if (!name.isNullOrEmpty()) {
+            val symbol = uniqueNames?.getPrefix(name) ?: ""
+            return peopleHelper.createAvatarSymbol(
+                /* name = */ name,
+                /* symbol = */ symbol,
+                /* layoutColor = */ layoutColor
+            )
+        }
+        // If name is null, create default avatar with background color
+        // TODO(b/319829062): Investigate caching default icon for color
+        return peopleHelper.createAvatarSymbol(/* name = */ "", /* symbol = */ "", layoutColor)
+    }
+
+    private fun Person.getKeyOrName(): CharSequence? = if (key == null) name else key
+
+    private val peopleHelper = PeopleHelper()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineConversationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineConversationViewBinder.kt
new file mode 100644
index 0000000..69284bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineConversationViewBinder.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.statusbar.notification.row.ui.viewbinder
+
+import com.android.systemui.statusbar.notification.row.HybridConversationNotificationView
+import com.android.systemui.statusbar.notification.row.HybridNotificationView
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel
+
+object SingleLineConversationViewBinder {
+    @JvmStatic
+    fun bind(viewModel: SingleLineViewModel, view: HybridNotificationView?) {
+        if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return
+        if (view !is HybridConversationNotificationView || !viewModel.isConversation()) {
+            SingleLineViewBinder.bind(viewModel, view)
+            return
+        }
+
+        viewModel.conversationData?.avatar?.let { view.setAvatar(it) }
+        view.setText(
+            viewModel.titleText,
+            viewModel.contentText,
+            viewModel.conversationData?.conversationSenderName
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt
new file mode 100644
index 0000000..22e10c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.systemui.statusbar.notification.row.ui.viewbinder
+
+import com.android.systemui.statusbar.notification.row.HybridNotificationView
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel
+
+object SingleLineViewBinder {
+    @JvmStatic
+    fun bind(viewModel: SingleLineViewModel?, view: HybridNotificationView?) {
+        // bind the title and content text views
+        view?.apply {
+            bind(
+                /* title = */ viewModel?.titleText,
+                /* text = */ viewModel?.contentText,
+                /* contentView = */ null
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/SingleLineViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/SingleLineViewModel.kt
new file mode 100644
index 0000000..d583fa5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/SingleLineViewModel.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.systemui.statusbar.notification.row.ui.viewmodel
+
+import android.annotation.ColorInt
+import android.graphics.drawable.Drawable
+
+/**
+ * ViewModel for SingleLine Notification View.
+ *
+ * @property titleText the text of notification view title
+ * @property contentText the text of view content
+ * @property conversationData the data that is needed specifically for conversation single-line
+ *   views. Null conversationData shows that the notification is not conversation. Legacy
+ *   MessagingStyle Notifications doesn't have this member.
+ */
+data class SingleLineViewModel(
+    var titleText: CharSequence?,
+    var contentText: CharSequence?,
+    var conversationData: ConversationData?,
+) {
+    fun isConversation(): Boolean {
+        return conversationData != null
+    }
+}
+
+/**
+ * @property conversationSenderName the name of sender to show in the single-line view. Only group
+ *   conversation single-line views show the sender name.
+ * @property avatar the avatar to show for the conversation
+ */
+data class ConversationData(
+    val conversationSenderName: CharSequence?,
+    val avatar: ConversationAvatar,
+)
+
+/**
+ * An avatar to show for a single-line conversation notification, it can be either a single icon or
+ * a face pile.
+ */
+sealed class ConversationAvatar
+
+data class SingleIcon(val iconDrawable: Drawable?) : ConversationAvatar()
+
+/**
+ * A kind of avatar to show for a group conversation notification view. It consists of two avatars
+ * of the last two senders.
+ */
+data class FacePile(
+    val topIconDrawable: Drawable?,
+    val bottomIconDrawable: Drawable?,
+    @ColorInt val bottomBackgroundColor: Int
+) : ConversationAvatar()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 45b9c26..abf6c27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1295,8 +1295,8 @@
             if (singleLineView != null) {
                 minExpandHeight += singleLineView.getHeight();
             } else {
-                Log.e(TAG, "getMinHeight: child " + child + " single line view is null",
-                        new Exception());
+                Log.e(TAG, "getMinHeight: child " + child.getEntry().getKey()
+                                + " single line view is null", new Exception());
             }
             visibleChildren++;
         }
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 04db653..dd04531 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
@@ -4917,30 +4917,12 @@
     public void removeContainerView(View v) {
         Assert.isMainThread();
         removeView(v);
-        if (!FooterViewRefactor.isEnabled()) {
-            // A notification was removed, and we're not currently showing the empty shade view.
-            if (v instanceof ExpandableNotificationRow && !mController.isShowingEmptyShadeView()) {
-                mController.updateShowEmptyShadeView();
-                updateFooter();
-                mController.updateImportantForAccessibility();
-            }
-        }
-
         updateSpeedBumpIndex();
     }
 
     public void addContainerView(View v) {
         Assert.isMainThread();
         addView(v);
-        if (!FooterViewRefactor.isEnabled()) {
-            // A notification was added, and we're currently showing the empty shade view.
-            if (v instanceof ExpandableNotificationRow && mController.isShowingEmptyShadeView()) {
-                mController.updateShowEmptyShadeView();
-                updateFooter();
-                mController.updateImportantForAccessibility();
-            }
-        }
-
         updateSpeedBumpIndex();
     }
 
@@ -4948,14 +4930,6 @@
         Assert.isMainThread();
         ensureRemovedFromTransientContainer(v);
         addView(v, index);
-        // A notification was added, and we're currently showing the empty shade view.
-        if (!FooterViewRefactor.isEnabled() && v instanceof ExpandableNotificationRow
-                && mController.isShowingEmptyShadeView()) {
-            mController.updateShowEmptyShadeView();
-            updateFooter();
-            mController.updateImportantForAccessibility();
-        }
-
         updateSpeedBumpIndex();
     }
 
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 1143481..49fde39 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
@@ -2137,6 +2137,7 @@
 
             if (!FooterViewRefactor.isEnabled()) {
                 updateShowEmptyShadeView();
+                updateImportantForAccessibility();
             }
         }
     }
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 f842e30..fe5bdd4 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
@@ -18,9 +18,12 @@
 
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
+import android.view.View
+import android.view.WindowInsets
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
@@ -30,6 +33,9 @@
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 
 /** Binds the shared notification container to its view-model. */
@@ -65,6 +71,8 @@
                 }
             }
 
+        val burnInParams = MutableStateFlow(BurnInParameters())
+
         /*
          * For animation sensitive coroutines, immediately run just like applicationScope does
          * instead of doing a post() to the main thread. This extra delay can cause visible jitter.
@@ -122,7 +130,11 @@
                         }
                     }
 
-                    launch { viewModel.translationY.collect { controller.setTranslationY(it) } }
+                    launch {
+                        burnInParams
+                            .flatMapLatest { params -> viewModel.translationY(params) }
+                            .collect { y -> controller.setTranslationY(y) }
+                    }
 
                     launch {
                         viewModel.expansionAlpha.collect { controller.setMaxAlphaForExpansion(it) }
@@ -137,11 +149,20 @@
 
         controller.setOnHeightChangedRunnable(Runnable { viewModel.notificationStackChanged() })
 
+        view.setOnApplyWindowInsetsListener { v: View, insets: WindowInsets ->
+            val insetTypes = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout()
+            burnInParams.update { current ->
+                current.copy(topInset = insets.getInsetsIgnoringVisibility(insetTypes).top)
+            }
+            insets
+        }
+
         return object : DisposableHandle {
             override fun dispose() {
                 disposableHandle.dispose()
                 disposableHandleMainImmediate.dispose()
                 controller.setOnHeightChangedRunnable(null)
+                view.setOnApplyWindowInsetsListener(null)
             }
         }
     }
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 99cd89b..4617ce4 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
@@ -28,6 +28,8 @@
 import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
 import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
 import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
+import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
@@ -65,10 +67,11 @@
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val shadeInteractor: ShadeInteractor,
     communalInteractor: CommunalInteractor,
-    occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
+    private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
     lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,
     glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel,
-    lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel
+    lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel,
+    private val aodBurnInViewModel: AodBurnInViewModel,
 ) {
     private val statesForConstrainedNotifications =
         setOf(
@@ -313,20 +316,22 @@
      * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
      * translated as the keyguard fades out.
      */
-    val translationY: Flow<Float> =
-        combine(
+    fun translationY(params: BurnInParameters): Flow<Float> {
+        return combine(
+            aodBurnInViewModel.translationY(params).onStart { emit(0f) },
             isOnLockscreenWithoutShade,
             merge(
                 keyguardInteractor.keyguardTranslationY,
                 occludedToLockscreenTransitionViewModel.lockscreenTranslationY,
             )
-        ) { isOnLockscreenWithoutShade, translationY ->
+        ) { burnInY, isOnLockscreenWithoutShade, translationY ->
             if (isOnLockscreenWithoutShade) {
-                translationY
+                burnInY + translationY
             } else {
                 0f
             }
         }
+    }
 
     /**
      * When on keyguard, there is limited space to display notifications so calculate how many could
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 266c19c..64fcef5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -28,10 +28,10 @@
 
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 import static com.android.systemui.Flags.lightRevealMigration;
+import static com.android.systemui.Flags.predictiveBackSysui;
 import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
-import static com.android.systemui.Flags.predictiveBackSysui;
 
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
@@ -95,7 +95,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
@@ -126,6 +125,7 @@
 import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -202,12 +202,10 @@
 import com.android.systemui.statusbar.core.StatusBarInitializer;
 import com.android.systemui.statusbar.data.model.StatusBarMode;
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
@@ -225,7 +223,6 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
@@ -249,6 +246,7 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -278,19 +276,9 @@
     private static final String BANNER_ACTION_SETUP =
             "com.android.systemui.statusbar.banner_action_setup";
 
-    private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
     private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
     // 1020-1040 reserved for BaseStatusBar
 
-    /**
-     * TODO(b/249277686) delete this
-     * The delay to reset the hint text when the hint animation is finished running.
-     */
-    private static final int HINT_RESET_DELAY_MS = 1200;
-
-    /** If true, the lockscreen will show a distinct wallpaper */
-    public static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
-
     private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
 
     private final Context mContext;
@@ -300,7 +288,7 @@
     private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks;
     private float mTransitionToFullShadeProgress = 0f;
     private final NotificationListContainer mNotifListContainer;
-    private boolean mIsShortcutListSearchEnabled;
+    private final boolean mIsShortcutListSearchEnabled;
 
     private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
             new KeyguardStateController.Callback() {
@@ -459,7 +447,6 @@
     private final NotificationGutsManager mGutsManager;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
     private final KeyguardViewMediator mKeyguardViewMediator;
-    private final VisualInterruptionDecisionProvider mVisualInterruptionDecisionProvider;
     private final BrightnessSliderController.Factory mBrightnessSliderFactory;
     private final FeatureFlags mFeatureFlags;
     private final FragmentService mFragmentService;
@@ -555,7 +542,6 @@
     private int mLastLoggedStateFingerprint;
     private boolean mIsLaunchingActivityOverLockscreen;
 
-    private final UserSwitcherController mUserSwitcherController;
     private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
     protected final BatteryController mBatteryController;
     private UiModeManager mUiModeManager;
@@ -567,6 +553,25 @@
     private final WakefulnessLifecycle mWakefulnessLifecycle;
     protected final PowerInteractor mPowerInteractor;
 
+    private final CommunalInteractor mCommunalInteractor;
+
+    /**
+     * True if the device is showing the glanceable hub. See
+     * {@link CommunalInteractor#isIdleOnCommunal()} for more details.
+     */
+    private boolean mIsIdleOnCommunal = false;
+    private final Consumer<Boolean> mIdleOnCommunalConsumer = (Boolean idleOnCommunal) -> {
+        if (idleOnCommunal == mIsIdleOnCommunal) {
+            // Ignore initial value coming through the flow.
+            return;
+        }
+
+        mIsIdleOnCommunal = idleOnCommunal;
+        // Trigger an update for the scrim state when we enter or exit glanceable hub, so that we
+        // can transition to/from ScrimState.GLANCEABLE_HUB if needed.
+        updateScrimController();
+    };
+
     private boolean mNoAnimationOnNextBarModeChange;
     private final SysuiStatusBarStateController mStatusBarStateController;
 
@@ -586,8 +591,6 @@
     private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
             (extractor, which) -> updateTheme();
 
-    private final InteractionJankMonitor mJankMonitor;
-
     private final SceneContainerFlags mSceneContainerFlags;
 
     /**
@@ -615,12 +618,10 @@
             KeyguardBypassController keyguardBypassController,
             KeyguardStateController keyguardStateController,
             HeadsUpManager headsUpManager,
-            DynamicPrivacyController dynamicPrivacyController,
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
             NotificationGutsManager notificationGutsManager,
-            VisualInterruptionDecisionProvider visualInterruptionDecisionProvider,
             ShadeExpansionStateManager shadeExpansionStateManager,
             KeyguardViewMediator keyguardViewMediator,
             DisplayMetrics displayMetrics,
@@ -633,12 +634,12 @@
             NotificationLockscreenUserManager lockScreenUserManager,
             NotificationRemoteInputManager remoteInputManager,
             QuickSettingsController quickSettingsController,
-            UserSwitcherController userSwitcherController,
             BatteryController batteryController,
             SysuiColorExtractor colorExtractor,
             ScreenLifecycle screenLifecycle,
             WakefulnessLifecycle wakefulnessLifecycle,
             PowerInteractor powerInteractor,
+            CommunalInteractor communalInteractor,
             SysuiStatusBarStateController statusBarStateController,
             Optional<Bubbles> bubblesOptional,
             Lazy<NoteTaskController> noteTaskControllerLazy,
@@ -693,7 +694,6 @@
             WallpaperManager wallpaperManager,
             Optional<StartingSurface> startingSurfaceOptional,
             ActivityLaunchAnimator activityLaunchAnimator,
-            InteractionJankMonitor jankMonitor,
             DeviceStateManager deviceStateManager,
             WiredChargingRippleController wiredChargingRippleController,
             IDreamManager dreamManager,
@@ -727,7 +727,6 @@
         mFalsingManager = falsingManager;
         mBroadcastDispatcher = broadcastDispatcher;
         mGutsManager = notificationGutsManager;
-        mVisualInterruptionDecisionProvider = visualInterruptionDecisionProvider;
         mShadeExpansionStateManager = shadeExpansionStateManager;
         mKeyguardViewMediator = keyguardViewMediator;
         mDisplayMetrics = displayMetrics;
@@ -740,12 +739,12 @@
         mLockscreenUserManager = lockScreenUserManager;
         mRemoteInputManager = remoteInputManager;
         mQsController = quickSettingsController;
-        mUserSwitcherController = userSwitcherController;
         mBatteryController = batteryController;
         mColorExtractor = colorExtractor;
         mScreenLifecycle = screenLifecycle;
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mPowerInteractor = powerInteractor;
+        mCommunalInteractor = communalInteractor;
         mStatusBarStateController = statusBarStateController;
         mBubblesOptional = bubblesOptional;
         mNoteTaskControllerLazy = noteTaskControllerLazy;
@@ -795,7 +794,6 @@
         mMainExecutor = delayableExecutor;
         mMessageRouter = messageRouter;
         mWallpaperManager = wallpaperManager;
-        mJankMonitor = jankMonitor;
         mCameraLauncherLazy = cameraLauncherLazy;
         mAlternateBouncerInteractor = alternateBouncerInteractor;
         mUserTracker = userTracker;
@@ -1076,6 +1074,10 @@
         //TODO(b/264502026) move the rest of the listeners here.
         mDeviceStateManager.registerCallback(mMainExecutor,
                 new FoldStateListener(mContext, this::onFoldedStateChanged));
+
+        mJavaAdapter.alwaysCollectFlow(
+                mCommunalInteractor.isIdleOnCommunal(),
+                mIdleOnCommunalConsumer);
     }
 
     /**
@@ -2587,8 +2589,7 @@
                 // So if AOD is off or unsupported we need to trigger these updates at screen on
                 // when the keyguard is occluded.
                 mLockscreenUserManager.updatePublicMode();
-                mShadeSurface.getNotificationStackScrollLayoutController()
-                        .updateSensitivenessForOccludedWakeup();
+                mStackScrollerController.updateSensitivenessForOccludedWakeup();
             }
             if (mLaunchCameraWhenFinishedWaking) {
                 mCameraLauncherLazy.get().launchCamera(mLastCameraLaunchSource,
@@ -2821,6 +2822,8 @@
             // This will cancel the keyguardFadingAway animation if it is running. We need to do
             // this as otherwise it can remain pending and leave keyguard in a weird state.
             mUnlockScrimCallback.onCancelled();
+        } else if (mIsIdleOnCommunal) {
+            mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
         } else if (mKeyguardStateController.isShowing()
                 && !mKeyguardStateController.isOccluded()
                 && !unlocking) {
@@ -3088,7 +3091,7 @@
         }
     };
 
-    private StatusBarStateController.StateListener mStateListener =
+    private final StatusBarStateController.StateListener mStateListener =
             new StatusBarStateController.StateListener() {
                 @Override
                 public void onStatePreChange(int oldState, int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
deleted file mode 100644
index 9f08633..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ /dev/null
@@ -1,128 +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.systemui.statusbar.phone
-
-import android.content.Context
-import android.content.pm.PackageManager
-import android.hardware.Sensor
-import android.hardware.TriggerEvent
-import android.hardware.TriggerEventListener
-import com.android.keyguard.ActiveUnlockConfig
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.CoreStartable
-import com.android.systemui.Dumpable
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
-import com.android.systemui.util.Assert
-import com.android.systemui.util.sensors.AsyncSensorManager
-import java.io.PrintWriter
-import javax.inject.Inject
-
-/**
- * Triggers face auth on lift when the device is showing the lock screen. Only initialized
- * if face auth is supported on the device. Not to be confused with the lift to wake gesture
- * which is handled by {@link com.android.server.policy.PhoneWindowManager}.
- */
-@SysUISingleton
-class KeyguardLiftController @Inject constructor(
-        private val context: Context,
-        private val statusBarStateController: StatusBarStateController,
-        private val asyncSensorManager: AsyncSensorManager,
-        private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-        private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
-        private val dumpManager: DumpManager,
-        private val selectedUserInteractor: SelectedUserInteractor,
-) : Dumpable, CoreStartable {
-
-    private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
-    private var isListening = false
-    private var bouncerVisible = false
-
-    override fun start() {
-        if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
-            init()
-        }
-    }
-
-    private fun init() {
-        dumpManager.registerDumpable(this)
-        statusBarStateController.addCallback(statusBarStateListener)
-        keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
-        updateListeningState()
-    }
-
-    private val listener: TriggerEventListener = object : TriggerEventListener() {
-        override fun onTrigger(event: TriggerEvent?) {
-            Assert.isMainThread()
-            // Not listening anymore since trigger events unregister themselves
-            isListening = false
-            updateListeningState()
-            deviceEntryFaceAuthInteractor.onDeviceLifted()
-            keyguardUpdateMonitor.requestActiveUnlock(
-                ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE,
-                "KeyguardLiftController")
-        }
-    }
-
-    private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
-        override fun onKeyguardBouncerFullyShowingChanged(bouncer: Boolean) {
-            bouncerVisible = bouncer
-            updateListeningState()
-        }
-
-        override fun onKeyguardVisibilityChanged(visible: Boolean) {
-            updateListeningState()
-        }
-    }
-
-    private val statusBarStateListener = object : StatusBarStateController.StateListener {
-        override fun onDozingChanged(isDozing: Boolean) {
-            updateListeningState()
-        }
-    }
-
-    override fun dump(pw: PrintWriter, args: Array<out String>) {
-        pw.println("KeyguardLiftController:")
-        pw.println("  pickupSensor: $pickupSensor")
-        pw.println("  isListening: $isListening")
-        pw.println("  bouncerVisible: $bouncerVisible")
-    }
-
-    private fun updateListeningState() {
-        if (pickupSensor == null) {
-            return
-        }
-        val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible &&
-                !statusBarStateController.isDozing
-
-        val isFaceEnabled = deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
-        val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled
-        if (shouldListen != isListening) {
-            isListening = shouldListen
-
-            if (shouldListen) {
-                asyncSensorManager.requestTriggerSensor(listener, pickupSensor)
-            } else {
-                asyncSensorManager.cancelTriggerSensor(listener, pickupSensor)
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index aabe4a0..6f78604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -17,7 +17,9 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB;
 import static com.android.systemui.keyguard.shared.model.KeyguardState.GONE;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN;
 import static com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
@@ -62,6 +64,7 @@
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
 import com.android.systemui.keyguard.shared.model.ScrimAlpha;
 import com.android.systemui.keyguard.shared.model.TransitionState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -292,6 +295,30 @@
                 mScrimBehind.setViewAlpha(mBehindAlpha);
             };
 
+    /**
+     * Consumer that fades the behind scrim in and out during the transition between the lock screen
+     * and the glanceable hub.
+     *
+     * While the lock screen is showing, the behind scrim is used to slightly darken the lock screen
+     * wallpaper underneath. Since the glanceable hub is under all of the scrims, we want to fade
+     * out the scrim so that the glanceable hub isn't darkened when it opens.
+     *
+     * {@link #applyState()} handles the scrim alphas once on the glanceable hub, this is only
+     * responsible for setting the behind alpha during the transition.
+     */
+    private final Consumer<TransitionStep> mGlanceableHubConsumer = (TransitionStep step) -> {
+        final float baseAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+        final float transitionProgress = step.getValue();
+        if (step.getTo() == KeyguardState.LOCKSCREEN) {
+            // Transitioning back to lock screen, fade in behind scrim again.
+            mBehindAlpha = baseAlpha * transitionProgress;
+        } else if (step.getTo() == GLANCEABLE_HUB) {
+            // Transitioning to glanceable hub, fade out behind scrim.
+            mBehindAlpha = baseAlpha * (1 - transitionProgress);
+        }
+        mScrimBehind.setViewAlpha(mBehindAlpha);
+    };
+
     Consumer<TransitionStep> mBouncerToGoneTransition;
 
     @Inject
@@ -444,6 +471,14 @@
                 mBouncerToGoneTransition, mMainDispatcher);
         collectFlow(behindScrim, mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha(),
                 mScrimAlphaConsumer, mMainDispatcher);
+
+        // LOCKSCREEN<->GLANCEABLE_HUB
+        collectFlow(behindScrim,
+                mKeyguardTransitionInteractor.transition(LOCKSCREEN, GLANCEABLE_HUB),
+                mGlanceableHubConsumer, mMainDispatcher);
+        collectFlow(behindScrim,
+                mKeyguardTransitionInteractor.transition(GLANCEABLE_HUB, LOCKSCREEN),
+                mGlanceableHubConsumer, mMainDispatcher);
     }
 
     // TODO(b/270984686) recompute scrim height accurately, based on shade contents.
@@ -763,10 +798,15 @@
             // see: b/186644628
             mNotificationsScrim.setDrawableBounds(left - 1, top, right + 1, bottom);
             mScrimBehind.setBottomEdgePosition((int) top);
+        } else {
+            mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
+        }
+
+        // Only clip if the notif scrim is visible
+        if (mNotificationsAlpha > 0f) {
             mKeyguardInteractor.setTopClippingBounds((int) top);
         } else {
             mKeyguardInteractor.setTopClippingBounds(null);
-            mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
         }
     }
 
@@ -810,9 +850,9 @@
             return;
         }
         mBouncerHiddenFraction = bouncerHiddenAmount;
-        if (mState == ScrimState.DREAMING) {
-            // Only the dreaming state requires this for the scrim calculation, so we should
-            // only trigger an update if dreaming.
+        if (mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB) {
+            // The dreaming and glanceable hub states requires this for the scrim calculation, so we
+            // should only trigger an update in those states.
             applyAndDispatchState();
         }
     }
@@ -934,7 +974,7 @@
         } else if (mState == ScrimState.AUTH_SCRIMMED_SHADE) {
             mNotificationsAlpha = (float) Math.pow(getInterpolatedFraction(), 0.8f);
         } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED
-                || mState == ScrimState.PULSING) {
+                || mState == ScrimState.PULSING || mState == ScrimState.GLANCEABLE_HUB) {
             Pair<Integer, Float> result = calculateBackStateForState(mState);
             int behindTint = result.first;
             float behindAlpha = result.second;
@@ -945,6 +985,11 @@
                         mTransitionToFullShadeProgress);
                 behindTint = ColorUtils.blendARGB(behindTint, shadeResult.first,
                         mTransitionToFullShadeProgress);
+            } else if (mState == ScrimState.GLANCEABLE_HUB && mTransitionToFullShadeProgress == 0.0f
+                    && mBouncerHiddenFraction == KeyguardBouncerConstants.EXPANSION_HIDDEN) {
+                // Behind scrim should not be visible when idle on the glanceable hub and neither
+                // bouncer nor shade are showing.
+                behindAlpha = 0f;
             }
             mInFrontAlpha = mState.getFrontAlpha();
             if (mClipsQsScrim) {
@@ -960,6 +1005,13 @@
                 } else if (mState == ScrimState.SHADE_LOCKED) {
                     // going from KEYGUARD to SHADE_LOCKED state
                     mNotificationsAlpha = getInterpolatedFraction();
+                } else if (mState == ScrimState.GLANCEABLE_HUB
+                        && mTransitionToFullShadeProgress == 0.0f) {
+                    // Notification scrim should not be visible on the glanceable hub unless the
+                    // shade is showing or transitioning in. Otherwise the notification scrim will
+                    // be visible as the bouncer transitions in or after the notification shade
+                    // closes.
+                    mNotificationsAlpha = 0;
                 } else {
                     mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index e3b65ab..f2a649b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -20,6 +20,7 @@
 import android.os.Trace;
 
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.res.R;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
@@ -39,8 +40,8 @@
     OFF {
         @Override
         public void prepare(ScrimState previousState) {
-            mFrontTint = Color.BLACK;
-            mBehindTint = Color.BLACK;
+            mFrontTint = mBackgroundColor;
+            mBehindTint = mBackgroundColor;
 
             mFrontAlpha = 1f;
             mBehindAlpha = 1f;
@@ -74,15 +75,15 @@
             } else {
                 mAnimationDuration = ScrimController.ANIMATION_DURATION;
             }
-            mFrontTint = Color.BLACK;
-            mBehindTint = Color.BLACK;
-            mNotifTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
+            mFrontTint = mBackgroundColor;
+            mBehindTint = mBackgroundColor;
+            mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
 
             mFrontAlpha = 0;
             mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard;
             mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0;
             if (mClipQsScrim) {
-                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+                updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
             }
         }
     },
@@ -93,10 +94,10 @@
             // notif scrim alpha values are determined by ScrimController#applyState
             // based on the shade expansion
 
-            mFrontTint = Color.BLACK;
+            mFrontTint = mBackgroundColor;
             mFrontAlpha = .66f;
 
-            mBehindTint = Color.BLACK;
+            mBehindTint = mBackgroundColor;
             mBehindAlpha = 1f;
         }
     },
@@ -110,7 +111,7 @@
             mBehindTint = previousState.mBehindTint;
             mBehindAlpha = previousState.mBehindAlpha;
 
-            mFrontTint = Color.BLACK;
+            mFrontTint = mBackgroundColor;
             mFrontAlpha = .66f;
         }
     },
@@ -122,7 +123,7 @@
         @Override
         public void prepare(ScrimState previousState) {
             mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
-            mBehindTint = mClipQsScrim ? Color.BLACK : mSurfaceColor;
+            mBehindTint = mClipQsScrim ? mBackgroundColor : mSurfaceColor;
             mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
             mNotifTint = Color.TRANSPARENT;
             mFrontAlpha = 0f;
@@ -154,10 +155,10 @@
             mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
             mNotifAlpha = 1f;
             mFrontAlpha = 0f;
-            mBehindTint = mClipQsScrim ? Color.TRANSPARENT : Color.BLACK;
+            mBehindTint = mClipQsScrim ? Color.TRANSPARENT : mBackgroundColor;
 
             if (mClipQsScrim) {
-                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+                updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
             }
         }
     },
@@ -184,11 +185,11 @@
             final boolean isDocked = mDockManager.isDocked();
             mBlankScreen = mDisplayRequiresBlanking;
 
-            mFrontTint = Color.BLACK;
+            mFrontTint = mBackgroundColor;
             mFrontAlpha = (alwaysOnEnabled || isDocked || quickPickupEnabled)
                     ? mAodFrontScrimAlpha : 1f;
 
-            mBehindTint = Color.BLACK;
+            mBehindTint = mBackgroundColor;
             mBehindAlpha = ScrimController.TRANSPARENT;
 
             mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
@@ -222,8 +223,8 @@
         @Override
         public void prepare(ScrimState previousState) {
             mFrontAlpha = mAodFrontScrimAlpha;
-            mBehindTint = Color.BLACK;
-            mFrontTint = Color.BLACK;
+            mBehindTint = mBackgroundColor;
+            mFrontTint = mBackgroundColor;
             mBlankScreen = mDisplayRequiresBlanking;
             mAnimationDuration = mWakeLockScreenSensorActive
                     ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
@@ -231,7 +232,7 @@
         @Override
         public float getMaxLightRevealScrimAlpha() {
             return mWakeLockScreenSensorActive ? ScrimController.WAKE_SENSOR_SCRIM_ALPHA
-                : AOD.getMaxLightRevealScrimAlpha();
+                    : AOD.getMaxLightRevealScrimAlpha();
         }
     },
 
@@ -245,7 +246,6 @@
             mBehindAlpha = mClipQsScrim ? 1 : 0;
             mNotifAlpha = 0;
             mFrontAlpha = 0;
-
             mAnimationDuration = mKeyguardFadingAway
                     ? mKeyguardFadingAwayDuration
                     : CentralSurfaces.FADE_KEYGUARD_DURATION;
@@ -259,22 +259,22 @@
                     && !fromAod;
 
             mFrontTint = Color.TRANSPARENT;
-            mBehindTint = Color.BLACK;
+            mBehindTint = mBackgroundColor;
             mBlankScreen = false;
 
             if (mDisplayRequiresBlanking && previousState == ScrimState.AOD) {
                 // Set all scrims black, before they fade transparent.
-                updateScrimColor(mScrimInFront, 1f /* alpha */, Color.BLACK /* tint */);
-                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK /* tint */);
+                updateScrimColor(mScrimInFront, 1f /* alpha */, mBackgroundColor /* tint */);
+                updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor /* tint */);
 
                 // Scrims should still be black at the end of the transition.
-                mFrontTint = Color.BLACK;
-                mBehindTint = Color.BLACK;
+                mFrontTint = mBackgroundColor;
+                mBehindTint = mBackgroundColor;
                 mBlankScreen = true;
             }
 
             if (mClipQsScrim) {
-                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+                updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
             }
         }
     },
@@ -283,8 +283,8 @@
         @Override
         public void prepare(ScrimState previousState) {
             mFrontTint = Color.TRANSPARENT;
-            mBehindTint = Color.BLACK;
-            mNotifTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
+            mBehindTint = mBackgroundColor;
+            mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
 
             mFrontAlpha = 0;
             mBehindAlpha = mClipQsScrim ? 1 : 0;
@@ -293,9 +293,24 @@
             mBlankScreen = false;
 
             if (mClipQsScrim) {
-                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+                updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
             }
         }
+    },
+
+    /**
+     * Device is locked or on dream and user has swiped from the right edge to enter the glanceable
+     * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen
+     * or dream, as well as swipe down for the notifications and up for the bouncer.
+     */
+    GLANCEABLE_HUB {
+        @Override
+        public void prepare(ScrimState previousState) {
+            // No scrims should be visible by default in this state.
+            mBehindAlpha = 0;
+            mNotifAlpha = 0;
+            mFrontAlpha = 0;
+        }
     };
 
     boolean mBlankScreen = false;
@@ -327,9 +342,11 @@
     boolean mKeyguardFadingAway;
     long mKeyguardFadingAwayDuration;
     boolean mClipQsScrim;
+    int mBackgroundColor;
 
     public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters,
             DockManager dockManager) {
+        mBackgroundColor = scrimBehind.getContext().getColor(R.color.shade_scrim_background_dark);
         mScrimInFront = scrimInFront;
         mScrimBehind = scrimBehind;
 
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 88347ab..4c83ca2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -69,6 +69,7 @@
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.KeyguardWmStateRefactor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
@@ -474,7 +475,7 @@
             mIsDocked = mDockManager.isDocked();
         }
 
-        if (mFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+        if (KeyguardWmStateRefactor.isEnabled()) {
             // Show the keyguard views whenever we've told WM that the lockscreen is visible.
             mShadeViewController.postToView(() ->
                     collectFlow(
@@ -1428,7 +1429,7 @@
             executeAfterKeyguardGoneAction();
         }
 
-        if (mFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+        if (KeyguardWmStateRefactor.isEnabled()) {
             mKeyguardTransitionInteractor.startDismissKeyguardTransition();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
index 0e67756..f73d089 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
@@ -153,7 +153,14 @@
         if (satelliteManager != null) {
             // First, check that satellite is supported on this device
             scope.launch {
-                ensureMinUptime(systemClock, MIN_UPTIME)
+                val waitTime = ensureMinUptime(systemClock, MIN_UPTIME)
+                if (waitTime > 0) {
+                    logBuffer.i({ long1 = waitTime }) {
+                        "Waiting $long1 ms before checking for satellite support"
+                    }
+                    delay(waitTime)
+                }
+
                 satelliteSupport.value = satelliteManager.checkSatelliteSupported()
 
                 logBuffer.i(
@@ -176,7 +183,7 @@
                                  */
                                 while (true) {
                                     logBuffer.i {
-                                        "requestIsSatelliteCommunicationAllowedForCurrentLocation"
+                                        "requestIsCommunicationAllowedForCurrentLocation"
                                     }
                                     checkIsSatelliteAllowed()
                                     delay(POLLING_INTERVAL_MS)
@@ -209,14 +216,13 @@
                 var registered = false
 
                 try {
-                    val res =
-                        sm.registerForSatelliteModemStateChanged(bgDispatcher.asExecutor(), cb)
+                    val res = sm.registerForModemStateChanged(bgDispatcher.asExecutor(), cb)
                     registered = res == SATELLITE_RESULT_SUCCESS
                 } catch (e: Exception) {
                     logBuffer.e("error registering for modem state", e)
                 }
 
-                awaitClose { if (registered) sm.unregisterForSatelliteModemStateChanged(cb) }
+                awaitClose { if (registered) sm.unregisterForModemStateChanged(cb) }
             }
             .flowOn(bgDispatcher)
 
@@ -248,7 +254,7 @@
     /** Fire off a request to check for satellite availability. Always runs on the bg context */
     private suspend fun checkIsSatelliteAllowed() =
         withContext(bgDispatcher) {
-            satelliteManager?.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+            satelliteManager?.requestIsCommunicationAllowedForCurrentLocation(
                 bgDispatcher.asExecutor(),
                 object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> {
                     override fun onError(e: SatelliteManager.SatelliteException) {
@@ -260,7 +266,7 @@
                     }
 
                     override fun onResult(allowed: Boolean) {
-                        logBuffer.i { allowed.toString() }
+                        logBuffer.i { "isSatelliteAllowedForCurrentLocation: $allowed" }
                         isSatelliteAllowedForCurrentLocation.value = allowed
                     }
                 }
@@ -294,7 +300,7 @@
                 }
 
             try {
-                requestIsSatelliteSupported(bgDispatcher.asExecutor(), cb)
+                requestIsSupported(bgDispatcher.asExecutor(), cb)
             } catch (error: Exception) {
                 logBuffer.e(
                     "Exception when checking for satellite support. " +
@@ -309,19 +315,14 @@
         // TTL for satellite polling is one hour
         const val POLLING_INTERVAL_MS: Long = 1000 * 60 * 60
 
-        // Let the system boot up and stabilize before we check for system support
-        const val MIN_UPTIME: Long = 1000 * 60
+        // Let the system boot up (5s) and stabilize before we check for system support
+        const val MIN_UPTIME: Long = 1000 * 5
 
         private const val TAG = "DeviceBasedSatelliteRepo"
 
-        /** If our process hasn't been up for at least MIN_UPTIME, delay until we reach that time */
-        private suspend fun ensureMinUptime(clock: SystemClock, uptime: Long) {
-            val timeTilMinUptime =
-                uptime - (clock.uptimeMillis() - android.os.Process.getStartUptimeMillis())
-            if (timeTilMinUptime > 0) {
-                delay(timeTilMinUptime)
-            }
-        }
+        /** Calculates how long we have to wait to reach MIN_UPTIME */
+        private fun ensureMinUptime(clock: SystemClock, uptime: Long): Long =
+            uptime - (clock.uptimeMillis() - android.os.Process.getStartUptimeMillis())
 
         /** A couple of convenience logging methods rather than a whole class */
         private fun LogBuffer.i(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index 8779577..6e1114c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -79,7 +79,7 @@
             } else {
                 flowOf(false)
             }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), true)
 }
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index a2d8d15..20d1fff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -28,8 +28,6 @@
 import android.icu.text.DateTimePatternGenerator;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -50,11 +48,11 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.FontSizeUtils;
+import com.android.systemui.res.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.demomode.DemoModeCommandReceiver;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -108,7 +106,6 @@
     private final int mAmPmStyle;
     private boolean mShowSeconds;
     private Handler mSecondsHandler;
-    private HandlerThread mHandlerThread;
 
     // Fields to cache the width so the clock remains at an approximately constant width
     private int mCharsAtCurrentWidth = -1;
@@ -149,8 +146,6 @@
         }
         mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
         mUserTracker = Dependency.get(UserTracker.class);
-        mHandlerThread = new HandlerThread("Clock");
-        mHandlerThread.start();
 
         setIncludeFontPadding(false);
     }
@@ -210,8 +205,7 @@
             Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
                     StatusBarIconController.ICON_HIDE_LIST);
             mCommandQueue.addCallback(this);
-            mUserTracker.addCallback(mUserChangedCallback,
-                       new HandlerExecutor(mHandlerThread.getThreadHandler()));
+            mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
             mCurrentUserId = mUserTracker.getUserId();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
index a7440d6..b7d8ee3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
@@ -21,8 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
 import android.os.UserHandle;
 
 import androidx.annotation.NonNull;
@@ -53,7 +51,6 @@
     private final UserTracker mUserTracker;
     private AlarmManager mAlarmManager;
     private AlarmManager.AlarmClockInfo mNextAlarm;
-    private HandlerThread mHandlerThread;
 
     private final UserTracker.Callback mUserChangedCallback =
             new UserTracker.Callback() {
@@ -78,10 +75,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
         broadcastDispatcher.registerReceiver(this, filter, null, UserHandle.ALL);
-        mHandlerThread = new HandlerThread("NextAlarmControllerImpl");
-        mHandlerThread.start();
-        mUserTracker.addCallback(mUserChangedCallback,
-                    new HandlerExecutor(mHandlerThread.getThreadHandler()));
+        mUserTracker.addCallback(mUserChangedCallback, mainExecutor);
         updateNextAlarm();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 6a6efbc..9f4a906 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -157,7 +157,7 @@
         // TODO: re-register network callback on user change.
         mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
         onUserSwitched(mUserTracker.getUserId());
-        mUserTracker.addCallback(mUserChangedCallback, mBgExecutor);
+        mUserTracker.addCallback(mUserChangedCallback, mMainExecutor);
     }
 
     public void dump(PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
index 0bc0e88..2ed9d15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
@@ -36,9 +36,9 @@
 
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.drawable.UserIconDrawable;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.res.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.settings.UserTracker;
 
 import java.util.ArrayList;
@@ -66,11 +66,11 @@
     /**
      */
     @Inject
-    public UserInfoControllerImpl(Context context, @Background Executor bgExecutor,
+    public UserInfoControllerImpl(Context context, @Main Executor mainExecutor,
             UserTracker userTracker) {
         mContext = context;
         mUserTracker = userTracker;
-        mUserTracker.addCallback(mUserChangedCallback, bgExecutor);
+        mUserTracker.addCallback(mUserChangedCallback, mainExecutor);
 
         IntentFilter profileFilter = new IntentFilter();
         profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index f0b4930..df210b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -29,7 +29,6 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerExecutor;
-import android.os.HandlerThread;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -82,7 +81,6 @@
     private volatile int mZenMode;
     private long mZenUpdateTime;
     private NotificationManager.Policy mConsolidatedNotificationPolicy;
-    private HandlerThread mHandlerThread;
 
     private final UserTracker.Callback mUserChangedCallback =
             new UserTracker.Callback() {
@@ -135,8 +133,6 @@
                 }
             }
         };
-        mHandlerThread = new HandlerThread("ZenModeControllerImpl");
-        mHandlerThread.start();
         mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         globalSettings.registerContentObserver(Global.ZEN_MODE, modeContentObserver);
         updateZenMode(getModeSettingValueFromProvider());
@@ -147,8 +143,7 @@
         mSetupObserver = new SetupObserver(handler);
         mSetupObserver.register();
         mUserManager = context.getSystemService(UserManager.class);
-        mUserTracker.addCallback(mUserChangedCallback,
-                new HandlerExecutor(mHandlerThread.getThreadHandler()));
+        mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(handler));
         // This registers the alarm broadcast receiver for the current user
         mUserChangedCallback.onUserChanged(getCurrentUser(), context);
 
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 77518db..2b9ad50 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -480,7 +480,7 @@
             return;
         }
 
-        mUserTracker.addCallback(mUserTrackerCallback, mBgExecutor);
+        mUserTracker.addCallback(mUserTrackerCallback, mMainExecutor);
 
         mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index f5b4d17..550a65c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -26,7 +26,6 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerExecutor;
-import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -39,11 +38,11 @@
 
 import com.android.internal.util.ArrayUtils;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -99,7 +98,6 @@
     private UserTracker.Callback mCurrentUserTracker;
     private UserTracker mUserTracker;
     private final ComponentName mTunerComponent;
-    private HandlerThread mHandlerThread;
 
     /**
      */
@@ -119,8 +117,7 @@
         mDemoModeController = demoModeController;
         mUserTracker = userTracker;
         mTunerComponent = new ComponentName(mContext, TunerActivity.class);
-        mHandlerThread = new HandlerThread("TunerServiceImpl");
-        mHandlerThread.start();
+
         for (UserInfo user : UserManager.get(mContext).getUsers()) {
             mCurrentUser = user.getUserHandle().getIdentifier();
             if (getValue(TUNER_VERSION, 0) != CURRENT_TUNER_VERSION) {
@@ -138,7 +135,7 @@
             }
         };
         mUserTracker.addCallback(mCurrentUserTracker,
-                new HandlerExecutor(mHandlerThread.getThreadHandler()));
+                new HandlerExecutor(mainHandler));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index 10fc83c..0016d95 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -26,7 +26,6 @@
 import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager
 import com.android.systemui.util.kotlin.getOrNull
 import dagger.BindsInstance
-import dagger.Lazy
 import dagger.Module
 import dagger.Provides
 import dagger.Subcomponent
@@ -57,7 +56,6 @@
         rotationProvider: Optional<NaturalRotationUnfoldProgressProvider>,
         @Named(UNFOLD_STATUS_BAR) scopedProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
         @UnfoldBg bgProvider: Optional<UnfoldTransitionProgressProvider>,
-        unfoldLatencyTracker: Lazy<UnfoldLatencyTracker>,
         factory: SysUIUnfoldComponent.Factory
     ): Optional<SysUIUnfoldComponent> {
         val p1 = provider.getOrNull()
@@ -67,7 +65,7 @@
         return if (p1 == null || p2 == null || p3 == null || p4 == null) {
             Optional.empty()
         } else {
-            Optional.of(factory.create(p1, p2, p3, p4, unfoldLatencyTracker.get()))
+            Optional.of(factory.create(p1, p2, p3, p4))
         }
     }
 }
@@ -82,8 +80,7 @@
             @BindsInstance p1: UnfoldTransitionProgressProvider,
             @BindsInstance p2: NaturalRotationUnfoldProgressProvider,
             @BindsInstance p3: ScopedUnfoldTransitionProgressProvider,
-            @BindsInstance @UnfoldBg p4: UnfoldTransitionProgressProvider,
-            @BindsInstance p5: UnfoldLatencyTracker,
+            @BindsInstance @UnfoldBg p4: UnfoldTransitionProgressProvider
         ): SysUIUnfoldComponent
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
index 8c66c2f..33fa9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
@@ -22,7 +22,6 @@
 import android.os.Trace
 import android.util.Log
 import com.android.internal.util.LatencyTracker
-import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.UiBackground
 import com.android.systemui.keyguard.ScreenLifecycle
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
@@ -42,7 +41,7 @@
  * For now, the focus is on the time the inner display is visible, but in the future, it is easily
  * possible to monitor the time to go from the inner screen to the outer.
  */
-@SysUISingleton
+@SysUIUnfoldScope
 class UnfoldLatencyTracker
 @Inject
 constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index 8bef53c..9bd0e32 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -177,17 +177,20 @@
 
     @Module
     interface Bindings {
-        @Binds
-        @IntoMap
-        @ClassKey(UnfoldTraceLogger::class)
-        fun bindUnfoldTraceLogger(impl: UnfoldTraceLogger): CoreStartable
-
         @Binds fun bindRepository(impl: UnfoldTransitionRepositoryImpl): UnfoldTransitionRepository
 
         @Binds fun bindInteractor(impl: UnfoldTransitionInteractorImpl): UnfoldTransitionInteractor
 
         @Binds fun bindFoldStateRepository(impl: FoldStateRepositoryImpl): FoldStateRepository
     }
+
+    @Module
+    interface Startables {
+        @Binds
+        @IntoMap
+        @ClassKey(UnfoldTraceLogger::class)
+        fun bindUnfoldTraceLogger(impl: UnfoldTraceLogger): CoreStartable
+    }
 }
 
 const val UNFOLD_STATUS_BAR = "unfold_status_bar"
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index 74e1339..cf76c0d 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -190,7 +190,7 @@
                         }
                     }
 
-                tracker.addCallback(callback, backgroundDispatcher.asExecutor())
+                tracker.addCallback(callback, mainDispatcher.asExecutor())
                 send(currentSelectionStatus)
 
                 awaitClose { tracker.removeCallback(callback) }
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepository.kt b/packages/SystemUI/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepository.kt
index adae782..31a8d86 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepository.kt
@@ -26,7 +26,7 @@
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.withContext
+import kotlinx.coroutines.flow.flowOn
 
 /** Utility class that could give information about if animation are enabled in the system */
 interface AnimationStatusRepository {
@@ -45,24 +45,26 @@
      * Emits true if animations are enabled in the system, after subscribing it immediately emits
      * the current state
      */
-    override fun areAnimationsEnabled(): Flow<Boolean> = conflatedCallbackFlow {
-        val initialValue = withContext(backgroundDispatcher) { resolver.areAnimationsEnabled() }
-        trySend(initialValue)
+    override fun areAnimationsEnabled(): Flow<Boolean> =
+        conflatedCallbackFlow {
+                val initialValue = resolver.areAnimationsEnabled()
+                trySend(initialValue)
 
-        val observer =
-            object : ContentObserver(backgroundHandler) {
-                override fun onChange(selfChange: Boolean) {
-                    val updatedValue = resolver.areAnimationsEnabled()
-                    trySend(updatedValue)
-                }
+                val observer =
+                    object : ContentObserver(backgroundHandler) {
+                        override fun onChange(selfChange: Boolean) {
+                            val updatedValue = resolver.areAnimationsEnabled()
+                            trySend(updatedValue)
+                        }
+                    }
+
+                resolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
+                    /* notifyForDescendants= */ false,
+                    observer
+                )
+
+                awaitClose { resolver.unregisterContentObserver(observer) }
             }
-
-        resolver.registerContentObserver(
-            Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
-            /* notifyForDescendants= */ false,
-            observer
-        )
-
-        awaitClose { resolver.unregisterContentObserver(observer) }
-    }
+            .flowOn(backgroundDispatcher)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/BooleanFlowOperators.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/BooleanFlowOperators.kt
new file mode 100644
index 0000000..693a835
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/BooleanFlowOperators.kt
@@ -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 com.android.systemui.util.kotlin
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+object BooleanFlowOperators {
+    /**
+     * Logical AND operator for boolean flows. Will collect all flows and [combine] them to
+     * determine the result.
+     *
+     * Usage:
+     * ```
+     * val result = and(flow1, flow2)
+     * ```
+     */
+    fun and(vararg flows: Flow<Boolean>): Flow<Boolean> =
+        combine(flows.asIterable()) { values -> values.all { it } }
+
+    /**
+     * Logical NOT operator for a boolean flow.
+     *
+     * Usage:
+     * ```
+     * val negatedFlow = not(flow)
+     * ```
+     */
+    fun not(flow: Flow<Boolean>) = flow.map { !it }
+
+    /**
+     * Logical OR operator for a boolean flow. Will collect all flows and [combine] them to
+     * determine the result.
+     */
+    fun or(vararg flows: Flow<Boolean>): Flow<Boolean> =
+        combine(flows.asIterable()) { values -> values.any { it } }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
deleted file mode 100644
index cf6b0d9..0000000
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.android.systemui.util.kotlin
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dagger.qualifiers.Tracing
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
-import dagger.Module
-import dagger.Provides
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.plus
-import kotlin.coroutines.CoroutineContext
-
-/** Providers for various coroutines-related constructs. */
-@Module
-class CoroutinesModule {
-    @Provides
-    @SysUISingleton
-    @Application
-    fun applicationScope(
-            @Main dispatcherContext: CoroutineContext,
-    ): CoroutineScope = CoroutineScope(dispatcherContext)
-
-    @Provides
-    @SysUISingleton
-    @Background
-    fun bgApplicationScope(
-            @Application applicationScope: CoroutineScope,
-            @Background coroutineContext: CoroutineContext,
-    ): CoroutineScope = applicationScope.plus(coroutineContext)
-
-    @Provides
-    @SysUISingleton
-    @Main
-    @Deprecated(
-        "Use @Main CoroutineContext instead",
-        ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext")
-    )
-    fun mainDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
-
-    @Provides
-    @SysUISingleton
-    @Main
-    fun mainCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
-        return Dispatchers.Main.immediate + tracingCoroutineContext
-    }
-
-    /**
-     * Provide a [CoroutineDispatcher] backed by a thread pool containing at most X threads, where
-     * X is the number of CPU cores available.
-     *
-     * Because there are multiple threads at play, there is no serialization order guarantee. You
-     * should use a [kotlinx.coroutines.channels.Channel] for serialization if necessary.
-     *
-     * @see Dispatchers.Default
-     */
-    @Provides
-    @SysUISingleton
-    @Background
-    @Deprecated(
-        "Use @Background CoroutineContext instead",
-        ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
-    )
-    fun bgDispatcher(): CoroutineDispatcher = Dispatchers.IO
-
-
-    @Provides
-    @Background
-    @SysUISingleton
-    fun bgCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
-        return Dispatchers.IO + tracingCoroutineContext
-    }
-
-    @OptIn(ExperimentalCoroutinesApi::class)
-    @Provides
-    @Tracing
-    @SysUISingleton
-    fun tracingCoroutineContext(): CoroutineContext {
-        return createCoroutineTracingContext()
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Dagger.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Dagger.kt
index c587f2e..5150389 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Dagger.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Dagger.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.util.kotlin
 
 import dagger.Lazy
+import java.util.Optional
 import kotlin.reflect.KProperty
 
 /**
@@ -30,3 +31,16 @@
  * ```
  */
 operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = get()
+
+/**
+ * Extension operator that allows developers to use [java.util.Optional] as a nullable property
+ * delegate:
+ * ```kotlin
+ *    class MyClass @Inject constructor(
+ *      optionalDependency: Optional<Foo>,
+ *    ) {
+ *      val dependency: Foo? by optionalDependency
+ *    }
+ * ```
+ */
+operator fun <T> Optional<T>.getValue(thisRef: Any?, property: KProperty<*>): T? = getOrNull()
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
new file mode 100644
index 0000000..8ecf250
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.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.util.kotlin
+
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.Tracing
+import dagger.Module
+import dagger.Provides
+import javax.inject.Singleton
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+/** Providers for various application-wide coroutines-related constructs. */
+@Module
+class GlobalCoroutinesModule {
+    @Provides
+    @Singleton
+    @Application
+    fun applicationScope(
+        @Main dispatcherContext: CoroutineContext,
+    ): CoroutineScope = CoroutineScope(dispatcherContext)
+
+    @Provides
+    @Singleton
+    @Main
+    @Deprecated(
+        "Use @Main CoroutineContext instead",
+        ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+    )
+    fun mainDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
+
+    @Provides
+    @Singleton
+    @Main
+    fun mainCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
+        return Dispatchers.Main.immediate + tracingCoroutineContext
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Provides
+    @Tracing
+    @Singleton
+    fun tracingCoroutineContext(): CoroutineContext {
+        return createCoroutineTracingContext()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
new file mode 100644
index 0000000..a13d85b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Tracing
+import dagger.Module
+import dagger.Provides
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.plus
+
+/** Providers for various SystemIU specific coroutines-related constructs. */
+@Module
+class SysUICoroutinesModule {
+    @Provides
+    @SysUISingleton
+    @Background
+    fun bgApplicationScope(
+        @Application applicationScope: CoroutineScope,
+        @Background coroutineContext: CoroutineContext,
+    ): CoroutineScope = applicationScope.plus(coroutineContext)
+
+    /**
+     * Provide a [CoroutineDispatcher] backed by a thread pool containing at most X threads, where X
+     * is the number of CPU cores available.
+     *
+     * Because there are multiple threads at play, there is no serialization order guarantee. You
+     * should use a [kotlinx.coroutines.channels.Channel] for serialization if necessary.
+     *
+     * @see Dispatchers.Default
+     */
+    @Provides
+    @SysUISingleton
+    @Background
+    @Deprecated(
+        "Use @Background CoroutineContext instead",
+        ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+    )
+    fun bgDispatcher(): CoroutineDispatcher = Dispatchers.IO
+
+    @Provides
+    @Background
+    @SysUISingleton
+    fun bgCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
+        return Dispatchers.IO + tracingCoroutineContext
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
new file mode 100644
index 0000000..8d5e55a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.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.volume.dagger
+
+import android.media.AudioManager
+import com.android.settingslib.volume.data.repository.AudioRepository
+import com.android.settingslib.volume.data.repository.AudioRepositoryImpl
+import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import dagger.Module
+import dagger.Provides
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+
+/** Dagger module for audio code in the volume package */
+@Module
+interface AudioModule {
+
+    companion object {
+
+        @Provides
+        fun provideAudioRepository(
+            audioManager: AudioManager,
+            @Background coroutineContext: CoroutineContext,
+            @Application coroutineScope: CoroutineScope,
+        ): AudioRepository = AudioRepositoryImpl(audioManager, coroutineContext, coroutineScope)
+
+        @Provides
+        fun provideAudioModeInteractor(repository: AudioRepository): AudioModeInteractor =
+            AudioModeInteractor(repository)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index b1bfbe0..c842e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -60,6 +60,9 @@
 
 /** Dagger Module for code in the volume package. */
 @Module(
+        includes = {
+                AudioModule.class,
+        },
         subcomponents = {
                 VolumePanelComponent.class
         }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 7c6ad23..1e801ae 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -32,8 +32,6 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.util.Log;
 import android.view.Display;
@@ -127,7 +125,6 @@
     private final DisplayTracker mDisplayTracker;
     private final NoteTaskInitializer mNoteTaskInitializer;
     private final Executor mSysUiMainExecutor;
-    private HandlerThread mHandlerThread;
 
     // Listeners and callbacks. Note that we prefer member variable over anonymous class here to
     // avoid the situation that some implementations, like KeyguardUpdateMonitor, use WeakReference
@@ -209,8 +206,6 @@
         mDisplayTracker = displayTracker;
         mNoteTaskInitializer = noteTaskInitializer;
         mSysUiMainExecutor = sysUiMainExecutor;
-        mHandlerThread = new HandlerThread("WMShell");
-        mHandlerThread.start();
     }
 
     @Override
@@ -224,8 +219,7 @@
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
 
         // Subscribe to user changes
-        mUserTracker.addCallback(mUserChangedCallback,
-                     new HandlerExecutor(mHandlerThread.getThreadHandler()));
+        mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
 
         mCommandQueue.addCallback(this);
         mPipOptional.ifPresent(this::initPip);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
index 44770fa..b23dfdc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.accessibility;
 
+import android.annotation.NonNull;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.os.IBinder;
 import android.view.Display;
 import android.view.View;
 import android.view.ViewGroup;
@@ -89,6 +91,11 @@
         return mWindowManager.getMaximumWindowMetrics();
     }
 
+    @Override
+    public @NonNull IBinder getDefaultToken() {
+        return mWindowManager.getDefaultToken();
+    }
+
     public View getAttachedView() {
         return mView;
     }
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 d86d123..8299acb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -21,8 +21,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -33,10 +35,16 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteException;
+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.testing.AndroidTestingRunner;
 import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -46,6 +54,7 @@
 import androidx.test.filters.LargeTest;
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.AnimatorTestRule;
 import com.android.systemui.model.SysUiState;
@@ -63,7 +72,10 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
 
 @LargeTest
 @RunWith(AndroidTestingRunner.class)
@@ -71,6 +83,8 @@
 
     @Rule
     public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
     private static final float DEFAULT_SCALE = 4.0f;
     private static final float DEFAULT_CENTER_X = 400.0f;
     private static final float DEFAULT_CENTER_Y = 500.0f;
@@ -107,6 +121,13 @@
 
     private TestableWindowManager mWindowManager;
     private ValueAnimator mValueAnimator;
+    // This list contains all SurfaceControlViewHosts created during a given test. If the
+    // magnification window is recreated during a test, the list will contain more than a single
+    // element.
+    private List<SurfaceControlViewHost> mSurfaceControlViewHosts = new ArrayList<>();
+    // The most recently created SurfaceControlViewHost.
+    private SurfaceControlViewHost mSurfaceControlViewHost;
+    private SurfaceControl.Transaction mTransaction;
 
     @Before
     public void setUp() throws Exception {
@@ -123,10 +144,27 @@
         mValueAnimator = newValueAnimator();
         mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
                 mContext, mValueAnimator);
-        mController = new SpyWindowMagnificationController(mContext, mHandler,
+
+        Supplier<SurfaceControlViewHost> scvhSupplier = () -> {
+            mSurfaceControlViewHost = spy(new SurfaceControlViewHost(
+                    mContext, mContext.getDisplay(), new Binder(), "WindowMagnification"));
+            mSurfaceControlViewHosts.add(mSurfaceControlViewHost);
+            return mSurfaceControlViewHost;
+        };
+
+        mTransaction = spy(new SurfaceControl.Transaction());
+        mController = new SpyWindowMagnificationController(
+                mContext,
+                mHandler,
                 mWindowMagnificationAnimationController,
-                mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(),
-                mWindowMagnifierCallback, mSysUiState, mSecureSettings);
+                /* mirrorWindowControl= */ null,
+                mTransaction,
+                mWindowMagnifierCallback,
+                mSysUiState,
+                mSecureSettings,
+                scvhSupplier,
+                mSfVsyncFrameProvider);
+
         mSpyController = mController.getSpyController();
     }
 
@@ -235,8 +273,52 @@
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
     }
 
+    @RequiresFlagsEnabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER)
     @Test
-    public void enableWindowMagnificationWithScaleOne_enabled_AnimationAndInvokeCallback()
+    public void
+            enableWindowMagnificationScaleOne_enabledAndWindowlessFlagOn_AnimationAndCallbackTrue()
+            throws RemoteException {
+        enableWindowMagnificationWithoutAnimation();
+
+        // Wait for Rects updated.
+        waitForIdleSync();
+        View mirrorView = mSurfaceControlViewHost.getView();
+        final float targetScale = 1.0f;
+        // Move the magnifier to the top left corner, within the boundary
+        final float targetCenterX = mirrorView.getWidth() / 2.0f;
+        final float targetCenterY = mirrorView.getHeight() / 2.0f;
+
+        Mockito.reset(mSpyController);
+        getInstrumentation().runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                    targetCenterX, targetCenterY, mAnimationCallback);
+            mCurrentScale.set(mController.getScale());
+            mCurrentCenterX.set(mController.getCenterX());
+            mCurrentCenterY.set(mController.getCenterY());
+            advanceTimeBy(mWaitAnimationDuration);
+        });
+
+        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+                mScaleCaptor.capture(),
+                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
+                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
+        verifyStartValue(mScaleCaptor, mCurrentScale.get());
+        verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
+        verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
+        verifyStartValue(mOffsetXCaptor, 0f);
+        verifyStartValue(mOffsetYCaptor, 0f);
+
+        verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
+
+        verify(mAnimationCallback).onResult(true);
+        assertEquals(WindowMagnificationAnimationController.STATE_ENABLED,
+                mWindowMagnificationAnimationController.getState());
+    }
+
+    @RequiresFlagsDisabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER)
+    @Test
+    public void
+            enableWindowMagnificationScaleOne_enabledAndWindowlessFlagOff_AnimationAndCallbackTrue()
             throws RemoteException {
         enableWindowMagnificationWithoutAnimation();
 
@@ -475,8 +557,46 @@
         verify(mAnimationCallback2).onResult(true);
     }
 
+    @RequiresFlagsEnabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER)
     @Test
-    public void enableWindowMagnificationWithOffset_expectedValues() {
+    public void enableWindowMagnificationWithOffset_windowlessFlagOn_expectedValues() {
+        final float offsetRatio = -0.1f;
+        final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
+
+        Mockito.reset(mSpyController);
+        getInstrumentation().runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+                    windowBounds.exactCenterX(), windowBounds.exactCenterY(),
+                    offsetRatio, offsetRatio, mAnimationCallback);
+            advanceTimeBy(mWaitAnimationDuration);
+        });
+        // Wait for Rects update
+        waitForIdleSync();
+
+        final int mirrorSurfaceMargin = mContext.getResources().getDimensionPixelSize(
+                R.dimen.magnification_mirror_surface_margin);
+        final int defaultMagnificationWindowSize =
+                mController.getMagnificationWindowSizeFromIndex(
+                        WindowMagnificationSettings.MagnificationSize.MEDIUM);
+        final int defaultMagnificationFrameSize =
+                defaultMagnificationWindowSize - 2 * mirrorSurfaceMargin;
+        final int expectedOffset = (int) (defaultMagnificationFrameSize / 2 * offsetRatio);
+
+        final float expectedX = (int) (windowBounds.exactCenterX() + expectedOffset
+                - defaultMagnificationWindowSize / 2);
+        final float expectedY = (int) (windowBounds.exactCenterY() + expectedOffset
+                - defaultMagnificationWindowSize / 2);
+
+        // This is called 4 times when (1) first creating WindowlessMirrorWindow (2) SurfaceView is
+        // created and we place the mirrored content as a child of the SurfaceView
+        // (3) the animation starts (4) the animation updates
+        verify(mTransaction, times(4))
+                .setPosition(any(SurfaceControl.class), eq(expectedX), eq(expectedY));
+    }
+
+    @RequiresFlagsDisabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER)
+    @Test
+    public void enableWindowMagnificationWithOffset_windowlessFlagOff_expectedValues() {
         final float offsetRatio = -0.1f;
         final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
 
@@ -876,23 +996,28 @@
     private static class SpyWindowMagnificationController extends WindowMagnificationController {
         private WindowMagnificationController mSpyController;
 
-        SpyWindowMagnificationController(Context context, Handler handler,
+        SpyWindowMagnificationController(Context context,
+                Handler handler,
                 WindowMagnificationAnimationController animationController,
-                SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
-                MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
-                WindowMagnifierCallback callback, SysUiState sysUiState,
-                SecureSettings secureSettings) {
+                MirrorWindowControl mirrorWindowControl,
+                SurfaceControl.Transaction transaction,
+                WindowMagnifierCallback callback,
+                SysUiState sysUiState,
+                SecureSettings secureSettings,
+                Supplier<SurfaceControlViewHost> scvhSupplier,
+                SfVsyncFrameCallbackProvider sfVsyncFrameProvider) {
             super(
                     context,
                     handler,
                     animationController,
-                    sfVsyncFrameProvider,
                     mirrorWindowControl,
                     transaction,
                     callback,
                     sysUiState,
-                    WindowManagerGlobal::getWindowSession,
-                    secureSettings);
+                    secureSettings,
+                    scvhSupplier,
+                    sfVsyncFrameProvider,
+                    WindowManagerGlobal::getWindowSession);
             mSpyController = Mockito.mock(WindowMagnificationController.class);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 044881e..2225ad6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -68,6 +68,9 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -90,8 +93,10 @@
 import androidx.test.filters.LargeTest;
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.AnimatorTestRule;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.FakeDisplayTracker;
@@ -120,10 +125,13 @@
 @LargeTest
 @TestableLooper.RunWithLooper
 @RunWith(AndroidTestingRunner.class)
+@RequiresFlagsDisabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER)
 public class WindowMagnificationControllerTest extends SysuiTestCase {
 
     @Rule
     public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     private static final int LAYOUT_CHANGE_TIMEOUT_MS = 5000;
     @Mock
@@ -159,6 +167,7 @@
     private View mSpyView;
     private View.OnTouchListener mTouchListener;
     private MotionEventHelper mMotionEventHelper = new MotionEventHelper();
+    private KosmosJavaAdapter mKosmos;
 
     /**
      *  return whether window magnification is supported for current test context.
@@ -170,6 +179,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mKosmos = new KosmosJavaAdapter(this);
         mContext = Mockito.spy(getContext());
         mHandler = new FakeHandler(TestableLooper.get(this).getLooper());
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -185,7 +195,7 @@
             return null;
         }).when(mSfVsyncFrameProvider).postFrameCallback(
                 any(FrameCallback.class));
-        mSysUiState = new SysUiState(mDisplayTracker);
+        mSysUiState = new SysUiState(mDisplayTracker, mKosmos.getSceneContainerPlugin());
         mSysUiState.addCallback(Mockito.mock(SysUiState.SysUiStateCallback.class));
         when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).then(
                 returnsSecondArg());
@@ -213,13 +223,14 @@
                         mContext,
                         mHandler,
                         mWindowMagnificationAnimationController,
-                        mSfVsyncFrameProvider,
                         mMirrorWindowControl,
                         mTransaction,
                         mWindowMagnifierCallback,
                         mSysUiState,
-                        () -> mWindowSessionSpy,
-                        mSecureSettings);
+                        mSecureSettings,
+                        /* scvhSupplier= */ () -> null,
+                        mSfVsyncFrameProvider,
+                        /* globalWindowSessionSupplier= */ () -> mWindowSessionSpy);
 
         verify(mMirrorWindowControl).setWindowDelegate(
                 any(MirrorWindowControl.MirrorWindowDelegate.class));
@@ -267,7 +278,7 @@
         mInstrumentation.runOnMainSync(
                 () -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                         Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
-                /* magnificationFrameOffsetRatioY= */ 0, null));
+                        /* magnificationFrameOffsetRatioY= */ 0, null));
 
         // Waits for the surface created
         verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onSourceBoundsChanged(
@@ -1412,7 +1423,7 @@
     }
 
     private MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
-                                          float y) {
+            float y) {
         return mMotionEventHelper.obtainMotionEvent(downTime, eventTime, action, x, y);
     }
 
@@ -1471,4 +1482,4 @@
             });
         }
     }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java
new file mode 100644
index 0000000..66fb63b6c3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java
@@ -0,0 +1,1502 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.accessibility;
+
+import static android.content.pm.PackageManager.FEATURE_WINDOW_MAGNIFICATION;
+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 android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.WindowInsets.Type.systemGestures;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.hasItems;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalAnswers.returnsSecondArg;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.animation.ValueAnimator;
+import android.annotation.IdRes;
+import android.annotation.Nullable;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
+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.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.text.TextUtils;
+import android.util.Size;
+import android.view.AttachedSurfaceControl;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IRemoteMagnificationAnimationCallback;
+import android.widget.FrameLayout;
+
+import androidx.test.InstrumentationRegistry;
+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;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.res.R;
+import com.android.systemui.settings.FakeDisplayTracker;
+import com.android.systemui.util.leak.ReferenceTestUtils;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.utils.os.FakeHandler;
+
+import com.google.common.util.concurrent.AtomicDouble;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+@LargeTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+@RequiresFlagsEnabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER)
+public class WindowMagnificationControllerWindowlessMagnifierTest extends SysuiTestCase {
+
+    @Rule
+    public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    private static final int LAYOUT_CHANGE_TIMEOUT_MS = 5000;
+    @Mock
+    private MirrorWindowControl mMirrorWindowControl;
+    @Mock
+    private WindowMagnifierCallback mWindowMagnifierCallback;
+    @Mock
+    IRemoteMagnificationAnimationCallback mAnimationCallback;
+    @Mock
+    IRemoteMagnificationAnimationCallback mAnimationCallback2;
+
+    private SurfaceControl.Transaction mTransaction;
+    @Mock
+    private SecureSettings mSecureSettings;
+
+    private long mWaitAnimationDuration;
+    private long mWaitBounceEffectDuration;
+
+    private Handler mHandler;
+    private TestableWindowManager mWindowManager;
+    private SysUiState mSysUiState;
+    private Resources mResources;
+    private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
+    private WindowMagnificationController mWindowMagnificationController;
+    private Instrumentation mInstrumentation;
+    private final ValueAnimator mValueAnimator = ValueAnimator.ofFloat(0, 1.0f).setDuration(0);
+    private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
+
+    private View mSpyView;
+    private View.OnTouchListener mTouchListener;
+
+    private MotionEventHelper mMotionEventHelper = new MotionEventHelper();
+
+    // This list contains all SurfaceControlViewHosts created during a given test. If the
+    // magnification window is recreated during a test, the list will contain more than a single
+    // element.
+    private List<SurfaceControlViewHost> mSurfaceControlViewHosts = new ArrayList<>();
+    // The most recently created SurfaceControlViewHost.
+    private SurfaceControlViewHost mSurfaceControlViewHost;
+    private KosmosJavaAdapter mKosmos;
+
+    /**
+     *  return whether window magnification is supported for current test context.
+     */
+    private boolean isWindowModeSupported() {
+        return getContext().getPackageManager().hasSystemFeature(FEATURE_WINDOW_MAGNIFICATION);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mKosmos = new KosmosJavaAdapter(this);
+        mContext = Mockito.spy(getContext());
+        mHandler = new FakeHandler(TestableLooper.get(this).getLooper());
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        mWindowManager = spy(new TestableWindowManager(wm));
+
+        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+        mSysUiState = new SysUiState(mDisplayTracker, mKosmos.getSceneContainerPlugin());
+        mSysUiState.addCallback(Mockito.mock(SysUiState.SysUiStateCallback.class));
+        when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).then(
+                returnsSecondArg());
+        when(mSecureSettings.getFloatForUser(anyString(), anyFloat(), anyInt())).then(
+                returnsSecondArg());
+
+        mResources = getContext().getOrCreateTestableResources().getResources();
+        // prevent the config orientation from undefined, which may cause config.diff method
+        // neglecting the orientation update.
+        if (mResources.getConfiguration().orientation == ORIENTATION_UNDEFINED) {
+            mResources.getConfiguration().orientation = ORIENTATION_PORTRAIT;
+        }
+
+        // Using the animation duration in WindowMagnificationAnimationController for testing.
+        mWaitAnimationDuration = mResources.getInteger(
+                com.android.internal.R.integer.config_longAnimTime);
+        // Using the bounce effect duration in WindowMagnificationController for testing.
+        mWaitBounceEffectDuration = mResources.getInteger(
+                com.android.internal.R.integer.config_shortAnimTime);
+
+        mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
+                mContext, mValueAnimator);
+        Supplier<SurfaceControlViewHost> scvhSupplier = () -> {
+            mSurfaceControlViewHost = spy(new SurfaceControlViewHost(
+                    mContext, mContext.getDisplay(), new Binder(), "WindowMagnification"));
+            ViewRootImpl viewRoot = mock(ViewRootImpl.class);
+            when(mSurfaceControlViewHost.getRootSurfaceControl()).thenReturn(viewRoot);
+            mSurfaceControlViewHosts.add(mSurfaceControlViewHost);
+            return mSurfaceControlViewHost;
+        };
+        mTransaction = spy(new SurfaceControl.Transaction());
+        mWindowMagnificationController =
+                new WindowMagnificationController(
+                        mContext,
+                        mHandler,
+                        mWindowMagnificationAnimationController,
+                        mMirrorWindowControl,
+                        mTransaction,
+                        mWindowMagnifierCallback,
+                        mSysUiState,
+                        mSecureSettings,
+                        scvhSupplier,
+                        /* sfVsyncFrameProvider= */ null,
+                        /* globalWindowSessionSupplier= */ null);
+
+        verify(mMirrorWindowControl).setWindowDelegate(
+                any(MirrorWindowControl.MirrorWindowDelegate.class));
+        mSpyView = Mockito.spy(new View(mContext));
+        doAnswer((invocation) -> {
+            mTouchListener = invocation.getArgument(0);
+            return null;
+        }).when(mSpyView).setOnTouchListener(
+                any(View.OnTouchListener.class));
+
+        // skip test if window magnification is not supported to prevent fail results. (b/279820875)
+        Assume.assumeTrue(isWindowModeSupported());
+    }
+
+    @After
+    public void tearDown() {
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.deleteWindowMagnification());
+        mValueAnimator.cancel();
+    }
+
+    @Test
+    public void initWindowMagnificationController_checkAllowDiagonalScrollingWithSecureSettings() {
+        verify(mSecureSettings).getIntForUser(
+                eq(Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING),
+                /* def */ eq(1), /* userHandle= */ anyInt());
+        assertTrue(mWindowMagnificationController.isDiagonalScrollingEnabled());
+    }
+
+    @Test
+    public void enableWindowMagnification_showControlAndNotifyBoundsChanged() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        verify(mMirrorWindowControl).showControl();
+        verify(mWindowMagnifierCallback,
+                timeout(LAYOUT_CHANGE_TIMEOUT_MS).atLeastOnce()).onWindowMagnifierBoundsChanged(
+                eq(mContext.getDisplayId()), any(Rect.class));
+    }
+
+    @Test
+    public void enableWindowMagnification_notifySourceBoundsChanged() {
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                        Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
+                        /* magnificationFrameOffsetRatioY= */ 0, null));
+
+        // Waits for the surface created
+        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onSourceBoundsChanged(
+                (eq(mContext.getDisplayId())), any());
+    }
+
+    @Test
+    public void enableWindowMagnification_disabled_notifySourceBoundsChanged() {
+        enableWindowMagnification_notifySourceBoundsChanged();
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.deleteWindowMagnification(null));
+        Mockito.reset(mWindowMagnifierCallback);
+
+        enableWindowMagnification_notifySourceBoundsChanged();
+    }
+
+    @Test
+    public void enableWindowMagnification_withAnimation_schedulesFrame() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(2.0f, 10,
+                    10, /* magnificationFrameOffsetRatioX= */ 0,
+                    /* magnificationFrameOffsetRatioY= */ 0,
+                    Mockito.mock(IRemoteMagnificationAnimationCallback.class));
+        });
+        advanceTimeBy(LAYOUT_CHANGE_TIMEOUT_MS);
+
+        verify(mTransaction, atLeastOnce()).setGeometry(any(), any(), any(),
+                eq(Surface.ROTATION_0));
+    }
+
+    @Test
+    public void moveWindowMagnifier_enabled_notifySourceBoundsChanged() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                    Float.NaN, 0, 0, null);
+        });
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.moveWindowMagnifier(10, 10);
+        });
+
+        final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
+        verify(mWindowMagnifierCallback, atLeast(2)).onSourceBoundsChanged(
+                (eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
+        assertEquals(mWindowMagnificationController.getCenterX(),
+                sourceBoundsCaptor.getValue().exactCenterX(), 0);
+        assertEquals(mWindowMagnificationController.getCenterY(),
+                sourceBoundsCaptor.getValue().exactCenterY(), 0);
+    }
+
+    @Test
+    public void enableWindowMagnification_systemGestureExclusionRectsIsSet() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+        // Wait for Rects updated.
+        waitForIdleSync();
+
+        List<Rect> rects = mSurfaceControlViewHost.getView().getSystemGestureExclusionRects();
+        assertFalse(rects.isEmpty());
+    }
+
+    @Ignore("The default window size should be constrained after fixing b/288056772")
+    @Test
+    public void enableWindowMagnification_LargeScreen_windowSizeIsConstrained() {
+        final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10;
+        mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        final int halfScreenSize = screenSize / 2;
+        ViewGroup.LayoutParams params = mSurfaceControlViewHost.getView().getLayoutParams();
+        // The frame size should be the half of smaller value of window height/width unless it
+        //exceed the max frame size.
+        assertTrue(params.width < halfScreenSize);
+        assertTrue(params.height < halfScreenSize);
+    }
+
+    @Test
+    public void deleteWindowMagnification_destroyControlAndUnregisterComponentCallback() {
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                        Float.NaN,
+                        Float.NaN));
+
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.deleteWindowMagnification());
+
+        verify(mMirrorWindowControl).destroyControl();
+        verify(mContext).unregisterComponentCallbacks(mWindowMagnificationController);
+    }
+
+    @Test
+    public void deleteWindowMagnification_enableAtTheBottom_overlapFlagIsFalse() {
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
+        setSystemGestureInsets();
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    bounds.bottom);
+        });
+        ReferenceTestUtils.waitForCondition(this::hasMagnificationOverlapFlag);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.deleteWindowMagnification();
+        });
+
+        verify(mMirrorWindowControl).destroyControl();
+        assertFalse(hasMagnificationOverlapFlag());
+    }
+
+    @Test
+    public void deleteWindowMagnification_notifySourceBoundsChanged() {
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                        Float.NaN,
+                        Float.NaN));
+
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.deleteWindowMagnification());
+
+        // The first time is for notifying magnification enabled and the second time is for
+        // notifying magnification disabled.
+        verify(mWindowMagnifierCallback, times(2)).onSourceBoundsChanged(
+                (eq(mContext.getDisplayId())), any());
+    }
+
+    @Test
+    public void moveMagnifier_schedulesFrame() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        waitForIdleSync();
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.moveWindowMagnifier(100f, 100f));
+
+        verify(mTransaction, atLeastOnce()).setGeometry(any(), any(), any(),
+                eq(Surface.ROTATION_0));
+    }
+
+    @Test
+    public void moveWindowMagnifierToPositionWithAnimation_expectedValuesAndInvokeCallback()
+            throws RemoteException {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                    Float.NaN, 0, 0, null);
+        });
+
+        final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
+        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
+                .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
+        final float targetCenterX = sourceBoundsCaptor.getValue().exactCenterX() + 10;
+        final float targetCenterY = sourceBoundsCaptor.getValue().exactCenterY() + 10;
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.moveWindowMagnifierToPosition(
+                    targetCenterX, targetCenterY, mAnimationCallback);
+        });
+        advanceTimeBy(mWaitAnimationDuration);
+
+        verify(mAnimationCallback, times(1)).onResult(eq(true));
+        verify(mAnimationCallback, never()).onResult(eq(false));
+        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
+                .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
+        assertEquals(mWindowMagnificationController.getCenterX(),
+                sourceBoundsCaptor.getValue().exactCenterX(), 0);
+        assertEquals(mWindowMagnificationController.getCenterY(),
+                sourceBoundsCaptor.getValue().exactCenterY(), 0);
+        assertEquals(mWindowMagnificationController.getCenterX(), targetCenterX, 0);
+        assertEquals(mWindowMagnificationController.getCenterY(), targetCenterY, 0);
+    }
+
+    @Test
+    public void moveWindowMagnifierToPositionMultipleTimes_expectedValuesAndInvokeCallback()
+            throws RemoteException {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                    Float.NaN, 0, 0, null);
+        });
+
+        final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
+        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
+                .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
+        final float centerX = sourceBoundsCaptor.getValue().exactCenterX();
+        final float centerY = sourceBoundsCaptor.getValue().exactCenterY();
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.moveWindowMagnifierToPosition(
+                    centerX + 10, centerY + 10, mAnimationCallback);
+            mWindowMagnificationController.moveWindowMagnifierToPosition(
+                    centerX + 20, centerY + 20, mAnimationCallback);
+            mWindowMagnificationController.moveWindowMagnifierToPosition(
+                    centerX + 30, centerY + 30, mAnimationCallback);
+            mWindowMagnificationController.moveWindowMagnifierToPosition(
+                    centerX + 40, centerY + 40, mAnimationCallback2);
+        });
+        advanceTimeBy(mWaitAnimationDuration);
+
+        // only the last one callback will return true
+        verify(mAnimationCallback2).onResult(eq(true));
+        // the others will return false
+        verify(mAnimationCallback, times(3)).onResult(eq(false));
+        verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
+                .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
+        assertEquals(mWindowMagnificationController.getCenterX(),
+                sourceBoundsCaptor.getValue().exactCenterX(), 0);
+        assertEquals(mWindowMagnificationController.getCenterY(),
+                sourceBoundsCaptor.getValue().exactCenterY(), 0);
+        assertEquals(mWindowMagnificationController.getCenterX(), centerX + 40, 0);
+        assertEquals(mWindowMagnificationController.getCenterY(), centerY + 40, 0);
+    }
+
+    @Test
+    public void setScale_enabled_expectedValueAndUpdateStateDescription() {
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(2.0f,
+                        Float.NaN, Float.NaN));
+
+        mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f));
+
+        assertEquals(3.0f, mWindowMagnificationController.getScale(), 0);
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        assertNotNull(mirrorView);
+        assertThat(mirrorView.getStateDescription().toString(), containsString("300"));
+    }
+
+    @Test
+    public void onConfigurationChanged_disabled_withoutException() {
+        Display display = Mockito.spy(mContext.getDisplay());
+        when(display.getRotation()).thenReturn(Surface.ROTATION_90);
+        when(mContext.getDisplay()).thenReturn(display);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE);
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
+        });
+    }
+
+    @Test
+    public void onOrientationChanged_enabled_updateDisplayRotationAndCenterStayAtSamePosition() {
+        final int newRotation = simulateRotateTheDevice();
+        final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
+        final float center = Math.min(windowBounds.exactCenterX(), windowBounds.exactCenterY());
+        final float displayWidth = windowBounds.width();
+        final PointF magnifiedCenter = new PointF(center, center + 5f);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                    magnifiedCenter.x, magnifiedCenter.y);
+            // Get the center again in case the center we set is out of screen.
+            magnifiedCenter.set(mWindowMagnificationController.getCenterX(),
+                    mWindowMagnificationController.getCenterY());
+        });
+        // Rotate the window clockwise 90 degree.
+        windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
+                windowBounds.right);
+        mWindowManager.setWindowBounds(windowBounds);
+
+        mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.onConfigurationChanged(
+                ActivityInfo.CONFIG_ORIENTATION));
+
+        assertEquals(newRotation, mWindowMagnificationController.mRotation);
+        final PointF expectedCenter = new PointF(magnifiedCenter.y,
+                displayWidth - magnifiedCenter.x);
+        final PointF actualCenter = new PointF(mWindowMagnificationController.getCenterX(),
+                mWindowMagnificationController.getCenterY());
+        assertEquals(expectedCenter, actualCenter);
+    }
+
+    @Test
+    public void onOrientationChanged_disabled_updateDisplayRotation() {
+        final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
+        // Rotate the window clockwise 90 degree.
+        windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
+                windowBounds.right);
+        mWindowManager.setWindowBounds(windowBounds);
+        final int newRotation = simulateRotateTheDevice();
+
+        mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.onConfigurationChanged(
+                ActivityInfo.CONFIG_ORIENTATION));
+
+        assertEquals(newRotation, mWindowMagnificationController.mRotation);
+    }
+
+    @Test
+    public void onScreenSizeAndDensityChanged_enabledAtTheCenterOfScreen_keepSameWindowSizeRatio() {
+        // The default position is at the center of the screen.
+        final float expectedRatio = 0.5f;
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        // Screen size and density change
+        mContext.getResources().getConfiguration().smallestScreenWidthDp =
+                mContext.getResources().getConfiguration().smallestScreenWidthDp * 2;
+        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);
+        });
+
+        // The ratio of center to window size should be the same.
+        assertEquals(expectedRatio,
+                mWindowMagnificationController.getCenterX() / testWindowBounds.width(),
+                0);
+        assertEquals(expectedRatio,
+                mWindowMagnificationController.getCenterY() / testWindowBounds.height(),
+                0);
+    }
+
+    @Test
+    public void onScreenChangedToSavedDensity_enabled_restoreSavedMagnifierWindow() {
+        mContext.getResources().getConfiguration().smallestScreenWidthDp =
+                mContext.getResources().getConfiguration().smallestScreenWidthDp * 2;
+        int windowFrameSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        mWindowMagnificationController.mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(
+                new Size(windowFrameSize, windowFrameSize));
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        ViewGroup.LayoutParams params = mSurfaceControlViewHost.getView().getLayoutParams();
+        assertTrue(params.width == windowFrameSize);
+        assertTrue(params.height == windowFrameSize);
+    }
+
+    @Test
+    public void screenSizeIsChangedToLarge_enabled_defaultWindowSize() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+        final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10;
+        // Screen size and density change
+        mContext.getResources().getConfiguration().smallestScreenWidthDp =
+                mContext.getResources().getConfiguration().smallestScreenWidthDp * 2;
+        mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
+        });
+
+        final int defaultWindowSize =
+                mWindowMagnificationController.getMagnificationWindowSizeFromIndex(
+                        WindowMagnificationSettings.MagnificationSize.MEDIUM);
+        ViewGroup.LayoutParams params = mSurfaceControlViewHost.getView().getLayoutParams();
+
+        assertTrue(params.width == defaultWindowSize);
+        assertTrue(params.height == defaultWindowSize);
+    }
+
+    @Test
+    public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            Mockito.reset(mWindowManager);
+            Mockito.reset(mMirrorWindowControl);
+        });
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+        });
+
+        verify(mResources, atLeastOnce()).getDimensionPixelSize(anyInt());
+        verify(mSurfaceControlViewHosts.get(0)).release();
+        verify(mMirrorWindowControl).destroyControl();
+        verify(mSurfaceControlViewHosts.get(1)).setView(any(), any());
+        verify(mMirrorWindowControl).showControl();
+    }
+
+    @Test
+    public void onDensityChanged_disabled_updateDimensions() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+        });
+
+        verify(mResources, atLeastOnce()).getDimensionPixelSize(anyInt());
+    }
+
+    @Test
+    public void initializeA11yNode_enabled_expectedValues() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
+                    Float.NaN);
+        });
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        assertNotNull(mirrorView);
+        final AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo();
+
+        mirrorView.onInitializeAccessibilityNodeInfo(nodeInfo);
+
+        assertNotNull(nodeInfo.getContentDescription());
+        assertThat(nodeInfo.getStateDescription().toString(), containsString("250"));
+        assertThat(nodeInfo.getActionList(),
+                hasItems(new AccessibilityAction(R.id.accessibility_action_zoom_in, null),
+                        new AccessibilityAction(R.id.accessibility_action_zoom_out, null),
+                        new AccessibilityAction(R.id.accessibility_action_move_right, null),
+                        new AccessibilityAction(R.id.accessibility_action_move_left, null),
+                        new AccessibilityAction(R.id.accessibility_action_move_down, null),
+                        new AccessibilityAction(R.id.accessibility_action_move_up, null)));
+    }
+
+    @Test
+    public void performA11yActions_visible_expectedResults() {
+        final int displayId = mContext.getDisplayId();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(1.5f, Float.NaN,
+                    Float.NaN);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        assertTrue(
+                mirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_out, null));
+        // Minimum scale is 1.0.
+        verify(mWindowMagnifierCallback).onPerformScaleAction(
+                eq(displayId), /* scale= */ eq(1.0f), /* updatePersistence= */ eq(true));
+
+        assertTrue(mirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_in, null));
+        verify(mWindowMagnifierCallback).onPerformScaleAction(
+                eq(displayId), /* scale= */ eq(2.5f), /* updatePersistence= */ eq(true));
+
+        // TODO: Verify the final state when the mirror surface is visible.
+        assertTrue(mirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null));
+        assertTrue(
+                mirrorView.performAccessibilityAction(R.id.accessibility_action_move_down, null));
+        assertTrue(
+                mirrorView.performAccessibilityAction(R.id.accessibility_action_move_right, null));
+        assertTrue(
+                mirrorView.performAccessibilityAction(R.id.accessibility_action_move_left, null));
+        verify(mWindowMagnifierCallback, times(4)).onMove(eq(displayId));
+
+        assertTrue(mirrorView.performAccessibilityAction(
+                AccessibilityAction.ACTION_CLICK.getId(), null));
+        verify(mWindowMagnifierCallback).onClickSettingsButton(eq(displayId));
+    }
+
+    @Test
+    public void performA11yActions_visible_notifyAccessibilityActionPerformed() {
+        final int displayId = mContext.getDisplayId();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
+                    Float.NaN);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        mirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null);
+
+        verify(mWindowMagnifierCallback).onAccessibilityActionPerformed(eq(displayId));
+    }
+
+    @Test
+    public void windowMagnifierEditMode_performA11yClickAction_exitEditMode() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        View closeButton = getInternalView(R.id.close_button);
+        View bottomRightCorner = getInternalView(R.id.bottom_right_corner);
+        View bottomLeftCorner = getInternalView(R.id.bottom_left_corner);
+        View topRightCorner = getInternalView(R.id.top_right_corner);
+        View topLeftCorner = getInternalView(R.id.top_left_corner);
+
+        assertEquals(View.VISIBLE, closeButton.getVisibility());
+        assertEquals(View.VISIBLE, bottomRightCorner.getVisibility());
+        assertEquals(View.VISIBLE, bottomLeftCorner.getVisibility());
+        assertEquals(View.VISIBLE, topRightCorner.getVisibility());
+        assertEquals(View.VISIBLE, topLeftCorner.getVisibility());
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        mInstrumentation.runOnMainSync(() ->
+                mirrorView.performAccessibilityAction(AccessibilityAction.ACTION_CLICK.getId(),
+                        null));
+
+        assertEquals(View.GONE, closeButton.getVisibility());
+        assertEquals(View.GONE, bottomRightCorner.getVisibility());
+        assertEquals(View.GONE, bottomLeftCorner.getVisibility());
+        assertEquals(View.GONE, topRightCorner.getVisibility());
+        assertEquals(View.GONE, topLeftCorner.getVisibility());
+    }
+
+    @Test
+
+    public void windowWidthIsNotMax_performA11yActionIncreaseWidth_windowWidthIncreased() {
+        final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        final int startingWidth = (int) (windowBounds.width() * 0.8);
+        final int startingHeight = (int) (windowBounds.height() * 0.8);
+        final float changeWindowSizeAmount = mContext.getResources().getFraction(
+                R.fraction.magnification_resize_window_size_amount,
+                /* base= */ 1,
+                /* pbase= */ 1);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mirrorView.performAccessibilityAction(
+                            R.id.accessibility_action_increase_window_width, null);
+                    actualWindowHeight.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().height);
+                    actualWindowWidth.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().width);
+                });
+
+        final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+                R.dimen.magnification_mirror_surface_margin);
+        // Window width includes the magnifier frame and the margin. Increasing the window size
+        // will be increasing the amount of the frame size only.
+        int newWindowWidth =
+                (int) ((startingWidth - 2 * mirrorSurfaceMargin) * (1 + changeWindowSizeAmount))
+                        + 2 * mirrorSurfaceMargin;
+        assertEquals(newWindowWidth, actualWindowWidth.get());
+        assertEquals(startingHeight, actualWindowHeight.get());
+    }
+
+    @Test
+    public void windowHeightIsNotMax_performA11yActionIncreaseHeight_windowHeightIncreased() {
+        final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        final int startingWidth = (int) (windowBounds.width() * 0.8);
+        final int startingHeight = (int) (windowBounds.height() * 0.8);
+        final float changeWindowSizeAmount = mContext.getResources().getFraction(
+                R.fraction.magnification_resize_window_size_amount,
+                /* base= */ 1,
+                /* pbase= */ 1);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mirrorView.performAccessibilityAction(
+                            R.id.accessibility_action_increase_window_height, null);
+                    actualWindowHeight.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().height);
+                    actualWindowWidth.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().width);
+                });
+
+        final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+                R.dimen.magnification_mirror_surface_margin);
+        // Window height includes the magnifier frame and the margin. Increasing the window size
+        // will be increasing the amount of the frame size only.
+        int newWindowHeight =
+                (int) ((startingHeight - 2 * mirrorSurfaceMargin) * (1 + changeWindowSizeAmount))
+                        + 2 * mirrorSurfaceMargin;
+        assertEquals(startingWidth, actualWindowWidth.get());
+        assertEquals(newWindowHeight, actualWindowHeight.get());
+    }
+
+    @Test
+    public void windowWidthIsMax_noIncreaseWindowWidthA11yAction() {
+        final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        final int startingWidth = windowBounds.width();
+        final int startingHeight = windowBounds.height();
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        final AccessibilityNodeInfo accessibilityNodeInfo =
+                mirrorView.createAccessibilityNodeInfo();
+        assertFalse(accessibilityNodeInfo.getActionList().contains(
+                new AccessibilityAction(R.id.accessibility_action_increase_window_width, null)));
+    }
+
+    @Test
+    public void windowHeightIsMax_noIncreaseWindowHeightA11yAction() {
+        final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        final int startingWidth = windowBounds.width();
+        final int startingHeight = windowBounds.height();
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        final AccessibilityNodeInfo accessibilityNodeInfo =
+                mirrorView.createAccessibilityNodeInfo();
+        assertFalse(accessibilityNodeInfo.getActionList().contains(
+                new AccessibilityAction(R.id.accessibility_action_increase_window_height, null)));
+    }
+
+    @Test
+    public void windowWidthIsNotMin_performA11yActionDecreaseWidth_windowWidthDecreased() {
+        int mMinWindowSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        final int startingSize = (int) (mMinWindowSize * 1.1);
+        final float changeWindowSizeAmount = mContext.getResources().getFraction(
+                R.fraction.magnification_resize_window_size_amount,
+                /* base= */ 1,
+                /* pbase= */ 1);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mirrorView.performAccessibilityAction(
+                            R.id.accessibility_action_decrease_window_width, null);
+                    actualWindowHeight.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().height);
+                    actualWindowWidth.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().width);
+                });
+
+        final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+                R.dimen.magnification_mirror_surface_margin);
+        // Window width includes the magnifier frame and the margin. Decreasing the window size
+        // will be decreasing the amount of the frame size only.
+        int newWindowWidth =
+                (int) ((startingSize - 2 * mirrorSurfaceMargin) * (1 - changeWindowSizeAmount))
+                        + 2 * mirrorSurfaceMargin;
+        assertEquals(newWindowWidth, actualWindowWidth.get());
+        assertEquals(startingSize, actualWindowHeight.get());
+    }
+
+    @Test
+    public void windowHeightIsNotMin_performA11yActionDecreaseHeight_windowHeightDecreased() {
+        int mMinWindowSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        final int startingSize = (int) (mMinWindowSize * 1.1);
+        final float changeWindowSizeAmount = mContext.getResources().getFraction(
+                R.fraction.magnification_resize_window_size_amount,
+                /* base= */ 1,
+                /* pbase= */ 1);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mirrorView.performAccessibilityAction(
+                            R.id.accessibility_action_decrease_window_height, null);
+                    actualWindowHeight.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().height);
+                    actualWindowWidth.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().width);
+                });
+
+        final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+                R.dimen.magnification_mirror_surface_margin);
+        // Window height includes the magnifier frame and the margin. Decreasing the window size
+        // will be decreasing the amount of the frame size only.
+        int newWindowHeight =
+                (int) ((startingSize - 2 * mirrorSurfaceMargin) * (1 - changeWindowSizeAmount))
+                        + 2 * mirrorSurfaceMargin;
+        assertEquals(startingSize, actualWindowWidth.get());
+        assertEquals(newWindowHeight, actualWindowHeight.get());
+    }
+
+    @Test
+    public void windowWidthIsMin_noDecreaseWindowWidthA11yAction() {
+        int mMinWindowSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        final int startingSize = mMinWindowSize;
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        final AccessibilityNodeInfo accessibilityNodeInfo =
+                mirrorView.createAccessibilityNodeInfo();
+        assertFalse(accessibilityNodeInfo.getActionList().contains(
+                new AccessibilityAction(R.id.accessibility_action_decrease_window_width, null)));
+    }
+
+    @Test
+    public void windowHeightIsMin_noDecreaseWindowHeightA11yAction() {
+        int mMinWindowSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        final int startingSize = mMinWindowSize;
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+            mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+            mWindowMagnificationController.setEditMagnifierSizeMode(true);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        final AccessibilityNodeInfo accessibilityNodeInfo =
+                mirrorView.createAccessibilityNodeInfo();
+        assertFalse(accessibilityNodeInfo.getActionList().contains(
+                new AccessibilityAction(R.id.accessibility_action_decrease_window_height, null)));
+    }
+
+    @Test
+    public void enableWindowMagnification_hasA11yWindowTitle() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        assertEquals(getContext().getResources().getString(
+                com.android.internal.R.string.android_system_label), getAccessibilityWindowTitle());
+    }
+
+    @Test
+    public void enableWindowMagnificationWithScaleLessThanOne_enabled_disabled() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(0.9f, Float.NaN,
+                    Float.NaN);
+        });
+
+        assertEquals(Float.NaN, mWindowMagnificationController.getScale(), 0);
+    }
+
+    @Test
+    public void enableWindowMagnification_rotationIsChanged_updateRotationValue() {
+        // the config orientation should not be undefined, since it would cause config.diff
+        // returning 0 and thus the orientation changed would not be detected
+        assertNotEquals(ORIENTATION_UNDEFINED, mResources.getConfiguration().orientation);
+
+        final Configuration config = mResources.getConfiguration();
+        config.orientation = config.orientation == ORIENTATION_LANDSCAPE ? ORIENTATION_PORTRAIT
+                : ORIENTATION_LANDSCAPE;
+        final int newRotation = simulateRotateTheDevice();
+
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                        Float.NaN, Float.NaN));
+
+        assertEquals(newRotation, mWindowMagnificationController.mRotation);
+    }
+
+    @Test
+    public void enableWindowMagnification_registerComponentCallback() {
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                        Float.NaN,
+                        Float.NaN));
+
+        verify(mContext).registerComponentCallbacks(mWindowMagnificationController);
+    }
+
+    @Test
+    public void onLocaleChanged_enabled_updateA11yWindowTitle() {
+        final String newA11yWindowTitle = "new a11y window title";
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+        final TestableResources testableResources = getContext().getOrCreateTestableResources();
+        testableResources.addOverride(com.android.internal.R.string.android_system_label,
+                newA11yWindowTitle);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE);
+        });
+
+        assertTrue(TextUtils.equals(newA11yWindowTitle, getAccessibilityWindowTitle()));
+    }
+
+    @Ignore("it's flaky in presubmit but works in abtd, filter for now. b/305654925")
+    @Test
+    public void onSingleTap_enabled_scaleAnimates() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.onSingleTap(mSpyView);
+        });
+
+        final View mirrorView = mSurfaceControlViewHost.getView();
+
+        final AtomicDouble maxScaleX = new AtomicDouble();
+        advanceTimeBy(mWaitBounceEffectDuration, /* runnableOnEachRefresh= */ () -> {
+            // For some reason the fancy way doesn't compile...
+            // maxScaleX.getAndAccumulate(mirrorView.getScaleX(), Math::max);
+            final double oldMax = maxScaleX.get();
+            final double newMax = Math.max(mirrorView.getScaleX(), oldMax);
+            assertTrue(maxScaleX.compareAndSet(oldMax, newMax));
+        });
+
+        assertTrue(maxScaleX.get() > 1.0);
+    }
+
+    @Test
+    public void moveWindowMagnificationToTheBottom_enabledWithGestureInset_overlapFlagIsTrue() {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        setSystemGestureInsets();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.moveWindowMagnifier(0, bounds.height());
+        });
+
+        ReferenceTestUtils.waitForCondition(() -> hasMagnificationOverlapFlag());
+    }
+
+    @Test
+    public void moveWindowMagnificationToRightEdge_dragHandleMovesToLeftAndUpdatesTapExcludeRegion()
+            throws RemoteException {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        setSystemGestureInsets();
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                            Float.NaN, Float.NaN, Float.NaN);
+                });
+        // Wait for Region updated.
+        waitForIdleSync();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController.moveWindowMagnifier(bounds.width(), 0);
+                });
+        // Wait for Region updated.
+        waitForIdleSync();
+
+        AttachedSurfaceControl viewRoot = mSurfaceControlViewHost.getRootSurfaceControl();
+        // Verifying two times in: (1) enable window magnification (2) reposition drag handle
+        verify(viewRoot, times(2)).setTouchableRegion(any());
+
+        View dragButton = getInternalView(R.id.drag_handle);
+        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) dragButton.getLayoutParams();
+        assertEquals(Gravity.BOTTOM | Gravity.LEFT, params.gravity);
+    }
+
+    @Test
+    public void moveWindowMagnificationToLeftEdge_dragHandleMovesToRightAndUpdatesTapExcludeRegion()
+            throws RemoteException {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        setSystemGestureInsets();
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                            Float.NaN, Float.NaN, Float.NaN);
+                });
+        // Wait for Region updated.
+        waitForIdleSync();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController.moveWindowMagnifier(-bounds.width(), 0);
+                });
+        // Wait for Region updated.
+        waitForIdleSync();
+
+        AttachedSurfaceControl viewRoot = mSurfaceControlViewHost.getRootSurfaceControl();
+        // Verifying one times in: (1) enable window magnification
+        verify(viewRoot).setTouchableRegion(any());
+
+        View dragButton = getInternalView(R.id.drag_handle);
+        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) dragButton.getLayoutParams();
+        assertEquals(Gravity.BOTTOM | Gravity.RIGHT, params.gravity);
+    }
+
+    @Test
+    public void setMinimumWindowSize_enabled_expectedWindowSize() {
+        final int minimumWindowSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        final int  expectedWindowHeight = minimumWindowSize;
+        final int  expectedWindowWidth = minimumWindowSize;
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                        Float.NaN, Float.NaN));
+
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight);
+            actualWindowHeight.set(mSurfaceControlViewHost.getView().getLayoutParams().height);
+            actualWindowWidth.set(mSurfaceControlViewHost.getView().getLayoutParams().width);
+
+        });
+
+        assertEquals(expectedWindowHeight, actualWindowHeight.get());
+        assertEquals(expectedWindowWidth, actualWindowWidth.get());
+    }
+
+    @Test
+    public void setMinimumWindowSizeThenEnable_expectedWindowSize() {
+        final int minimumWindowSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        final int  expectedWindowHeight = minimumWindowSize;
+        final int  expectedWindowWidth = minimumWindowSize;
+
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight);
+            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                    Float.NaN, Float.NaN);
+            actualWindowHeight.set(mSurfaceControlViewHost.getView().getLayoutParams().height);
+            actualWindowWidth.set(mSurfaceControlViewHost.getView().getLayoutParams().width);
+        });
+
+        assertEquals(expectedWindowHeight, actualWindowHeight.get());
+        assertEquals(expectedWindowWidth, actualWindowWidth.get());
+    }
+
+    @Test
+    public void setWindowSizeLessThanMin_enabled_minimumWindowSize() {
+        final int minimumWindowSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                        Float.NaN, Float.NaN));
+
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.setWindowSize(minimumWindowSize - 10,
+                    minimumWindowSize - 10);
+            actualWindowHeight.set(mSurfaceControlViewHost.getView().getLayoutParams().height);
+            actualWindowWidth.set(mSurfaceControlViewHost.getView().getLayoutParams().width);
+        });
+
+        assertEquals(minimumWindowSize, actualWindowHeight.get());
+        assertEquals(minimumWindowSize, actualWindowWidth.get());
+    }
+
+    @Test
+    public void setWindowSizeLargerThanScreenSize_enabled_windowSizeIsScreenSize() {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                        Float.NaN, Float.NaN));
+
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.setWindowSize(bounds.width() + 10, bounds.height() + 10);
+            actualWindowHeight.set(mSurfaceControlViewHost.getView().getLayoutParams().height);
+            actualWindowWidth.set(mSurfaceControlViewHost.getView().getLayoutParams().width);
+        });
+
+        assertEquals(bounds.height(), actualWindowHeight.get());
+        assertEquals(bounds.width(), actualWindowWidth.get());
+    }
+
+    @Test
+    public void changeMagnificationSize_expectedWindowSize() {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+
+        final float magnificationScaleLarge = 2.5f;
+        final int initSize = Math.min(bounds.width(), bounds.height()) / 3;
+        final int magnificationSize = (int) (initSize * magnificationScaleLarge)
+                - (int) (initSize * magnificationScaleLarge) % 2;
+
+        final int expectedWindowHeight = magnificationSize;
+        final int expectedWindowWidth = magnificationSize;
+
+        mInstrumentation.runOnMainSync(
+                () ->
+                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                                Float.NaN, Float.NaN, Float.NaN));
+
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController.changeMagnificationSize(
+                            WindowMagnificationSettings.MagnificationSize.LARGE);
+                    actualWindowHeight.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().height);
+                    actualWindowWidth.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().width);
+                });
+
+        assertEquals(expectedWindowHeight, actualWindowHeight.get());
+        assertEquals(expectedWindowWidth, actualWindowWidth.get());
+    }
+
+    @Test
+    public void editModeOnDragCorner_resizesWindow() {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+
+        final int startingSize = (int) (bounds.width() / 2);
+
+        mInstrumentation.runOnMainSync(
+                () ->
+                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                                Float.NaN, Float.NaN, Float.NaN));
+
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+                    mWindowMagnificationController.setEditMagnifierSizeMode(true);
+                });
+
+        waitForIdleSync();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController
+                            .onDrag(getInternalView(R.id.bottom_right_corner), 2f, 1f);
+                    actualWindowHeight.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().height);
+                    actualWindowWidth.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().width);
+                });
+
+        assertEquals(startingSize + 1, actualWindowHeight.get());
+        assertEquals(startingSize + 2, actualWindowWidth.get());
+    }
+
+    @Test
+    public void editModeOnDragEdge_resizesWindowInOnlyOneDirection() {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+
+        final int startingSize = (int) (bounds.width() / 2f);
+
+        mInstrumentation.runOnMainSync(
+                () ->
+                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                                Float.NaN, Float.NaN, Float.NaN));
+
+        final AtomicInteger actualWindowHeight = new AtomicInteger();
+        final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+                    mWindowMagnificationController.setEditMagnifierSizeMode(true);
+                    mWindowMagnificationController
+                            .onDrag(getInternalView(R.id.bottom_handle), 2f, 1f);
+                    actualWindowHeight.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().height);
+                    actualWindowWidth.set(
+                            mSurfaceControlViewHost.getView().getLayoutParams().width);
+                });
+        assertEquals(startingSize + 1, actualWindowHeight.get());
+        assertEquals(startingSize, actualWindowWidth.get());
+    }
+
+    @Test
+    public void setWindowCenterOutOfScreen_enabled_magnificationCenterIsInsideTheScreen() {
+
+        final int minimumWindowSize = mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                        Float.NaN, Float.NaN));
+
+        final AtomicInteger magnificationCenterX = new AtomicInteger();
+        final AtomicInteger magnificationCenterY = new AtomicInteger();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.setWindowSizeAndCenter(minimumWindowSize,
+                    minimumWindowSize, bounds.right, bounds.bottom);
+            magnificationCenterX.set((int) mWindowMagnificationController.getCenterX());
+            magnificationCenterY.set((int) mWindowMagnificationController.getCenterY());
+        });
+
+        assertTrue(magnificationCenterX.get() < bounds.right);
+        assertTrue(magnificationCenterY.get() < bounds.bottom);
+    }
+
+    @Test
+    public void performSingleTap_DragHandle() {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                            1.5f, bounds.centerX(), bounds.centerY());
+                });
+        View dragButton = getInternalView(R.id.drag_handle);
+
+        // Perform a single-tap
+        final long downTime = SystemClock.uptimeMillis();
+        dragButton.dispatchTouchEvent(
+                obtainMotionEvent(downTime, 0, ACTION_DOWN, 100, 100));
+        dragButton.dispatchTouchEvent(
+                obtainMotionEvent(downTime, downTime, ACTION_UP, 100, 100));
+
+        verify(mSurfaceControlViewHost).setView(any(View.class), any());
+    }
+
+    private <T extends View> T getInternalView(@IdRes int idRes) {
+        View mirrorView = mSurfaceControlViewHost.getView();
+        T view = mirrorView.findViewById(idRes);
+        assertNotNull(view);
+        return view;
+    }
+
+    private MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
+            float y) {
+        return mMotionEventHelper.obtainMotionEvent(downTime, eventTime, action, x, y);
+    }
+
+    private CharSequence getAccessibilityWindowTitle() {
+        final View mirrorView = mSurfaceControlViewHost.getView();
+        if (mirrorView == null) {
+            return null;
+        }
+        WindowManager.LayoutParams layoutParams =
+                (WindowManager.LayoutParams) mirrorView.getLayoutParams();
+        return layoutParams.accessibilityTitle;
+    }
+
+    private boolean hasMagnificationOverlapFlag() {
+        return (mSysUiState.getFlags() & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0;
+    }
+
+    private void setSystemGestureInsets() {
+        final WindowInsets testInsets = new WindowInsets.Builder()
+                .setInsets(systemGestures(), Insets.of(0, 0, 0, 10))
+                .build();
+        mWindowManager.setWindowInsets(testInsets);
+    }
+
+    private int updateMirrorSurfaceMarginDimension() {
+        return mContext.getResources().getDimensionPixelSize(
+                R.dimen.magnification_mirror_surface_margin);
+    }
+
+    @Surface.Rotation
+    private int simulateRotateTheDevice() {
+        final Display display = Mockito.spy(mContext.getDisplay());
+        final int currentRotation = display.getRotation();
+        final int newRotation = (currentRotation + 1) % 4;
+        when(display.getRotation()).thenReturn(newRotation);
+        when(mContext.getDisplay()).thenReturn(display);
+        return newRotation;
+    }
+
+    // advance time based on the device frame refresh rate
+    private void advanceTimeBy(long timeDelta) {
+        advanceTimeBy(timeDelta, /* runnableOnEachRefresh= */ null);
+    }
+
+    // advance time based on the device frame refresh rate, and trigger runnable on each refresh
+    private void advanceTimeBy(long timeDelta, @Nullable Runnable runnableOnEachRefresh) {
+        final float frameRate = mContext.getDisplay().getRefreshRate();
+        final int timeSlot = (int) (1000 / frameRate);
+        int round = (int) Math.ceil((double) timeDelta / timeSlot);
+        for (; round >= 0; round--) {
+            mInstrumentation.runOnMainSync(() -> {
+                mAnimatorTestRule.advanceTimeBy(timeSlot);
+                if (runnableOnEachRefresh != null) {
+                    runnableOnEachRefresh.run();
+                }
+            });
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
index 9bcab57..9087816 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
@@ -16,10 +16,12 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
+import android.annotation.NonNull;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.WindowManager;
@@ -27,10 +29,12 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.utils.TestUtils;
 import com.android.systemui.util.settings.SecureSettings;
-import com.android.wm.shell.bubbles.DismissViewUtils;
 import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -46,6 +50,7 @@
 @TestableLooper.RunWithLooper
 public class DragToInteractAnimationControllerTest extends SysuiTestCase {
     private DragToInteractAnimationController mDragToInteractAnimationController;
+    private DragToInteractView mInteractView;
     private DismissView mDismissView;
 
     @Rule
@@ -57,29 +62,72 @@
     @Before
     public void setUp() throws Exception {
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
+        final SecureSettings mockSecureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                mock(SecureSettings.class));
+                mockSecureSettings);
         final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
                 stubWindowManager);
-        final MenuView stubMenuView = new MenuView(mContext, stubMenuViewModel,
-                stubMenuViewAppearance);
+        final MenuView stubMenuView = spy(new MenuView(mContext, stubMenuViewModel,
+                stubMenuViewAppearance, mockSecureSettings));
+        mInteractView = spy(new DragToInteractView(mContext));
         mDismissView = spy(new DismissView(mContext));
-        DismissViewUtils.setup(mDismissView);
-        mDragToInteractAnimationController = new DragToInteractAnimationController(
-                mDismissView, stubMenuView);
+
+        if (Flags.floatingMenuDragToEdit()) {
+            mDragToInteractAnimationController = new DragToInteractAnimationController(
+                    mInteractView, stubMenuView);
+        } else {
+            mDragToInteractAnimationController = new DragToInteractAnimationController(
+                    mDismissView, stubMenuView);
+        }
+
+        mDragToInteractAnimationController.setMagnetListener(new MagnetizedObject.MagnetListener() {
+            @Override
+            public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+
+            }
+
+            @Override
+            public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
+                    float velX, float velY, boolean wasFlungOut) {
+
+            }
+
+            @Override
+            public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+
+            }
+        });
     }
 
     @Test
-    public void showDismissView_success() {
-        mDragToInteractAnimationController.showDismissView(true);
+    @DisableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void showDismissView_success_old() {
+        mDragToInteractAnimationController.showInteractView(true);
 
         verify(mDismissView).show();
     }
 
     @Test
-    public void hideDismissView_success() {
-        mDragToInteractAnimationController.showDismissView(false);
+    @DisableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void hideDismissView_success_old() {
+        mDragToInteractAnimationController.showInteractView(false);
 
         verify(mDismissView).hide();
     }
+
+    @Test
+    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void showDismissView_success() {
+        mDragToInteractAnimationController.showInteractView(true);
+
+        verify(mInteractView).show();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void hideDismissView_success() {
+        mDragToInteractAnimationController.showInteractView(false);
+
+        verify(mInteractView).hide();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
index 215f93d..e0df1e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.accessibility.floatingmenu;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -42,6 +43,7 @@
 import com.android.systemui.Flags;
 import com.android.systemui.Prefs;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.utils.TestUtils;
 import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.After;
@@ -79,10 +81,12 @@
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
         final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
                 stubWindowManager);
+        final SecureSettings secureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                mock(SecureSettings.class));
+                secureSettings);
 
-        mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance));
+        mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance,
+                secureSettings));
         mViewPropertyAnimator = spy(mMenuView.animate());
         doReturn(mViewPropertyAnimator).when(mMenuView).animate();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
index 9c8de30..c2ed7d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
@@ -22,10 +22,13 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.graphics.Rect;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.WindowManager;
@@ -37,7 +40,9 @@
 import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.utils.TestUtils;
 import com.android.systemui.res.R;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -49,6 +54,8 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /** Tests for {@link MenuItemAccessibilityDelegate}. */
 @SmallTest
 @TestableLooper.RunWithLooper
@@ -59,17 +66,16 @@
 
     @Mock
     private AccessibilityManager mAccessibilityManager;
-    @Mock
-    private SecureSettings mSecureSettings;
-    @Mock
-    private DragToInteractAnimationController.DismissCallback mStubDismissCallback;
-
+    private final SecureSettings mSecureSettings = TestUtils.mockSecureSettings();
     private RecyclerView mStubListView;
     private MenuView mMenuView;
+    private MenuViewLayer mMenuViewLayer;
     private MenuItemAccessibilityDelegate mMenuItemAccessibilityDelegate;
     private MenuAnimationController mMenuAnimationController;
     private final Rect mDraggableBounds = new Rect(100, 200, 300, 400);
 
+    private final AtomicBoolean mEditReceived = new AtomicBoolean(false);
+
     @Before
     public void setUp() {
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
@@ -80,20 +86,28 @@
 
         final int halfScreenHeight =
                 stubWindowManager.getCurrentWindowMetrics().getBounds().height() / 2;
-        mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance));
+        mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance,
+                mSecureSettings));
         mMenuView.setTranslationY(halfScreenHeight);
 
+        mMenuViewLayer = spy(new MenuViewLayer(
+                mContext, stubWindowManager, mAccessibilityManager,
+                stubMenuViewModel, stubMenuViewAppearance, mMenuView,
+                mock(IAccessibilityFloatingMenu.class), mSecureSettings));
+
         doReturn(mDraggableBounds).when(mMenuView).getMenuDraggableBounds();
         mStubListView = new RecyclerView(mContext);
         mMenuAnimationController = spy(new MenuAnimationController(mMenuView,
                 stubMenuViewAppearance));
         mMenuItemAccessibilityDelegate =
                 new MenuItemAccessibilityDelegate(new RecyclerViewAccessibilityDelegate(
-                        mStubListView), mMenuAnimationController);
+                        mStubListView), mMenuAnimationController, mMenuViewLayer);
+        mEditReceived.set(false);
     }
 
     @Test
-    public void getAccessibilityActionList_matchSize() {
+    @DisableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void getAccessibilityActionList_matchSize_withoutEdit() {
         final AccessibilityNodeInfoCompat info =
                 new AccessibilityNodeInfoCompat(new AccessibilityNodeInfo());
 
@@ -103,6 +117,17 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void getAccessibilityActionList_matchSize() {
+        final AccessibilityNodeInfoCompat info =
+                new AccessibilityNodeInfoCompat(new AccessibilityNodeInfo());
+
+        mMenuItemAccessibilityDelegate.onInitializeAccessibilityNodeInfo(mStubListView, info);
+
+        assertThat(info.getActionList().size()).isEqualTo(7);
+    }
+
+    @Test
     public void performMoveTopLeftAction_matchPosition() {
         final boolean moveTopLeftAction =
                 mMenuItemAccessibilityDelegate.performAccessibilityAction(mStubListView,
@@ -169,13 +194,22 @@
 
     @Test
     public void performRemoveMenuAction_success() {
-        mMenuAnimationController.setDismissCallback(mStubDismissCallback);
         final boolean removeMenuAction =
                 mMenuItemAccessibilityDelegate.performAccessibilityAction(mStubListView,
                         R.id.action_remove_menu, null);
 
         assertThat(removeMenuAction).isTrue();
-        verify(mMenuAnimationController).removeMenu();
+        verify(mMenuViewLayer).dispatchAccessibilityAction(R.id.action_remove_menu);
+    }
+
+    @Test
+    public void performEditAction_success() {
+        final boolean editAction =
+                mMenuItemAccessibilityDelegate.performAccessibilityAction(mStubListView,
+                        R.id.action_edit, null);
+
+        assertThat(editAction).isTrue();
+        verify(mMenuViewLayer).dispatchAccessibilityAction(R.id.action_edit);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index e1522f5..9e8c6b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
+import static android.R.id.empty;
 import static android.view.View.OVER_SCROLL_NEVER;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -27,6 +28,8 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.MotionEvent;
@@ -38,10 +41,11 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.MotionEventHelper;
+import com.android.systemui.accessibility.utils.TestUtils;
 import com.android.systemui.util.settings.SecureSettings;
-import com.android.wm.shell.bubbles.DismissViewUtils;
 import com.android.wm.shell.common.bubbles.DismissView;
 
 import org.junit.After;
@@ -71,6 +75,7 @@
     private DragToInteractAnimationController mDragToInteractAnimationController;
     private RecyclerView mStubListView;
     private DismissView mDismissView;
+    private DragToInteractView mInteractView;
 
     @Rule
     public MockitoRule mockito = MockitoJUnit.rule();
@@ -81,19 +86,28 @@
     @Before
     public void setUp() throws Exception {
         final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+        final SecureSettings secureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                mock(SecureSettings.class));
+                secureSettings);
         final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
                 windowManager);
-        mStubMenuView = new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance);
+        mStubMenuView = new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance,
+                secureSettings);
         mStubMenuView.setTranslationX(0);
         mStubMenuView.setTranslationY(0);
         mMenuAnimationController = spy(new MenuAnimationController(
                 mStubMenuView, stubMenuViewAppearance));
+        mInteractView = spy(new DragToInteractView(mContext));
         mDismissView = spy(new DismissView(mContext));
-        DismissViewUtils.setup(mDismissView);
-        mDragToInteractAnimationController =
-                spy(new DragToInteractAnimationController(mDismissView, mStubMenuView));
+
+        if (Flags.floatingMenuDragToEdit()) {
+            mDragToInteractAnimationController = spy(new DragToInteractAnimationController(
+                    mInteractView, mStubMenuView));
+        } else {
+            mDragToInteractAnimationController = spy(new DragToInteractAnimationController(
+                    mDismissView, mStubMenuView));
+        }
+
         mTouchHandler = new MenuListViewTouchHandler(mMenuAnimationController,
                 mDragToInteractAnimationController);
         final AccessibilityTargetAdapter stubAdapter = new AccessibilityTargetAdapter(mStubTargets);
@@ -115,7 +129,7 @@
 
     @Test
     public void onActionMoveEvent_notConsumedEvent_shouldMoveToPosition() {
-        doReturn(false).when(mDragToInteractAnimationController).maybeConsumeMoveMotionEvent(
+        doReturn(empty).when(mDragToInteractAnimationController).maybeConsumeMoveMotionEvent(
                 any(MotionEvent.class));
         final int offset = 100;
         final MotionEvent stubDownEvent =
@@ -136,6 +150,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
     public void onActionMoveEvent_shouldShowDismissView() {
         final int offset = 100;
         final MotionEvent stubDownEvent =
@@ -154,6 +169,25 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void onActionMoveEvent_shouldShowInteractView() {
+        final int offset = 100;
+        final MotionEvent stubDownEvent =
+                mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0, /* eventTime= */ 1,
+                        MotionEvent.ACTION_DOWN, mStubMenuView.getTranslationX(),
+                        mStubMenuView.getTranslationY());
+        final MotionEvent stubMoveEvent =
+                mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0, /* eventTime= */ 3,
+                        MotionEvent.ACTION_MOVE, mStubMenuView.getTranslationX() + offset,
+                        mStubMenuView.getTranslationY() + offset);
+
+        mTouchHandler.onInterceptTouchEvent(mStubListView, stubDownEvent);
+        mTouchHandler.onInterceptTouchEvent(mStubListView, stubMoveEvent);
+
+        verify(mInteractView).show();
+    }
+
+    @Test
     public void dragAndDrop_shouldFlingMenuThenSpringToEdge() {
         final int offset = 100;
         final MotionEvent stubDownEvent =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index bc9a0a5..ca3eb3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -30,6 +30,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
@@ -68,10 +69,13 @@
 import androidx.dynamicanimation.animation.SpringAnimation;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
+import com.android.systemui.accessibility.utils.TestUtils;
+import com.android.systemui.res.R;
 import com.android.systemui.util.settings.SecureSettings;
 import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
 
@@ -81,6 +85,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
@@ -122,18 +127,17 @@
     private SysuiTestableContext mSpyContext = getContext();
     @Mock
     private IAccessibilityFloatingMenu mFloatingMenu;
-
-    @Mock
-    private SecureSettings mSecureSettings;
-
     @Mock
     private WindowManager mStubWindowManager;
-
     @Mock
     private AccessibilityManager mStubAccessibilityManager;
+    private final SecureSettings mSecureSettings = TestUtils.mockSecureSettings();
 
     private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
 
+    private final ArgumentMatcher<IntentFilter> mNotificationMatcher =
+            (arg) -> arg.hasAction(ACTION_UNDO) && arg.hasAction(ACTION_DELETE);
+
     @Before
     public void setUp() throws Exception {
         mSpyContext.addMockSystemService(Context.NOTIFICATION_SERVICE, mMockNotificationManager);
@@ -145,8 +149,16 @@
                 new WindowMetrics(mDisplayBounds, fakeDisplayInsets(), /* density = */ 0.0f));
         doReturn(mWindowMetrics).when(mStubWindowManager).getCurrentWindowMetrics();
 
-        mMenuViewLayer = new MenuViewLayer(mSpyContext, mStubWindowManager,
-                mStubAccessibilityManager, mFloatingMenu, mSecureSettings);
+        MenuViewModel menuViewModel = new MenuViewModel(
+                mSpyContext, mStubAccessibilityManager, mSecureSettings);
+        MenuViewAppearance menuViewAppearance = new MenuViewAppearance(
+                mSpyContext, mStubWindowManager);
+        mMenuView = spy(
+                new MenuView(mSpyContext, menuViewModel, menuViewAppearance, mSecureSettings));
+
+        mMenuViewLayer = spy(new MenuViewLayer(mSpyContext, mStubWindowManager,
+                mStubAccessibilityManager, menuViewModel, menuViewAppearance, mMenuView,
+                mFloatingMenu, mSecureSettings));
         mMenuView = (MenuView) mMenuViewLayer.getChildAt(LayerIndex.MENU_VIEW);
         mMenuAnimationController = mMenuView.getMenuAnimationController();
 
@@ -226,7 +238,7 @@
         final List<String> stubShortcutTargets = new ArrayList<>();
         stubShortcutTargets.add(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
         when(mStubAccessibilityManager.getAccessibilityShortcutTargets(
-                AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY)).thenReturn(stubShortcutTargets);
+                ShortcutConstants.UserShortcutType.HARDWARE)).thenReturn(stubShortcutTargets);
 
         mMenuViewLayer.mDismissMenuAction.run();
         final String value = Settings.Secure.getString(mSpyContext.getContentResolver(),
@@ -236,6 +248,27 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void onEditAction_gotoEditScreen_isCalled() {
+        mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
+        verify(mMenuView).gotoEditScreen();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE)
+    public void onDismissAction_hideMenuAndShowNotification() {
+        mMenuViewLayer.dispatchAccessibilityAction(R.id.action_remove_menu);
+        verify(mMenuViewLayer).hideMenuAndShowNotification();
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE)
+    public void onDismissAction_hideMenuAndShowMessage() {
+        mMenuViewLayer.dispatchAccessibilityAction(R.id.action_remove_menu);
+        verify(mMenuViewLayer).hideMenuAndShowMessage();
+    }
+
+    @Test
     public void showingImeInsetsChange_notOverlapOnIme_menuKeepOriginalPosition() {
         final float menuTop = STATUS_BAR_HEIGHT + 100;
         mMenuAnimationController.moveAndPersistPosition(new PointF(0, menuTop));
@@ -307,19 +340,13 @@
     @Test
     @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE)
     public void onReleasedInTarget_hideMenuAndShowNotificationWithExpectedActions() {
-        dragMenuThenReleasedInTarget();
+        dragMenuThenReleasedInTarget(R.id.action_remove_menu);
 
         verify(mMockNotificationManager).notify(
                 eq(SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN),
                 any(Notification.class));
-        ArgumentCaptor<IntentFilter> intentFilterCaptor = ArgumentCaptor.forClass(
-                IntentFilter.class);
         verify(mSpyContext).registerReceiver(
-                any(BroadcastReceiver.class),
-                intentFilterCaptor.capture(),
-                anyInt());
-        assertThat(intentFilterCaptor.getValue().matchAction(ACTION_UNDO)).isTrue();
-        assertThat(intentFilterCaptor.getValue().matchAction(ACTION_DELETE)).isTrue();
+                any(BroadcastReceiver.class), argThat(mNotificationMatcher), anyInt());
     }
 
     @Test
@@ -327,10 +354,10 @@
     public void receiveActionUndo_dismissNotificationAndMenuVisible() {
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass(
                 BroadcastReceiver.class);
-        dragMenuThenReleasedInTarget();
+        dragMenuThenReleasedInTarget(R.id.action_remove_menu);
 
         verify(mSpyContext).registerReceiver(broadcastReceiverCaptor.capture(),
-                any(IntentFilter.class), anyInt());
+                argThat(mNotificationMatcher), anyInt());
         broadcastReceiverCaptor.getValue().onReceive(mSpyContext, new Intent(ACTION_UNDO));
 
         verify(mSpyContext).unregisterReceiver(broadcastReceiverCaptor.getValue());
@@ -344,10 +371,10 @@
     public void receiveActionDelete_dismissNotificationAndHideMenu() {
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass(
                 BroadcastReceiver.class);
-        dragMenuThenReleasedInTarget();
+        dragMenuThenReleasedInTarget(R.id.action_remove_menu);
 
         verify(mSpyContext).registerReceiver(broadcastReceiverCaptor.capture(),
-                any(IntentFilter.class), anyInt());
+                argThat(mNotificationMatcher), anyInt());
         broadcastReceiverCaptor.getValue().onReceive(mSpyContext, new Intent(ACTION_DELETE));
 
         verify(mSpyContext).unregisterReceiver(broadcastReceiverCaptor.getValue());
@@ -423,10 +450,12 @@
                 });
     }
 
-    private void dragMenuThenReleasedInTarget() {
+    private void dragMenuThenReleasedInTarget(int id) {
         MagnetizedObject.MagnetListener magnetListener =
-                mMenuViewLayer.getDragToInteractAnimationController().getMagnetListener();
+                mMenuViewLayer.getDragToInteractAnimationController().getMagnetListener(id);
+        View view = mock(View.class);
+        when(view.getId()).thenReturn(id);
         magnetListener.onReleasedInTarget(
-                new MagnetizedObject.MagneticTarget(mock(View.class), 200));
+                new MagnetizedObject.MagneticTarget(view, 200));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index 8da6cf9..7c97f53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -17,15 +17,19 @@
 package com.android.systemui.accessibility.floatingmenu;
 
 import static android.app.UiModeManager.MODE_NIGHT_YES;
+
 import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
+
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.app.UiModeManager;
+import android.content.Intent;
 import android.graphics.Rect;
 import android.graphics.drawable.GradientDrawable;
 import android.platform.test.annotations.EnableFlags;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.WindowManager;
@@ -36,6 +40,8 @@
 import com.android.systemui.Flags;
 import com.android.systemui.Prefs;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.SysuiTestableContext;
+import com.android.systemui.accessibility.utils.TestUtils;
 import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.After;
@@ -65,17 +71,23 @@
     @Mock
     private AccessibilityManager mAccessibilityManager;
 
+    private SysuiTestableContext mSpyContext;
+
     @Before
     public void setUp() throws Exception {
         mUiModeManager = mContext.getSystemService(UiModeManager.class);
         mNightMode = mUiModeManager.getNightMode();
         mUiModeManager.setNightMode(MODE_NIGHT_YES);
+
+        mSpyContext = spy(mContext);
+        final SecureSettings secureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                mock(SecureSettings.class));
+                secureSettings);
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
-        mStubMenuViewAppearance = new MenuViewAppearance(mContext, stubWindowManager);
-        mMenuView = spy(new MenuView(mContext, stubMenuViewModel, mStubMenuViewAppearance));
-        mLastPosition = Prefs.getString(mContext,
+        mStubMenuViewAppearance = new MenuViewAppearance(mSpyContext, stubWindowManager);
+        mMenuView = spy(new MenuView(mSpyContext, stubMenuViewModel, mStubMenuViewAppearance,
+                secureSettings));
+        mLastPosition = Prefs.getString(mSpyContext,
                 Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, /* defaultValue= */ null);
     }
 
@@ -154,6 +166,25 @@
         assertThat(radiiAnimator.isStarted()).isTrue();
     }
 
+    @Test
+    public void getIntentForEditScreen_validate() {
+        Intent intent = mMenuView.getIntentForEditScreen();
+        String[] targets = intent.getBundleExtra(
+                ":settings:show_fragment_args").getStringArray("targets");
+
+        assertThat(intent.getAction()).isEqualTo(Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS);
+        assertThat(targets).asList().containsExactlyElementsIn(TestUtils.TEST_BUTTON_TARGETS);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
+    public void gotoEditScreen_sendsIntent() {
+        // Notably, this shouldn't crash the settings app,
+        // because the button target args are configured.
+        mMenuView.gotoEditScreen();
+        verify(mSpyContext).startActivity(any());
+    }
+
     private InstantInsetLayerDrawable getMenuViewInsetLayer() {
         return (InstantInsetLayerDrawable) mMenuView.getBackground();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/TestUtils.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/TestUtils.java
index 10c8caa..8399fa8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/TestUtils.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/TestUtils.java
@@ -16,11 +16,27 @@
 
 package com.android.systemui.accessibility.utils;
 
-import android.os.SystemClock;
+import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.util.Set;
+import java.util.StringJoiner;
 import java.util.function.BooleanSupplier;
 
 public class TestUtils {
+    private static final ComponentName TEST_COMPONENT_A = new ComponentName("pkg", "A");
+    private static final ComponentName TEST_COMPONENT_B = new ComponentName("pkg", "B");
+    public static final String[] TEST_BUTTON_TARGETS = {
+            TEST_COMPONENT_A.flattenToString(), TEST_COMPONENT_B.flattenToString()};
     public static long DEFAULT_CONDITION_DURATION = 5_000;
 
     /**
@@ -55,4 +71,28 @@
             SystemClock.sleep(sleepMs);
         }
     }
+
+    /**
+     * Returns a mock secure settings configured to return information needed for tests.
+     * Currently, this only includes button targets.
+     */
+    public static SecureSettings mockSecureSettings() {
+        SecureSettings secureSettings = mock(SecureSettings.class);
+
+        final String targets = getShortcutTargets(
+                Set.of(TEST_COMPONENT_A, TEST_COMPONENT_B));
+        when(secureSettings.getStringForUser(
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
+                UserHandle.USER_CURRENT)).thenReturn(targets);
+
+        return secureSettings;
+    }
+
+    private static String getShortcutTargets(Set<ComponentName> components) {
+        final StringJoiner stringJoiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
+        for (ComponentName target : components) {
+            stringJoiner.add(target.flattenToString());
+        }
+        return stringJoiner.toString();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index a47e288..7c03d78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -27,12 +27,13 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.keyguard.logging.KeyguardLogger
+import com.android.systemui.Flags
 import com.android.systemui.Flags.FLAG_LIGHT_REVEAL_MIGRATION
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
-import com.android.systemui.log.logcatLogBuffer
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.deviceentry.domain.interactor.AuthRippleInteractor
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -42,7 +43,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.leak.RotationUtils
 import com.android.systemui.util.mockito.any
-import javax.inject.Provider
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import org.junit.After
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
@@ -61,8 +62,10 @@
 import org.mockito.MockitoAnnotations
 import org.mockito.MockitoSession
 import org.mockito.quality.Strictness
+import javax.inject.Provider
 
 
+@ExperimentalCoroutinesApi
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 class AuthRippleControllerTest : SysuiTestCase() {
@@ -74,6 +77,7 @@
     @Mock private lateinit var configurationController: ConfigurationController
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
     @Mock private lateinit var authController: AuthController
+    @Mock private lateinit var authRippleInteractor: AuthRippleInteractor
     @Mock private lateinit var keyguardStateController: KeyguardStateController
     @Mock
     private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@@ -88,8 +92,6 @@
     @Mock
     private lateinit var statusBarStateController: StatusBarStateController
     @Mock
-    private lateinit var featureFlags: FeatureFlags
-    @Mock
     private lateinit var lightRevealScrim: LightRevealScrim
     @Mock
     private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal
@@ -103,6 +105,7 @@
 
     @Before
     fun setUp() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
         MockitoAnnotations.initMocks(this)
         staticMockSession = mockitoSession()
                 .mockStatic(RotationUtils::class.java)
@@ -128,6 +131,7 @@
             KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
             biometricUnlockController,
             lightRevealScrim,
+            authRippleInteractor,
             facePropertyRepository,
             rippleView,
         )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryHapticsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryHapticsInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
index 0dfdeca..bdf0e06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryHapticsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.deviceentry.data.repository
+package com.android.systemui.deviceentry.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -23,12 +23,13 @@
 import com.android.systemui.biometrics.shared.model.FingerprintSensorType
 import com.android.systemui.biometrics.shared.model.SensorStrength
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryHapticsInteractor
 import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus
 import com.android.systemui.keyevent.data.repository.fakeKeyEventRepository
 import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
 import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus
 import com.android.systemui.kosmos.testScope
@@ -158,9 +159,10 @@
         }
 
     private suspend fun enterDeviceFromBiometricUnlock() {
-        kosmos.fakeDeviceEntryRepository.enteringDeviceFromBiometricUnlock(
+        kosmos.fakeKeyguardRepository.setBiometricUnlockSource(
             BiometricUnlockSource.FINGERPRINT_SENSOR
         )
+        kosmos.fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
     }
 
     private fun fingerprintFailure() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt
new file mode 100644
index 0000000..ed80a86
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt
@@ -0,0 +1,98 @@
+package com.android.systemui.keyboard.stickykeys.data.repository
+
+import android.content.pm.UserInfo
+import android.hardware.input.InputManager
+import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS
+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.keyboard.stickykeys.StickyKeysLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class StickyKeysRepositoryImplTest : SysuiTestCase() {
+
+    private val dispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(dispatcher)
+    private val secureSettings = FakeSettings()
+    private val userRepository = Kosmos().fakeUserRepository
+    private lateinit var stickyKeysRepository: StickyKeysRepositoryImpl
+
+    @Before
+    fun setup() {
+        stickyKeysRepository = StickyKeysRepositoryImpl(
+            mock<InputManager>(),
+            dispatcher,
+            secureSettings,
+            userRepository,
+            mock<StickyKeysLogger>()
+        )
+        userRepository.setUserInfos(USER_INFOS)
+        setStickyKeySettingForUser(enabled = true, userInfo = SETTING_ENABLED_USER)
+        setStickyKeySettingForUser(enabled = false, userInfo = SETTING_DISABLED_USER)
+    }
+
+    @Test
+    fun settingEnabledEmitsValueForCurrentUser() {
+        testScope.runTest {
+            userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+
+            val enabled by collectLastValue(stickyKeysRepository.settingEnabled)
+
+            assertThat(enabled).isTrue()
+        }
+    }
+
+    @Test
+    fun settingEnabledEmitsNewValueWhenSettingChanges() {
+        testScope.runTest {
+            userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+            val enabled by collectValues(stickyKeysRepository.settingEnabled)
+            runCurrent()
+
+            setStickyKeySettingForUser(enabled = false, userInfo = SETTING_ENABLED_USER)
+
+            assertThat(enabled).containsExactly(true, false).inOrder()
+        }
+    }
+
+    @Test
+    fun settingEnabledEmitsValueForNewUserWhenUserChanges() {
+        testScope.runTest {
+            userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+            val enabled by collectLastValue(stickyKeysRepository.settingEnabled)
+            runCurrent()
+
+            userRepository.setSelectedUserInfo(SETTING_DISABLED_USER)
+
+            assertThat(enabled).isFalse()
+        }
+    }
+
+    private fun setStickyKeySettingForUser(enabled: Boolean, userInfo: UserInfo) {
+        val newValue = if (enabled) "1" else "0"
+        secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, userInfo.id)
+    }
+
+    private companion object {
+        val SETTING_ENABLED_USER = UserInfo(/* id= */ 0, "user1", /* flags= */ 0)
+        val SETTING_DISABLED_USER = UserInfo(/* id= */ 1, "user2", /* flags= */ 0)
+        val USER_INFOS = listOf(SETTING_ENABLED_USER, SETTING_DISABLED_USER)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
index 8a71368..6eebb6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
@@ -18,6 +18,7 @@
 
 import android.hardware.input.InputManager
 import android.hardware.input.StickyModifierState
+import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -31,8 +32,11 @@
 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL
 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META
 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.settings.FakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.StandardTestDispatcher
@@ -57,6 +61,8 @@
     private lateinit var viewModel: StickyKeysIndicatorViewModel
     private val inputManager = mock<InputManager>()
     private val keyboardRepository = FakeKeyboardRepository()
+    private val secureSettings = FakeSettings()
+    private val userRepository = Kosmos().fakeUserRepository
     private val captor =
         ArgumentCaptor.forClass(InputManager.StickyModifierStateListener::class.java)
 
@@ -65,8 +71,11 @@
         val stickyKeysRepository = StickyKeysRepositoryImpl(
             inputManager,
             dispatcher,
+            secureSettings,
+            userRepository,
             mock<StickyKeysLogger>()
         )
+        setStickyKeySetting(enabled = false)
         viewModel =
             StickyKeysIndicatorViewModel(
                 stickyKeysRepository = stickyKeysRepository,
@@ -76,15 +85,26 @@
     }
 
     @Test
-    fun startsListeningToStickyKeysOnlyWhenKeyboardIsConnected() {
+    fun doesntListenToStickyKeysOnlyWhenKeyboardIsConnected() {
         testScope.runTest {
             collectLastValue(viewModel.indicatorContent)
-            runCurrent()
-            verifyZeroInteractions(inputManager)
 
             keyboardRepository.setIsAnyKeyboardConnected(true)
             runCurrent()
 
+            verifyZeroInteractions(inputManager)
+        }
+    }
+
+    @Test
+    fun startsListeningToStickyKeysOnlyWhenKeyboardIsConnectedAndSettingIsOn() {
+        testScope.runTest {
+            collectLastValue(viewModel.indicatorContent)
+            keyboardRepository.setIsAnyKeyboardConnected(true)
+
+            setStickyKeySetting(enabled = true)
+            runCurrent()
+
             verify(inputManager)
                 .registerStickyModifierStateListener(
                     any(),
@@ -93,11 +113,31 @@
         }
     }
 
+    private fun setStickyKeySetting(enabled: Boolean) {
+        val newValue = if (enabled) "1" else "0"
+        val defaultUser = userRepository.getSelectedUserInfo().id
+        secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, defaultUser)
+    }
+
+    @Test
+    fun stopsListeningToStickyKeysWhenStickyKeySettingsIsTurnedOff() {
+        testScope.runTest {
+            collectLastValue(viewModel.indicatorContent)
+            setStickyKeysActive()
+            runCurrent()
+
+            setStickyKeySetting(enabled = false)
+            runCurrent()
+
+            verify(inputManager).unregisterStickyModifierStateListener(any())
+        }
+    }
+
     @Test
     fun stopsListeningToStickyKeysWhenKeyboardDisconnects() {
         testScope.runTest {
             collectLastValue(viewModel.indicatorContent)
-            keyboardRepository.setIsAnyKeyboardConnected(true)
+            setStickyKeysActive()
             runCurrent()
 
             keyboardRepository.setIsAnyKeyboardConnected(false)
@@ -111,7 +151,7 @@
     fun emitsStickyKeysListWhenStickyKeyIsPressed() {
         testScope.runTest {
             val stickyKeys by collectLastValue(viewModel.indicatorContent)
-            keyboardRepository.setIsAnyKeyboardConnected(true)
+            setStickyKeysActive()
 
             setStickyKeys(mapOf(ALT to false))
 
@@ -123,7 +163,7 @@
     fun emitsEmptyListWhenNoStickyKeysAreActive() {
         testScope.runTest {
             val stickyKeys by collectLastValue(viewModel.indicatorContent)
-            keyboardRepository.setIsAnyKeyboardConnected(true)
+            setStickyKeysActive()
 
             setStickyKeys(emptyMap())
 
@@ -135,7 +175,7 @@
     fun passesAllStickyKeysToDialog() {
         testScope.runTest {
             val stickyKeys by collectLastValue(viewModel.indicatorContent)
-            keyboardRepository.setIsAnyKeyboardConnected(true)
+            setStickyKeysActive()
 
             setStickyKeys(mapOf(
                 ALT to false,
@@ -154,7 +194,7 @@
     fun showsOnlyLockedStateIfKeyIsStickyAndLocked() {
         testScope.runTest {
             val stickyKeys by collectLastValue(viewModel.indicatorContent)
-            keyboardRepository.setIsAnyKeyboardConnected(true)
+            setStickyKeysActive()
 
             setStickyKeys(mapOf(
                 ALT to false,
@@ -168,7 +208,7 @@
     fun doesNotChangeOrderOfKeysIfTheyBecomeLocked() {
         testScope.runTest {
             val stickyKeys by collectLastValue(viewModel.indicatorContent)
-            keyboardRepository.setIsAnyKeyboardConnected(true)
+            setStickyKeysActive()
 
             setStickyKeys(mapOf(
                 META to false,
@@ -186,6 +226,11 @@
         }
     }
 
+    private fun setStickyKeysActive() {
+        keyboardRepository.setIsAnyKeyboardConnected(true)
+        setStickyKeySetting(enabled = true)
+    }
+
     private fun TestScope.setStickyKeys(keys: Map<ModifierKey, Boolean>) {
         runCurrent()
         verify(inputManager).registerStickyModifierStateListener(any(), captor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 8a3a434..14cae0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -25,6 +25,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER;
+import static com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR;
 import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
 import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
 import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
@@ -270,8 +271,8 @@
                 mSceneContainerFlags,
                 mKosmos::getCommunalInteractor);
         mFeatureFlags = new FakeFeatureFlags();
-        mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
         mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER);
+        mSetFlagsRule.disableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR);
 
         DejankUtils.setImmediate(true);
 
@@ -356,6 +357,7 @@
                 mock(FoldGracePeriodProvider.class);
         mViewMediator.mFoldGracePeriodProvider = mockedFoldGracePeriodProvider;
         when(mockedFoldGracePeriodProvider.isEnabled()).thenReturn(true);
+        when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
 
         // GIVEN keyguard is not enabled and isn't showing
         mViewMediator.onSystemReady();
@@ -374,12 +376,40 @@
 
     @Test
     @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    public void doNotShowKeyguard_deviceNotProvisioned() {
+        // GIVEN feature is enabled
+        final FoldGracePeriodProvider mockedFoldGracePeriodProvider =
+                mock(FoldGracePeriodProvider.class);
+        mViewMediator.mFoldGracePeriodProvider = mockedFoldGracePeriodProvider;
+        when(mockedFoldGracePeriodProvider.isEnabled()).thenReturn(true);
+
+        // GIVEN keyguard is not enabled and isn't showing
+        mViewMediator.onSystemReady();
+        mViewMediator.setKeyguardEnabled(false);
+        TestableLooper.get(this).processAllMessages();
+        captureKeyguardUpdateMonitorCallback();
+        assertFalse(mViewMediator.isShowingAndNotOccluded());
+
+        // WHEN device is NOT provisioned
+        when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(false);
+
+        // WHEN showKeyguard is requested
+        mViewMediator.showDismissibleKeyguard();
+
+        // THEN keyguard is NOT shown
+        TestableLooper.get(this).processAllMessages();
+        assertFalse(mViewMediator.isShowingAndNotOccluded());
+    }
+
+    @Test
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
     public void showKeyguardAfterKeyguardNotEnabled_featureNotEnabled() {
         // GIVEN feature is NOT enabled
         final FoldGracePeriodProvider mockedFoldGracePeriodProvider =
                 mock(FoldGracePeriodProvider.class);
         mViewMediator.mFoldGracePeriodProvider = mockedFoldGracePeriodProvider;
         when(mockedFoldGracePeriodProvider.isEnabled()).thenReturn(false);
+        when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
 
         // GIVEN keyguard is not enabled and isn't showing
         mViewMediator.onSystemReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 4f3a63d..e93ad0be3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -21,6 +21,7 @@
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
@@ -29,7 +30,6 @@
 import com.android.systemui.communal.shared.model.CommunalSceneKey
 import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
 import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
@@ -137,8 +137,8 @@
 
         whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
 
-        featureFlags = FakeFeatureFlags().apply { set(Flags.KEYGUARD_WM_STATE_REFACTOR, false) }
         mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
+        featureFlags = FakeFeatureFlags()
 
         keyguardInteractor = createKeyguardInteractor()
 
@@ -299,6 +299,10 @@
                     powerInteractor = powerInteractor,
                 )
                 .apply { start() }
+
+        mSetFlagsRule.disableFlags(
+            FLAG_KEYGUARD_WM_STATE_REFACTOR,
+        )
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index c864704..699284e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -39,6 +39,7 @@
 import com.android.systemui.statusbar.VibratorHelper
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -71,6 +72,7 @@
             FakeFeatureFlagsClassic().apply { set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) }
         underTest =
             DefaultDeviceEntrySection(
+                TestScope().backgroundScope,
                 keyguardUpdateMonitor,
                 authController,
                 windowManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
index 75994da..ad2ae8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
@@ -19,7 +19,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -65,7 +65,7 @@
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val shadeRepository = kosmos.shadeRepository
     private val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController
-    private val primaryBouncerInteractor = kosmos.primaryBouncerInteractor
+    private val primaryBouncerInteractor = kosmos.mockPrimaryBouncerInteractor
     private val underTest = kosmos.bouncerToGoneFlows
 
     @Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt
index f5a70f0..8e05410 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.FakeDisplayTracker
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -29,7 +30,13 @@
 @RunWith(JUnit4::class)
 class SysUiStateExtTest : SysuiTestCase() {
 
-    private val underTest = SysUiState(FakeDisplayTracker(context))
+    private val kosmos = testKosmos()
+
+    private val underTest =
+        SysUiState(
+            FakeDisplayTracker(context),
+            kosmos.sceneContainerPlugin,
+        )
 
     @Test
     fun updateFlags() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
index 1a93adc..f03f4f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
@@ -26,6 +26,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.settings.FakeDisplayTracker;
 
 import org.junit.Before;
@@ -42,13 +43,15 @@
     private static final int FLAG_4 = 1 << 3;
     private static final int DISPLAY_ID = DEFAULT_DISPLAY;
 
+    private KosmosJavaAdapter mKosmos;
     private SysUiState.SysUiStateCallback mCallback;
     private SysUiState mFlagsContainer;
 
     @Before
     public void setup() {
         FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext);
-        mFlagsContainer = new SysUiState(displayTracker);
+        mKosmos = new KosmosJavaAdapter(this);
+        mFlagsContainer = new SysUiState(displayTracker, mKosmos.getSceneContainerPlugin());
         mCallback = mock(SysUiState.SysUiStateCallback.class);
         mFlagsContainer.addCallback(mCallback);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
index 8d306cce..28d35ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -41,6 +41,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
@@ -56,6 +57,8 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import dagger.Lazy;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -65,8 +68,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
-
-import dagger.Lazy;
+import java.util.concurrent.Executor;
 
 /**
  * Tests for {@link NavBarHelper}.
@@ -123,6 +125,8 @@
             SYSUI_STATE_A11Y_BUTTON_CLICKABLE | SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
     private NavBarHelper mNavBarHelper;
 
+    private final Executor mSynchronousExecutor = runnable -> runnable.run();
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -140,7 +144,8 @@
                 mSystemActions, mOverviewProxyService, mAssistManagerLazy,
                 () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardStateController.class),
                 mNavigationModeController, mEdgeBackGestureHandlerFactory, mWm, mUserTracker,
-                mDisplayTracker, mNotificationShadeWindowController, mDumpManager, mCommandQueue);
+                mDisplayTracker, mNotificationShadeWindowController, mDumpManager, mCommandQueue,
+                mSynchronousExecutor);
 
     }
 
@@ -266,7 +271,8 @@
     @Test
     public void initNavBarHelper_buttonModeNavBar_a11yButtonClickableState() {
         when(mAccessibilityManager.getAccessibilityShortcutTargets(
-                AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets());
+                ShortcutConstants.UserShortcutType.SOFTWARE)).thenReturn(
+                createFakeShortcutTargets());
 
         mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
@@ -291,7 +297,8 @@
                 ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
 
         when(mAccessibilityManager.getAccessibilityShortcutTargets(
-                AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets());
+                ShortcutConstants.UserShortcutType.SOFTWARE)).thenReturn(
+                createFakeShortcutTargets());
         mAccessibilityServicesStateChangeListener.onAccessibilityServicesStateChanged(
                 mAccessibilityManager);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index ddceed6..db5bd9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -228,6 +228,8 @@
     @Rule
     public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
 
+    private final Executor mSynchronousExecutor = runnable -> runnable.run();
+
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -269,7 +271,7 @@
                     mEdgeBackGestureHandlerFactory, mock(IWindowManager.class),
                     mock(UserTracker.class), mock(DisplayTracker.class),
                     mNotificationShadeWindowController, mock(DumpManager.class),
-                    mock(CommandQueue.class)));
+                    mock(CommandQueue.class), mSynchronousExecutor));
             mNavigationBar = createNavBar(mContext);
             mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
         });
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
index f93d52b..aa54565 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
@@ -28,6 +28,7 @@
 import android.view.ViewConfiguration
 import android.view.WindowManager
 import androidx.test.filters.SmallTest
+import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.util.LatencyTracker
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.NavigationEdgeBackPlugin
@@ -40,8 +41,10 @@
 import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
+import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -59,12 +62,16 @@
     @Mock private lateinit var windowManager: WindowManager
     @Mock private lateinit var configurationController: ConfigurationController
     @Mock private lateinit var latencyTracker: LatencyTracker
+    @Mock private lateinit var interactionJankMonitor: InteractionJankMonitor
     @Mock private lateinit var layoutParams: WindowManager.LayoutParams
     @Mock private lateinit var backCallback: NavigationEdgeBackPlugin.BackCallback
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
+        `when`(interactionJankMonitor.begin(any(), anyInt())).thenReturn(true)
+        `when`(interactionJankMonitor.end(anyInt())).thenReturn(true)
+        `when`(interactionJankMonitor.cancel(anyInt())).thenReturn(true)
         mBackPanelController =
             BackPanelController(
                 context,
@@ -74,6 +81,7 @@
                 vibratorHelper,
                 configurationController,
                 latencyTracker,
+                interactionJankMonitor,
             )
         mBackPanelController.setLayoutParams(layoutParams)
         mBackPanelController.setBackCallback(backCallback)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
index 60eb3ae..40eccad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
@@ -37,7 +37,7 @@
         object : Consumer<Int> {
             var lastValue: Int? = null
 
-            override fun accept(keyCode: Int?) {
+            override fun accept(keyCode: Int) {
                 lastValue = keyCode
             }
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
new file mode 100644
index 0000000..e8aa8f0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.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.tileimpl
+
+import android.animation.AnimatorTestRule
+import android.content.Context
+import android.service.quicksettings.Tile
+import android.testing.AndroidTestingRunner
+import android.testing.UiThreadTest
+import android.view.ContextThemeWrapper
+import android.view.View
+import android.widget.ImageView
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.connectivity.WifiIcons
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.junit.Rule
+import org.junit.runner.RunWith
+
+/** Test for regression b/311121830 */
+@RunWith(AndroidTestingRunner::class)
+@UiThreadTest
+@SmallTest
+class QSIconViewImplTest_311121830 : SysuiTestCase() {
+
+    @get:Rule val animatorRule = AnimatorTestRule()
+
+    @Test
+    fun alwaysLastIcon() {
+        // Need to inflate with the correct theme so the colors can be retrieved and the animations
+        // are run
+        val iconView =
+            AnimateQSIconViewImpl(
+                ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
+            )
+
+        val initialState =
+            QSTile.State().apply {
+                state = Tile.STATE_INACTIVE
+                icon = QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_no_internet_available)
+            }
+        val firstState =
+            QSTile.State().apply {
+                state = Tile.STATE_ACTIVE
+                icon = QSTileImpl.ResourceIcon.get(WifiIcons.WIFI_NO_INTERNET_ICONS[4])
+            }
+        val secondState =
+            QSTile.State().apply {
+                state = Tile.STATE_ACTIVE
+                icon = QSTileImpl.ResourceIcon.get(WifiIcons.WIFI_FULL_ICONS[4])
+            }
+
+        // Start with the initial state
+        iconView.setIcon(initialState, /* allowAnimations= */ false)
+
+        // Set the first state to animate, and advance time to half the time of the animation
+        iconView.setIcon(firstState, /* allowAnimations= */ true)
+        animatorRule.advanceTimeBy(QSIconViewImpl.QS_ANIM_LENGTH / 2)
+
+        // Set the second state to animate (it shouldn't, because `State.state` is the same) and
+        // advance time to 2 animations length
+        iconView.setIcon(secondState, /* allowAnimations= */ true)
+        animatorRule.advanceTimeBy(QSIconViewImpl.QS_ANIM_LENGTH * 2)
+
+        assertThat(iconView.mLastIcon).isEqualTo(secondState.icon)
+    }
+
+    private class AnimateQSIconViewImpl(context: Context) : QSIconViewImpl(context) {
+        override fun createIcon(): View {
+            return object : ImageView(context) {
+                override fun isShown(): Boolean {
+                    return true
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index 70a48f5..10d6ebf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -17,16 +17,21 @@
 package com.android.systemui.recents
 
 import android.content.ComponentName
+import android.content.Context
 import android.content.pm.PackageManager
 import android.content.pm.ResolveInfo
 import android.os.PowerManager
+import android.os.Process;
+import android.os.UserHandle
 import android.testing.AndroidTestingRunner
 import android.testing.TestableContext
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
 import com.android.internal.app.AssistUtils
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FakeFeatureFlags
@@ -35,6 +40,7 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
 import com.android.systemui.model.SysUiState
+import com.android.systemui.model.sceneContainerPlugin
 import com.android.systemui.navigationbar.NavigationBarController
 import com.android.systemui.navigationbar.NavigationModeController
 import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP
@@ -50,6 +56,7 @@
 import com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_WAKING
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.testKosmos
 import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -66,10 +73,14 @@
 import org.mockito.Mock
 import org.mockito.Mockito.any
 import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.atLeast
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.intThat
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -79,11 +90,12 @@
 
     @Main private val executor: Executor = MoreExecutors.directExecutor()
 
+    private val kosmos = testKosmos()
     private lateinit var subject: OverviewProxyService
-    private val dumpManager = DumpManager()
+    @Mock private val dumpManager = DumpManager()
     private val displayTracker = FakeDisplayTracker(mContext)
     private val fakeSystemClock = FakeSystemClock()
-    private val sysUiState = SysUiState(displayTracker)
+    private val sysUiState = SysUiState(displayTracker, kosmos.sceneContainerPlugin)
     private val featureFlags = FakeFeatureFlags()
     private val wakefulnessLifecycle =
         WakefulnessLifecycle(mContext, null, fakeSystemClock, dumpManager)
@@ -109,6 +121,8 @@
     @Mock
     private lateinit var unfoldTransitionProgressForwarder:
         Optional<UnfoldTransitionProgressForwarder>
+    @Mock
+    private lateinit var broadcastDispatcher: BroadcastDispatcher
 
     @Before
     fun setUp() {
@@ -131,32 +145,11 @@
         whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
             .thenReturn(mock(ResolveInfo::class.java))
 
-        featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
-        subject =
-            OverviewProxyService(
-                context,
-                executor,
-                commandQueue,
-                shellInterface,
-                { navBarController },
-                { shadeViewController },
-                screenPinningRequest,
-                navModeController,
-                statusBarWinController,
-                sysUiState,
-                mock(),
-                userTracker,
-                wakefulnessLifecycle,
-                uiEventLogger,
-                displayTracker,
-                sysuiUnlockAnimationController,
-                inWindowLauncherUnlockAnimationManager,
-                assistUtils,
-                featureFlags,
-                FakeSceneContainerFlags(),
-                dumpManager,
-                unfoldTransitionProgressForwarder
-            )
+        mSetFlagsRule.disableFlags(
+            com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
+        )
+
+        subject = createOverviewProxyService(context)
     }
 
     @After
@@ -209,4 +202,66 @@
                 intThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_GOING_TO_SLEEP }
             )
     }
+
+    @Test
+    fun connectToOverviewService_primaryUser_expectBindService() {
+        val mockitoSession = ExtendedMockito.mockitoSession()
+                .spyStatic(Process::class.java)
+                .startMocking()
+        try {
+            `when`(Process.myUserHandle()).thenReturn(UserHandle.SYSTEM)
+            val spyContext = spy(context)
+            val ops = createOverviewProxyService(spyContext)
+            ops.startConnectionToCurrentUser()
+            verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(),
+                anyInt(), any())
+        } finally {
+            mockitoSession.finishMocking()
+        }
+    }
+
+    @Test
+    fun connectToOverviewService_nonPrimaryUser_expectNoBindService() {
+        val mockitoSession = ExtendedMockito.mockitoSession()
+                .spyStatic(Process::class.java)
+                .startMocking()
+        try {
+            `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345))
+            val spyContext = spy(context)
+            val ops = createOverviewProxyService(spyContext)
+            ops.startConnectionToCurrentUser()
+            verify(spyContext, times(0)).bindServiceAsUser(any(), any(),
+                anyInt(), any())
+        } finally {
+            mockitoSession.finishMocking()
+        }
+    }
+
+    private fun createOverviewProxyService(ctx: Context) : OverviewProxyService {
+        return OverviewProxyService(
+            ctx,
+            executor,
+            commandQueue,
+            shellInterface,
+            { navBarController },
+            { shadeViewController },
+            screenPinningRequest,
+            navModeController,
+            statusBarWinController,
+            sysUiState,
+            mock(),
+            userTracker,
+            wakefulnessLifecycle,
+            uiEventLogger,
+            displayTracker,
+            sysuiUnlockAnimationController,
+            inWindowLauncherUnlockAnimationManager,
+            assistUtils,
+            featureFlags,
+            FakeSceneContainerFlags(),
+            dumpManager,
+            unfoldTransitionProgressForwarder,
+            broadcastDispatcher
+        )
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index a2aed98..9ce77e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -28,10 +28,10 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.app.ActivityOptions.LaunchCookie;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.Intent;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -146,7 +146,7 @@
 
     @Test
     public void testLogStartPartialRecording() {
-        MediaProjectionCaptureTarget target = new MediaProjectionCaptureTarget(new Binder());
+        MediaProjectionCaptureTarget target = new MediaProjectionCaptureTarget(new LaunchCookie());
         Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false, target);
         mRecordingService.onStartCommand(startIntent, 0, 0);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 6681cee..22b05be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -514,7 +514,7 @@
         }
 
         whenever(mGlanceableHubContainerController.isEnabled()).thenReturn(false)
-        whenever(mGlanceableHubContainerController.enabledState())
+        whenever(mGlanceableHubContainerController.communalAvailable())
             .thenReturn(MutableStateFlow(false))
 
         val mockCommunalPlaceholder = mock(View::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index 58eec2e..4519ba6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -65,6 +65,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
 import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
 import com.android.systemui.util.settings.SecureSettings;
@@ -111,6 +112,7 @@
     @Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater();
     private final SectionStyleProvider mSectionStyleProvider = new SectionStyleProvider();
     @Mock private UserTracker mUserTracker;
+    @Mock private GroupMembershipManager mGroupMembershipManager;
 
     private NotifUiAdjustmentProvider mAdjustmentProvider;
 
@@ -127,7 +129,9 @@
                 mSecureSettings,
                 mLockscreenUserManager,
                 mSectionStyleProvider,
-                mUserTracker);
+                mUserTracker,
+                mGroupMembershipManager
+                );
         mEntry = getNotificationEntryBuilder().setParent(ROOT_ENTRY).build();
         mInflationError = new Exception(TEST_MESSAGE);
         mErrorManager = new NotifInflationErrorManager();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
index f9f8d8a..73c49c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
@@ -17,6 +17,8 @@
 
 import android.database.ContentObserver
 import android.os.Handler
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
@@ -28,6 +30,8 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
 import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
@@ -35,6 +39,8 @@
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.util.settings.SecureSettings
 import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -55,6 +61,7 @@
     private val uri = FakeSettings().getUriFor(SHOW_NOTIFICATION_SNOOZE)
     private val dirtyListener: Runnable = mock()
     private val userTracker: UserTracker = mock()
+    private val groupMembershipManager: GroupMembershipManager = mock()
 
     private val section = NotifSection(mock(), 0)
     private val entry = NotificationEntryBuilder()
@@ -69,7 +76,8 @@
         secureSettings,
         lockscreenUserManager,
         sectionStyleProvider,
-        userTracker
+        userTracker,
+        groupMembershipManager,
     )
 
     @Before
@@ -127,4 +135,42 @@
         assertThat(withSnoozing.isSnoozeEnabled).isTrue()
         assertThat(withSnoozing).isNotEqualTo(original)
     }
+
+    @Test
+    @EnableFlags(AsyncHybridViewInflation.FLAG_NAME)
+    fun changeIsChildInGroup_asyncHybirdFlagEnabled_needReInflation() {
+        // Given: an Entry that is not child in group
+        // AsyncHybridViewInflation flag is enabled
+        whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(false)
+        val oldAdjustment = adjustmentProvider.calculateAdjustment(entry)
+        assertThat(oldAdjustment.isChildInGroup).isFalse()
+
+        // When: the Entry becomes a group child
+        whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(true)
+        val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
+        assertThat(newAdjustment.isChildInGroup).isTrue()
+        assertThat(newAdjustment).isNotEqualTo(oldAdjustment)
+
+        // Then: need re-inflation
+        assertTrue(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
+    }
+
+    @Test
+    @DisableFlags(AsyncHybridViewInflation.FLAG_NAME)
+    fun changeIsChildInGroup_asyncHybirdFlagDisabled_noNeedForReInflation() {
+        // Given: an Entry that is not child in group
+        // AsyncHybridViewInflation flag is disabled
+        whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(false)
+        val oldAdjustment = adjustmentProvider.calculateAdjustment(entry)
+        assertThat(oldAdjustment.isChildInGroup).isFalse()
+
+        // When: the Entry becomes a group child
+        whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(true)
+        val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
+        assertThat(newAdjustment.isChildInGroup).isTrue()
+        assertThat(newAdjustment).isNotEqualTo(oldAdjustment)
+
+        // Then: need no re-inflation
+        assertFalse(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index b0996ad..a0d1075 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -88,6 +88,8 @@
     private Notification.Builder mBuilder;
     private ExpandableNotificationRow mRow;
 
+    private NotificationTestHelper mHelper;
+
     @Mock private NotifRemoteViewCache mCache;
     @Mock private ConversationNotificationProcessor mConversationNotificationProcessor;
     @Mock private InflatedSmartReplyState mInflatedSmartReplyState;
@@ -119,11 +121,11 @@
                 .setContentTitle("Title")
                 .setContentText("Text")
                 .setStyle(new Notification.BigTextStyle().bigText("big text"));
-        NotificationTestHelper helper = new NotificationTestHelper(
+        mHelper = new NotificationTestHelper(
                 mContext,
                 mDependency,
                 TestableLooper.get(this));
-        ExpandableNotificationRow row = helper.createRow(mBuilder.build());
+        ExpandableNotificationRow row = mHelper.createRow(mBuilder.build());
         mRow = spy(row);
         when(mNotifLayoutInflaterFactoryProvider.provide(any(), any()))
                 .thenReturn(mNotifLayoutInflaterFactory);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt
new file mode 100644
index 0000000..1c959af
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.systemui.statusbar.notification.row
+
+import android.app.Notification
+import android.app.Person
+import android.platform.test.annotations.EnableFlags
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE
+import com.android.systemui.statusbar.notification.row.SingleLineViewInflater.inflateSingleLineViewHolder
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
+import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineConversationViewBinder
+import com.android.systemui.util.mockito.mock
+import kotlin.test.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class SingleLineConversationViewBinderTest : SysuiTestCase() {
+    private lateinit var notificationBuilder: Notification.Builder
+    private lateinit var helper: NotificationTestHelper
+
+    @Before
+    fun setUp() {
+        allowTestableLooperAsMainThread()
+        helper = NotificationTestHelper(context, mDependency, TestableLooper.get(this))
+        notificationBuilder = Notification.Builder(context, CHANNEL_ID)
+        notificationBuilder
+            .setSmallIcon(R.drawable.ic_corp_icon)
+            .setContentTitle(CONTENT_TITLE)
+            .setContentText(CONTENT_TEXT)
+    }
+
+    @Test
+    @EnableFlags(AsyncHybridViewInflation.FLAG_NAME)
+    fun bindGroupConversationSingleLineView() {
+        // GIVEN a row with a group conversation notification
+        val user =
+            Person.Builder()
+                //                .setIcon(Icon.createWithResource(mContext,
+                // R.drawable.ic_account_circle))
+                .setName(USER_NAME)
+                .build()
+        val style =
+            Notification.MessagingStyle(user)
+                .addMessage(MESSAGE_TEXT, System.currentTimeMillis(), user)
+                .addMessage(
+                    "How about lunch?",
+                    System.currentTimeMillis(),
+                    Person.Builder().setName("user2").build()
+                )
+                .setGroupConversation(true)
+        notificationBuilder.setStyle(style).setShortcutId(SHORTCUT_ID)
+        val notification = notificationBuilder.build()
+        val row = helper.createRow(notification)
+
+        val viewHolder =
+            inflateSingleLineViewHolder(
+                isConversation = true,
+                reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE,
+                entry = row.entry,
+                context = context,
+                logger = mock()
+            )
+                as HybridConversationNotificationView
+        val viewModel =
+            SingleLineViewInflater.inflateSingleLineViewModel(
+                notification = notification,
+                messagingStyle = style,
+                builder = notificationBuilder,
+                systemUiContext = context,
+            )
+        // WHEN: binds the viewHolder
+        SingleLineConversationViewBinder.bind(
+            viewModel,
+            viewHolder,
+        )
+
+        // THEN: the single-line conversation view should be bind with view model's corresponding
+        // fields
+        assertEquals(viewModel.titleText, viewHolder.titleView.text)
+        assertEquals(viewModel.contentText, viewHolder.textView.text)
+        assertEquals(
+            viewModel.conversationData?.conversationSenderName,
+            viewHolder.conversationSenderNameView.text
+        )
+    }
+
+    private companion object {
+        const val CHANNEL_ID = "CHANNEL_ID"
+        const val CONTENT_TITLE = "CONTENT_TITLE"
+        const val CONTENT_TEXT = "CONTENT_TEXT"
+        const val USER_NAME = "USER_NAME"
+        const val MESSAGE_TEXT = "MESSAGE_TEXT"
+        const val SHORTCUT_ID = "Shortcut"
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
new file mode 100644
index 0000000..f0fc349
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.systemui.statusbar.notification.row
+
+import android.app.Notification
+import android.platform.test.annotations.EnableFlags
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE
+import com.android.systemui.statusbar.notification.row.SingleLineViewInflater.inflateSingleLineViewHolder
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
+import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder
+import com.android.systemui.util.mockito.mock
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class SingleLineViewBinderTest : SysuiTestCase() {
+    private lateinit var notificationBuilder: Notification.Builder
+    private lateinit var helper: NotificationTestHelper
+
+    @Before
+    fun setUp() {
+        allowTestableLooperAsMainThread()
+        helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+        notificationBuilder = Notification.Builder(mContext, CHANNEL_ID)
+        notificationBuilder
+            .setSmallIcon(R.drawable.ic_corp_icon)
+            .setContentTitle(CONTENT_TITLE)
+            .setContentText(CONTENT_TEXT)
+    }
+
+    @Test
+    @EnableFlags(AsyncHybridViewInflation.FLAG_NAME)
+    fun bindNonConversationSingleLineView() {
+        // GIVEN: a row with bigText style notification
+        val style = Notification.BigTextStyle().bigText(CONTENT_TEXT)
+        notificationBuilder.setStyle(style)
+        val notification = notificationBuilder.build()
+        val row: ExpandableNotificationRow = helper.createRow(notification)
+
+        val viewHolder =
+            inflateSingleLineViewHolder(
+                isConversation = false,
+                reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE,
+                entry = row.entry,
+                context = context,
+                logger = mock()
+            )
+        val viewModel =
+            SingleLineViewInflater.inflateSingleLineViewModel(
+                notification = notification,
+                messagingStyle = null,
+                builder = notificationBuilder,
+                systemUiContext = context,
+            )
+
+        // WHEN: binds the viewHolder
+        SingleLineViewBinder.bind(viewModel, viewHolder)
+
+        // THEN: the single-line view should be bind with viewModel's title and content text
+        Assert.assertEquals(viewModel.titleText, viewHolder?.titleView?.text)
+        Assert.assertEquals(viewModel.contentText, viewHolder?.textView?.text)
+    }
+
+    private companion object {
+        const val CHANNEL_ID = "CHANNEL_ID"
+        const val CONTENT_TITLE = "A Cool New Feature"
+        const val CONTENT_TEXT = "Checkout out new feature!"
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
new file mode 100644
index 0000000..b67153a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
@@ -0,0 +1,463 @@
+/*
+ * 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.systemui.statusbar.notification.row
+
+import android.app.Notification
+import android.app.Person
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.platform.test.annotations.EnableFlags
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.core.graphics.drawable.toBitmap
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ConversationAvatar
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.FacePile
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleIcon
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel
+import kotlin.test.assertEquals
+import kotlin.test.assertIs
+import kotlin.test.assertIsNot
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@EnableFlags(AsyncHybridViewInflation.FLAG_NAME)
+class SingleLineViewInflaterTest : SysuiTestCase() {
+    private lateinit var helper: NotificationTestHelper
+    // Non-group MessagingStyles only have firstSender
+    private lateinit var firstSender: Person
+    private lateinit var lastSender: Person
+    private lateinit var firstSenderIcon: Icon
+    private lateinit var lastSenderIcon: Icon
+    private var firstSenderIconDrawable: Drawable? = null
+    private var lastSenderIconDrawable: Drawable? = null
+    private val currentUser: Person? = null
+
+    private companion object {
+        const val FIRST_SENDER_NAME = "First Sender"
+        const val LAST_SENDER_NAME = "Second Sender"
+        const val LAST_MESSAGE = "How about lunch?"
+
+        const val CONVERSATION_TITLE = "The Sender Family"
+        const val CONTENT_TITLE = "A Cool Group"
+        const val CONTENT_TEXT = "This is an amazing group chat"
+
+        const val SHORTCUT_ID = "Shortcut"
+    }
+
+    @Before
+    fun setUp() {
+        helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+        firstSenderIcon = Icon.createWithBitmap(getBitmap(context, R.drawable.ic_person))
+        firstSenderIconDrawable = firstSenderIcon.loadDrawable(context)
+        lastSenderIcon =
+            Icon.createWithBitmap(
+                getBitmap(context, com.android.internal.R.drawable.ic_account_circle)
+            )
+        lastSenderIconDrawable = lastSenderIcon.loadDrawable(context)
+        firstSender = Person.Builder().setName(FIRST_SENDER_NAME).setIcon(firstSenderIcon).build()
+        lastSender = Person.Builder().setName(LAST_SENDER_NAME).setIcon(lastSenderIcon).build()
+    }
+
+    @Test
+    fun createViewModelForNonConversationSingleLineView() {
+        // Given: a non-conversation notification
+        val notificationType = NonMessaging()
+        val notification = getNotification(NonMessaging())
+
+        // When: inflate the SingleLineViewModel
+        val singleLineViewModel = notification.makeSingleLineViewModel(notificationType)
+
+        // Then: the inflated SingleLineViewModel should be as expected
+        // conversationData: null, because it's not a conversation notification
+        assertEquals(SingleLineViewModel(CONTENT_TITLE, CONTENT_TEXT, null), singleLineViewModel)
+    }
+
+    @Test
+    fun createViewModelForNonGroupConversationNotification() {
+        // Given: a non-group conversation notification
+        val notificationType = OneToOneConversation()
+        val notification = getNotification(notificationType)
+
+        // When: inflate the SingleLineViewModel
+        val singleLineViewModel = notification.makeSingleLineViewModel(notificationType)
+
+        // Then: the inflated SingleLineViewModel should be as expected
+        // titleText: Notification.ConversationTitle
+        // contentText: the last message text
+        // conversationSenderName: null, because it's not a group conversation
+        // conversationData.avatar: a single icon of the last sender
+        assertEquals(CONVERSATION_TITLE, singleLineViewModel.titleText)
+        assertEquals(LAST_MESSAGE, singleLineViewModel.contentText)
+        assertNull(
+            singleLineViewModel.conversationData?.conversationSenderName,
+            "Sender name should be null for one-on-one conversation"
+        )
+        assertTrue {
+            singleLineViewModel.conversationData
+                ?.avatar
+                ?.equalsTo(SingleIcon(firstSenderIcon.loadDrawable(context))) == true
+        }
+    }
+
+    @Test
+    fun createViewModelForNonGroupLegacyMessagingStyleNotification() {
+        // Given: a non-group legacy messaging style notification
+        val notificationType = LegacyMessaging()
+        val notification = getNotification(notificationType)
+
+        // When: inflate the SingleLineViewModel
+        val singleLineViewModel = notification.makeSingleLineViewModel(notificationType)
+
+        // Then: the inflated SingleLineViewModel should be as expected
+        // titleText: CONVERSATION_TITLE: SENDER_NAME
+        // contentText: the last message text
+        // conversationData: null, because it's not a conversation notification
+        assertEquals("$CONVERSATION_TITLE: $FIRST_SENDER_NAME", singleLineViewModel.titleText)
+        assertEquals(LAST_MESSAGE, singleLineViewModel.contentText)
+        assertNull(
+            singleLineViewModel.conversationData,
+            "conversationData should be null for legacy messaging conversation"
+        )
+    }
+
+    @Test
+    fun createViewModelForGroupLegacyMessagingStyleNotification() {
+        // Given: a non-group legacy messaging style notification
+        val notificationType = LegacyMessagingGroup()
+        val notification = getNotification(notificationType)
+
+        // When: inflate the SingleLineViewModel
+        val singleLineViewModel = notification.makeSingleLineViewModel(notificationType)
+
+        // Then: the inflated SingleLineViewModel should be as expected
+        // titleText: CONVERSATION_TITLE: LAST_SENDER_NAME
+        // contentText: the last message text
+        // conversationData: null, because it's not a conversation notification
+        assertEquals("$CONVERSATION_TITLE: $LAST_SENDER_NAME", singleLineViewModel.titleText)
+        assertEquals(LAST_MESSAGE, singleLineViewModel.contentText)
+        assertNull(
+            singleLineViewModel.conversationData,
+            "conversationData should be null for legacy messaging conversation"
+        )
+    }
+
+    @Test
+    fun createViewModelForNonGroupConversationNotificationWithShortcutIcon() {
+        // Given: a non-group conversation notification with a shortcut icon
+        val shortcutIcon =
+            Icon.createWithResource(context, com.android.internal.R.drawable.ic_account_circle)
+        val notificationType = OneToOneConversation(shortcutIcon = shortcutIcon)
+        val notification = getNotification(notificationType)
+
+        // When: inflate the SingleLineViewModel
+        val singleLineViewModel = notification.makeSingleLineViewModel(notificationType)
+
+        // Then: the inflated SingleLineViewModel should be expected
+        // titleText: Notification.ConversationTitle
+        // contentText: the last message text
+        // conversationSenderName: null, because it's not a group conversation
+        // conversationData.avatar: a single icon of the shortcut icon
+        assertEquals(CONVERSATION_TITLE, singleLineViewModel.titleText)
+        assertEquals(LAST_MESSAGE, singleLineViewModel.contentText)
+        assertNull(
+            singleLineViewModel.conversationData?.conversationSenderName,
+            "Sender name should be null for one-on-one conversation"
+        )
+        assertTrue {
+            singleLineViewModel.conversationData
+                ?.avatar
+                ?.equalsTo(SingleIcon(shortcutIcon.loadDrawable(context))) == true
+        }
+    }
+
+    @Test
+    fun createViewModelForGroupConversationNotificationWithLargeIcon() {
+        // Given: a group conversation notification with a large icon
+        val largeIcon =
+            Icon.createWithResource(context, com.android.internal.R.drawable.ic_account_circle)
+        val notificationType = GroupConversation(largeIcon = largeIcon)
+        val notification = getNotification(notificationType)
+
+        // When: inflate the SingleLineViewModel
+        val singleLineViewModel = notification.makeSingleLineViewModel(notificationType)
+
+        // Then: the inflated SingleLineViewModel should be expected
+        // titleText: Notification.ConversationTitle
+        // contentText: the last message text
+        // conversationSenderName: the last non-user sender's name
+        // conversationData.avatar: a single icon
+        assertEquals(CONVERSATION_TITLE, singleLineViewModel.titleText)
+        assertEquals(LAST_MESSAGE, singleLineViewModel.contentText)
+        assertEquals(
+            context.resources.getString(
+                com.android.internal.R.string.conversation_single_line_name_display,
+                LAST_SENDER_NAME
+            ),
+            singleLineViewModel.conversationData?.conversationSenderName
+        )
+        assertTrue {
+            singleLineViewModel.conversationData
+                ?.avatar
+                ?.equalsTo(SingleIcon(largeIcon.loadDrawable(context))) == true
+        }
+    }
+
+    @Test
+    fun createViewModelForGroupConversationWithNoIcon() {
+        // Given: a group conversation notification
+        val notificationType = GroupConversation()
+        val notification = getNotification(notificationType)
+
+        // When: inflate the SingleLineViewModel
+        val singleLineViewModel = notification.makeSingleLineViewModel(notificationType)
+
+        // Then: the inflated SingleLineViewModel should be expected
+        // titleText: Notification.ConversationTitle
+        // contentText: the last message text
+        // conversationSenderName: the last non-user sender's name
+        // conversationData.avatar: a face-pile consists the last sender's icon
+        assertEquals(CONVERSATION_TITLE, singleLineViewModel.titleText)
+        assertEquals(LAST_MESSAGE, singleLineViewModel.contentText)
+        assertEquals(
+            context.resources.getString(
+                com.android.internal.R.string.conversation_single_line_name_display,
+                LAST_SENDER_NAME
+            ),
+            singleLineViewModel.conversationData?.conversationSenderName
+        )
+
+        val backgroundColor =
+            Notification.Builder.recoverBuilder(context, notification)
+                .getBackgroundColor(/* isHeader = */ false)
+        assertTrue {
+            singleLineViewModel.conversationData
+                ?.avatar
+                ?.equalsTo(
+                    FacePile(
+                        firstSenderIconDrawable,
+                        lastSenderIconDrawable,
+                        backgroundColor,
+                    )
+                ) == true
+        }
+    }
+
+    sealed class NotificationType(val largeIcon: Icon? = null)
+
+    class NonMessaging(largeIcon: Icon? = null) : NotificationType(largeIcon)
+
+    class LegacyMessaging(largeIcon: Icon? = null) : NotificationType(largeIcon)
+
+    class LegacyMessagingGroup(largeIcon: Icon? = null) : NotificationType(largeIcon)
+
+    class OneToOneConversation(largeIcon: Icon? = null, val shortcutIcon: Icon? = null) :
+        NotificationType(largeIcon)
+
+    class GroupConversation(largeIcon: Icon? = null) : NotificationType(largeIcon)
+
+    private fun getNotification(type: NotificationType): Notification {
+        val notificationBuilder: Notification.Builder =
+            Notification.Builder(mContext, "channelId")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle(CONTENT_TITLE)
+                .setContentText(CONTENT_TEXT)
+                .setLargeIcon(type.largeIcon)
+
+        val user = Person.Builder().setName("User").build()
+
+        val buildMessagingStyle =
+            Notification.MessagingStyle(user)
+                .setConversationTitle(CONVERSATION_TITLE)
+                .addMessage("Hi", 0, currentUser)
+
+        return when (type) {
+            is NonMessaging ->
+                notificationBuilder
+                    .setStyle(Notification.BigTextStyle().bigText("Big Text"))
+                    .build()
+            is LegacyMessaging -> {
+                buildMessagingStyle
+                    .addMessage("What's up?", 0, firstSender)
+                    .addMessage("Not much", 0, currentUser)
+                    .addMessage(LAST_MESSAGE, 0, firstSender)
+
+                val notification = notificationBuilder.setStyle(buildMessagingStyle).build()
+
+                assertNull(notification.shortcutId)
+                notification
+            }
+            is LegacyMessagingGroup -> {
+                buildMessagingStyle
+                    .addMessage("What's up?", 0, firstSender)
+                    .addMessage("Check out my new hover board!", 0, lastSender)
+                    .setGroupConversation(true)
+                    .addMessage(LAST_MESSAGE, 0, lastSender)
+
+                val notification = notificationBuilder.setStyle(buildMessagingStyle).build()
+
+                assertNull(notification.shortcutId)
+                notification
+            }
+            is OneToOneConversation -> {
+                buildMessagingStyle
+                    .addMessage("What's up?", 0, firstSender)
+                    .addMessage("Not much", 0, currentUser)
+                    .addMessage(LAST_MESSAGE, 0, firstSender)
+                    .setShortcutIcon(type.shortcutIcon)
+                notificationBuilder.setShortcutId(SHORTCUT_ID).setStyle(buildMessagingStyle).build()
+            }
+            is GroupConversation -> {
+                buildMessagingStyle
+                    .addMessage("What's up?", 0, firstSender)
+                    .addMessage("Check out my new hover board!", 0, lastSender)
+                    .setGroupConversation(true)
+                    .addMessage(LAST_MESSAGE, 0, lastSender)
+                notificationBuilder.setShortcutId(SHORTCUT_ID).setStyle(buildMessagingStyle).build()
+            }
+        }
+    }
+
+    private fun Notification.makeSingleLineViewModel(type: NotificationType): SingleLineViewModel {
+        val builder = Notification.Builder.recoverBuilder(context, this)
+
+        // Validate the recovered builder has the right type of style
+        val expectMessagingStyle =
+            when (type) {
+                is LegacyMessaging,
+                is LegacyMessagingGroup,
+                is OneToOneConversation,
+                is GroupConversation -> true
+                else -> false
+            }
+        if (expectMessagingStyle) {
+            assertIs<Notification.MessagingStyle>(
+                builder.style,
+                "Notification style should be MessagingStyle"
+            )
+        } else {
+            assertIsNot<Notification.MessagingStyle>(
+                builder.style,
+                message = "Notification style should not be MessagingStyle"
+            )
+        }
+
+        // Inflate the SingleLineViewModel
+        // Mock the behavior of NotificationContentInflater.doInBackground
+        val messagingStyle = builder.getMessagingStyle()
+        val isConversation = type is OneToOneConversation || type is GroupConversation
+        return SingleLineViewInflater.inflateSingleLineViewModel(
+            this,
+            if (isConversation) messagingStyle else null,
+            builder,
+            context
+        )
+    }
+
+    private fun Notification.Builder.getMessagingStyle(): Notification.MessagingStyle? {
+        return style as? Notification.MessagingStyle
+    }
+
+    private fun getBitmap(context: Context, resId: Int): Bitmap {
+        val largeIconDimension =
+            context.resources.getDimension(R.dimen.conversation_single_line_avatar_size)
+        val d = context.resources.getDrawable(resId)
+        val b =
+            Bitmap.createBitmap(
+                largeIconDimension.toInt(),
+                largeIconDimension.toInt(),
+                Bitmap.Config.ARGB_8888
+            )
+        val c = Canvas(b)
+        val paint = Paint()
+        c.drawCircle(
+            largeIconDimension / 2,
+            largeIconDimension / 2,
+            largeIconDimension.coerceAtMost(largeIconDimension) / 2,
+            paint
+        )
+        d.setBounds(0, 0, largeIconDimension.toInt(), largeIconDimension.toInt())
+        paint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.SRC_IN))
+        c.saveLayer(0F, 0F, largeIconDimension, largeIconDimension, paint, Canvas.ALL_SAVE_FLAG)
+        d.draw(c)
+        c.restore()
+        return b
+    }
+
+    fun ConversationAvatar.equalsTo(other: ConversationAvatar?): Boolean =
+        when {
+            this === other -> true
+            this is SingleIcon && other is SingleIcon -> equalsTo(other)
+            this is FacePile && other is FacePile -> equalsTo(other)
+            else -> false
+        }
+
+    private fun SingleIcon.equalsTo(other: SingleIcon): Boolean =
+        iconDrawable?.equalsTo(other.iconDrawable) == true
+
+    private fun FacePile.equalsTo(other: FacePile): Boolean =
+        when {
+            bottomBackgroundColor != other.bottomBackgroundColor -> false
+            topIconDrawable?.equalsTo(other.topIconDrawable) != true -> false
+            bottomIconDrawable?.equalsTo(other.bottomIconDrawable) != true -> false
+            else -> true
+        }
+
+    fun Drawable.equalsTo(other: Drawable?): Boolean =
+        when {
+            this === other -> true
+            this.pixelsEqualTo(other) -> true
+            else -> false
+        }
+
+    private fun <T : Drawable> T.pixelsEqualTo(t: T?) =
+        toBitmap().pixelsEqualTo(t?.toBitmap(), false)
+
+    private fun Bitmap.pixelsEqualTo(otherBitmap: Bitmap?, shouldRecycle: Boolean = false) =
+        otherBitmap?.let { other ->
+            if (width == other.width && height == other.height) {
+                val res = toPixels().contentEquals(other.toPixels())
+                if (shouldRecycle) {
+                    doRecycle().also { otherBitmap.doRecycle() }
+                }
+                res
+            } else false
+        }
+            ?: kotlin.run { false }
+
+    private fun Bitmap.toPixels() =
+        IntArray(width * height).apply { getPixels(this, 0, width, 0, 0, width, height) }
+
+    fun Bitmap.doRecycle() {
+        if (!isRecycled) recycle()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 1ab4c32..dbe63f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -860,9 +860,6 @@
         when(mNotificationStackScrollLayout.onKeyguard()).thenReturn(true);
         mController.getNotifStackController().setNotifStats(NotifStats.getEmpty());
 
-        // WHEN: call updateImportantForAccessibility
-        mController.updateImportantForAccessibility();
-
         // THEN: mNotificationStackScrollLayout should not be important for A11y
         verify(mNotificationStackScrollLayout)
                 .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -884,9 +881,6 @@
                         /* hasClearableSilentNotifs = */ false)
         );
 
-        // WHEN: call updateImportantForAccessibility
-        mController.updateImportantForAccessibility();
-
         // THEN: mNotificationStackScrollLayout should be important for A11y
         verify(mNotificationStackScrollLayout)
                 .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -908,9 +902,6 @@
                         /* hasClearableSilentNotifs = */ false)
         );
 
-        // WHEN: call updateImportantForAccessibility
-        mController.updateImportantForAccessibility();
-
         // THEN: mNotificationStackScrollLayout should be important for A11y
         verify(mNotificationStackScrollLayout)
                 .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -925,9 +916,6 @@
         when(mNotificationStackScrollLayout.onKeyguard()).thenReturn(false);
         mController.getNotifStackController().setNotifStats(NotifStats.getEmpty());
 
-        // WHEN: call updateImportantForAccessibility
-        mController.updateImportantForAccessibility();
-
         // THEN: mNotificationStackScrollLayout should be important for A11y
         verify(mNotificationStackScrollLayout)
                 .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 06298b7..32c727c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -38,6 +38,9 @@
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel
 import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
@@ -45,6 +48,7 @@
 import com.android.systemui.shade.mockLargeScreenHeaderHelper
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
 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.ExperimentalCoroutinesApi
@@ -55,15 +59,22 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class SharedNotificationContainerViewModelTest : SysuiTestCase() {
+    val aodBurnInViewModel = mock(AodBurnInViewModel::class.java)
+    lateinit var translationYFlow: MutableStateFlow<Float>
 
     val kosmos =
         testKosmos().apply {
             fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
         }
+
+    init {
+        kosmos.aodBurnInViewModel = aodBurnInViewModel
+    }
     val testScope = kosmos.testScope
     val configurationRepository = kosmos.fakeConfigurationRepository
     val keyguardRepository = kosmos.fakeKeyguardRepository
@@ -75,11 +86,14 @@
     val sharedNotificationContainerInteractor = kosmos.sharedNotificationContainerInteractor
     val largeScreenHeaderHelper = kosmos.mockLargeScreenHeaderHelper
 
-    val underTest = kosmos.sharedNotificationContainerViewModel
+    lateinit var underTest: SharedNotificationContainerViewModel
 
     @Before
     fun setUp() {
         overrideResource(R.bool.config_use_split_notification_shade, false)
+        translationYFlow = MutableStateFlow(0f)
+        whenever(aodBurnInViewModel.translationY(any())).thenReturn(translationYFlow)
+        underTest = kosmos.sharedNotificationContainerViewModel
     }
 
     @Test
@@ -579,9 +593,21 @@
         }
 
     @Test
+    fun translationYUpdatesOnKeyguardForBurnIn() =
+        testScope.runTest {
+            val translationY by collectLastValue(underTest.translationY(BurnInParameters()))
+
+            showLockscreen()
+            assertThat(translationY).isEqualTo(0)
+
+            translationYFlow.value = 150f
+            assertThat(translationY).isEqualTo(150f)
+        }
+
+    @Test
     fun translationYUpdatesOnKeyguard() =
         testScope.runTest {
-            val translationY by collectLastValue(underTest.translationY)
+            val translationY by collectLastValue(underTest.translationY(BurnInParameters()))
 
             configurationRepository.setDimensionPixelSize(
                 R.dimen.keyguard_translate_distance_on_swipe_up,
@@ -601,7 +627,7 @@
     @Test
     fun translationYDoesNotUpdateWhenShadeIsExpanded() =
         testScope.runTest {
-            val translationY by collectLastValue(underTest.translationY)
+            val translationY by collectLastValue(underTest.translationY(BurnInParameters()))
 
             configurationRepository.setDimensionPixelSize(
                 R.dimen.keyguard_translate_distance_on_swipe_up,
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 316f2b9..849a13b 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
@@ -41,6 +41,8 @@
 
 import static java.util.Collections.emptySet;
 
+import static kotlinx.coroutines.flow.FlowKt.flowOf;
+
 import android.app.ActivityManager;
 import android.app.IWallpaperManager;
 import android.app.WallpaperManager;
@@ -72,13 +74,11 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.logging.testing.FakeMetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.TestScopeProvider;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
@@ -93,6 +93,10 @@
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.data.repository.CommunalRepository;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
+import com.android.systemui.communal.shared.model.CommunalSceneKey;
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
@@ -103,6 +107,7 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.notetask.NoteTaskController;
@@ -131,7 +136,6 @@
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.LightRevealScrim;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -144,13 +148,10 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.core.StatusBarInitializer;
 import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
-import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
@@ -169,7 +170,6 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.util.EventLog;
@@ -201,6 +201,8 @@
 
 import javax.inject.Provider;
 
+import kotlinx.coroutines.test.TestScope;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -209,11 +211,17 @@
     private static final int FOLD_STATE_FOLDED = 0;
     private static final int FOLD_STATE_UNFOLDED = 1;
 
+    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+
     private CentralSurfacesImpl mCentralSurfaces;
     private FakeMetricsLogger mMetricsLogger;
     private PowerManager mPowerManager;
     private VisualInterruptionDecisionProvider mVisualInterruptionDecisionProvider;
 
+
+    private final TestScope mTestScope = mKosmos.getTestScope();
+    private final CommunalInteractor mCommunalInteractor = mKosmos.getCommunalInteractor();
+    private final CommunalRepository mCommunalRepository = mKosmos.getCommunalRepository();
     @Mock private NotificationsController mNotificationsController;
     @Mock private LightBarController mLightBarController;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -235,12 +243,10 @@
     @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     @Mock private BiometricUnlockController mBiometricUnlockController;
     @Mock private AuthRippleController mAuthRippleController;
-    @Mock private NotificationListener mNotificationListener;
     @Mock private KeyguardViewMediator mKeyguardViewMediator;
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
-    @Mock private ShadeExpansionStateManager mShadeExpansionStateManager;
     @Mock private BatteryController mBatteryController;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private NotificationLaunchAnimatorControllerProvider mNotifLaunchAnimControllerProvider;
@@ -262,12 +268,10 @@
     @Mock private PulseExpansionHandler mPulseExpansionHandler;
     @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
     @Mock private KeyguardBypassController mKeyguardBypassController;
-    @Mock private DynamicPrivacyController mDynamicPrivacyController;
     @Mock private AutoHideController mAutoHideController;
     @Mock private StatusBarWindowController mStatusBarWindowController;
     @Mock private Provider<CollapsedStatusBarFragment> mCollapsedStatusBarFragmentProvider;
     @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
-    @Mock private UserSwitcherController mUserSwitcherController;
     @Mock private Bubbles mBubbles;
     @Mock private NoteTaskController mNoteTaskController;
     @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -295,7 +299,6 @@
     @Mock private WallpaperController mWallpaperController;
     @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
     @Mock private LockscreenShadeTransitionController mLockscreenTransitionController;
-    @Mock private NotificationVisibilityProvider mVisibilityProvider;
     @Mock private WallpaperManager mWallpaperManager;
     @Mock private IWallpaperManager mIWallpaperManager;
     @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@@ -304,8 +307,6 @@
     @Mock private OperatorNameViewController mOperatorNameViewController;
     @Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
     @Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
-    @Mock private NotifLiveDataStore mNotifLiveDataStore;
-    @Mock private InteractionJankMonitor mJankMonitor;
     @Mock private DeviceStateManager mDeviceStateManager;
     @Mock private WiredChargingRippleController mWiredChargingRippleController;
     @Mock private Lazy<CameraLauncher> mCameraLauncherLazy;
@@ -465,30 +466,28 @@
                 mKeyguardBypassController,
                 mKeyguardStateController,
                 mHeadsUpManager,
-                mDynamicPrivacyController,
                 new FalsingManagerFake(),
                 new FalsingCollectorFake(),
                 mBroadcastDispatcher,
                 mNotificationGutsManager,
-                mVisualInterruptionDecisionProvider,
                 new ShadeExpansionStateManager(),
                 mKeyguardViewMediator,
                 new DisplayMetrics(),
                 mMetricsLogger,
                 mShadeLogger,
-                new JavaAdapter(TestScopeProvider.getTestScope()),
+                new JavaAdapter(mTestScope),
                 mUiBgExecutor,
                 mNotificationPanelViewController,
                 mNotificationMediaManager,
                 mLockscreenUserManager,
                 mRemoteInputManager,
                 mQuickSettingsController,
-                mUserSwitcherController,
                 mBatteryController,
                 mColorExtractor,
                 mScreenLifecycle,
                 mWakefulnessLifecycle,
                 mPowerInteractor,
+                mCommunalInteractor,
                 mStatusBarStateController,
                 Optional.of(mBubbles),
                 () -> mNoteTaskController,
@@ -542,7 +541,6 @@
                 mWallpaperManager,
                 Optional.of(mStartingSurface),
                 mActivityLaunchAnimator,
-                mJankMonitor,
                 mDeviceStateManager,
                 mWiredChargingRippleController,
                 mDreamManager,
@@ -838,6 +836,25 @@
     }
 
     @Test
+    public void testEnteringGlanceableHub_updatesScrim() {
+        // Transition to the glanceable hub.
+        mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
+                CommunalSceneKey.Communal.INSTANCE)));
+        mTestScope.getTestScheduler().runCurrent();
+
+        // ScrimState also transitions.
+        verify(mScrimController).transitionTo(ScrimState.GLANCEABLE_HUB);
+
+        // Transition away from the glanceable hub.
+        mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
+                CommunalSceneKey.Blank.INSTANCE)));
+        mTestScope.getTestScheduler().runCurrent();
+
+        // ScrimState goes back to UNLOCKED.
+        verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any());
+    }
+
+    @Test
     public void testShowKeyguardImplementation_setsState() {
         when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index b3a47d7..3bde6e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -31,6 +31,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -50,6 +51,7 @@
 import android.graphics.Color;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.testing.ViewUtils;
 import android.util.MathUtils;
 import android.view.View;
 
@@ -58,13 +60,13 @@
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.TestScopeProvider;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.model.KeyguardState;
@@ -72,6 +74,7 @@
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel;
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.shade.transition.LinearLargeScreenShadeInterpolator;
@@ -102,7 +105,6 @@
 import java.util.HashSet;
 import java.util.Map;
 
-import kotlinx.coroutines.CoroutineDispatcher;
 import kotlinx.coroutines.test.TestScope;
 
 @RunWith(AndroidTestingRunner.class)
@@ -111,13 +113,14 @@
 public class ScrimControllerTest extends SysuiTestCase {
 
     @Rule public Expect mExpect = Expect.create();
+    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
 
     private final FakeConfigurationController mConfigurationController =
             new FakeConfigurationController();
     private final LargeScreenShadeInterpolator
             mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator();
 
-    private final TestScope mTestScope = TestScopeProvider.getTestScope();
+    private final TestScope mTestScope = mKosmos.getTestScope();
     private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
 
     private ScrimController mScrimController;
@@ -144,10 +147,12 @@
     @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
     @Mock private AlternateBouncerToGoneTransitionViewModel
             mAlternateBouncerToGoneTransitionViewModel;
-    @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+    private final KeyguardTransitionInteractor mKeyguardTransitionInteractor =
+            mKosmos.getKeyguardTransitionInteractor();
+    private final FakeKeyguardTransitionRepository mKeyguardTransitionRepository =
+            mKosmos.getKeyguardTransitionRepository();
     @Mock private KeyguardInteractor mKeyguardInteractor;
     private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository();
-    @Mock private CoroutineDispatcher mMainDispatcher;
     @Mock private TypedArray mMockTypedArray;
 
     // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
@@ -264,8 +269,6 @@
         when(mDelayedWakeLockFactory.create(any(String.class))).thenReturn(mWakeLock);
         when(mDockManager.isDocked()).thenReturn(false);
 
-        when(mKeyguardTransitionInteractor.transition(any(), any()))
-                .thenReturn(emptyFlow());
         when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha())
                 .thenReturn(emptyFlow());
         when(mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha())
@@ -291,13 +294,16 @@
                 mKeyguardTransitionInteractor,
                 mKeyguardInteractor,
                 mWallpaperRepository,
-                mMainDispatcher,
+                mKosmos.getTestDispatcher(),
                 mLinearLargeScreenShadeInterpolator);
         mScrimController.start();
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
 
+        // Attach behind scrim so flows that are collecting on it start running.
+        ViewUtils.attachView(mScrimBehind);
+
         mScrimController.setHasBackdrop(false);
 
         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
@@ -628,6 +634,164 @@
     }
 
     @Test
+    public void lockscreenToHubTransition_setsBehindScrimAlpha() {
+        // Start on lockscreen.
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        finishAnimationsImmediately();
+
+        // Behind scrim starts at default alpha.
+        final float transitionProgress = 0f;
+        float expectedAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+        mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+                new TransitionStep(
+                        KeyguardState.LOCKSCREEN,
+                        KeyguardState.GLANCEABLE_HUB,
+                        transitionProgress,
+                        TransitionState.STARTED
+                ), true);
+        mTestScope.getTestScheduler().runCurrent();
+        assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+        // Scrim fades out as transition runs.
+        final float runningProgress = 0.2f;
+        expectedAlpha = (1 - runningProgress) * ScrimState.KEYGUARD.getBehindAlpha();
+        mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+                new TransitionStep(
+                        KeyguardState.LOCKSCREEN,
+                        KeyguardState.GLANCEABLE_HUB,
+                        runningProgress,
+                        TransitionState.RUNNING
+                ), true);
+        mTestScope.getTestScheduler().runCurrent();
+        assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+        // Scrim invisible at end of transition.
+        final float finishedProgress = 1f;
+        expectedAlpha = 0f;
+        mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+                new TransitionStep(
+                        KeyguardState.LOCKSCREEN,
+                        KeyguardState.GLANCEABLE_HUB,
+                        finishedProgress,
+                        TransitionState.FINISHED
+                ), true);
+        mTestScope.getTestScheduler().runCurrent();
+        assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+    }
+
+    @Test
+    public void hubToLockscreenTransition_setsViewAlpha() {
+        // Start on glanceable hub.
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+        finishAnimationsImmediately();
+
+        // Behind scrim starts at 0 alpha.
+        final float transitionProgress = 0f;
+        float expectedAlpha = 0f;
+        mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+                new TransitionStep(
+                        KeyguardState.GLANCEABLE_HUB,
+                        KeyguardState.LOCKSCREEN,
+                        transitionProgress,
+                        TransitionState.STARTED
+                ), true);
+        mTestScope.getTestScheduler().runCurrent();
+        assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+        // Scrim fades in as transition runs.
+        final float runningProgress = 0.2f;
+        expectedAlpha = runningProgress * ScrimState.KEYGUARD.getBehindAlpha();
+        mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+                new TransitionStep(
+                        KeyguardState.GLANCEABLE_HUB,
+                        KeyguardState.LOCKSCREEN,
+                        runningProgress,
+                        TransitionState.RUNNING
+                ), true);
+        mTestScope.getTestScheduler().runCurrent();
+        assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+        // Scrim at default visibility at end of transition.
+        final float finishedProgress = 1f;
+        expectedAlpha = finishedProgress * ScrimState.KEYGUARD.getBehindAlpha();
+        mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+                new TransitionStep(
+                        KeyguardState.GLANCEABLE_HUB,
+                        KeyguardState.LOCKSCREEN,
+                        finishedProgress,
+                        TransitionState.FINISHED
+                ), true);
+        mTestScope.getTestScheduler().runCurrent();
+        assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+    }
+
+    @Test
+    public void transitionToHub() {
+        mScrimController.setRawPanelExpansionFraction(0f);
+        mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+        finishAnimationsImmediately();
+
+        // All scrims transparent on the hub.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
+    }
+
+    @Test
+    public void openBouncerOnHub() {
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+
+        // Open the bouncer.
+        mScrimController.setRawPanelExpansionFraction(0f);
+        mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_VISIBLE);
+        finishAnimationsImmediately();
+
+        // Only behind widget is visible.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, OPAQUE));
+
+        // Bouncer is closed.
+        mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+        finishAnimationsImmediately();
+
+        // All scrims are transparent.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
+    }
+
+    @Test
+    public void openShadeOnHub() {
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+
+        // Open the shade.
+        mScrimController.transitionTo(SHADE_LOCKED);
+        mScrimController.setQsPosition(1f, 0);
+        finishAnimationsImmediately();
+
+        // Shade scrims are visible.
+        assertScrimAlpha(Map.of(
+                mNotificationsScrim, OPAQUE,
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
+
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+        finishAnimationsImmediately();
+
+        // All scrims are transparent.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
+    }
+
+    @Test
     public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
         assertEquals(BOUNCER.getBehindTint(), 0x112233);
         mSurfaceColor = 0x223344;
@@ -1000,7 +1164,7 @@
                 mKeyguardTransitionInteractor,
                 mKeyguardInteractor,
                 mWallpaperRepository,
-                mMainDispatcher,
+                mKosmos.getTestDispatcher(),
                 mLinearLargeScreenShadeInterpolator);
         mScrimController.start();
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
@@ -1266,7 +1430,7 @@
                 ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, BOUNCER,
                 ScrimState.DREAMING, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR,
                 ScrimState.UNLOCKED, SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
-                ScrimState.AUTH_SCRIMMED_SHADE));
+                ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB));
 
         for (ScrimState state : ScrimState.values()) {
             if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
@@ -1683,6 +1847,26 @@
     }
 
     @Test
+    public void notificationBoundsTopGetsPassedToKeyguard() {
+        mScrimController.transitionTo(SHADE_LOCKED);
+        mScrimController.setQsPosition(1f, 0);
+        finishAnimationsImmediately();
+
+        mScrimController.setNotificationsBounds(0f, 100f, 0f, 0f);
+        verify(mKeyguardInteractor).setTopClippingBounds(eq(100));
+    }
+
+    @Test
+    public void notificationBoundsTopDoesNotGetPassedToKeyguardWhenNotifScrimIsNotVisible() {
+        mScrimController.setKeyguardOccluded(true);
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        finishAnimationsImmediately();
+
+        mScrimController.setNotificationsBounds(0f, 100f, 0f, 0f);
+        verify(mKeyguardInteractor).setTopClippingBounds(eq(null));
+    }
+
+    @Test
     public void transitionToDreaming() {
         mScrimController.setRawPanelExpansionFraction(0f);
         mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 8dde935..cb45315 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -182,8 +182,10 @@
         when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback);
         mFeatureFlags = new FakeFeatureFlags();
         mFeatureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false);
-        mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
-        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
+        mSetFlagsRule.disableFlags(
+                com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR,
+                com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
+        );
 
         when(mNotificationShadeWindowController.getWindowRootView())
                 .thenReturn(mNotificationShadeWindowView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
index 5b5819d..77e48bff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
@@ -102,29 +102,6 @@
         }
 
     @Test
-    fun satelliteManagerThrows_checkSupportDoesNotCrash() =
-        testScope.runTest {
-            whenever(satelliteManager.requestIsSatelliteSupported(any(), any()))
-                .thenThrow(IllegalStateException())
-
-            systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME)
-
-            underTest =
-                DeviceBasedSatelliteRepositoryImpl(
-                    Optional.of(satelliteManager),
-                    dispatcher,
-                    testScope.backgroundScope,
-                    FakeLogBuffer.Factory.create(),
-                    systemClock,
-                )
-
-            runCurrent()
-
-            // Creating the repo does not crash, and we consider the feature not to be supported
-            assertThat(underTest.satelliteSupport.value).isEqualTo(SatelliteSupport.NotSupported)
-        }
-
-    @Test
     fun connectionState_mapsFromSatelliteModemState() =
         testScope.runTest {
             setupDefaultRepo()
@@ -132,7 +109,7 @@
             runCurrent()
             val callback =
                 withArgCaptor<SatelliteModemStateCallback> {
-                    verify(satelliteManager).registerForSatelliteModemStateChanged(any(), capture())
+                    verify(satelliteManager).registerForModemStateChanged(any(), capture())
                 }
 
             // Mapping from modem state to SatelliteConnectionState is rote, just run all of the
@@ -207,7 +184,7 @@
                     null
                 }
                 .`when`(satelliteManager)
-                .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+                .requestIsCommunicationAllowedForCurrentLocation(
                     any(),
                     any<OutcomeReceiver<Boolean, SatelliteException>>()
                 )
@@ -230,7 +207,7 @@
                     null
                 }
                 .`when`(satelliteManager)
-                .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+                .requestIsCommunicationAllowedForCurrentLocation(
                     any(),
                     any<OutcomeReceiver<Boolean, SatelliteException>>()
                 )
@@ -253,7 +230,7 @@
                     null
                 }
                 .`when`(satelliteManager)
-                .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+                .requestIsCommunicationAllowedForCurrentLocation(
                     any(),
                     any<OutcomeReceiver<Boolean, SatelliteException>>()
                 )
@@ -297,7 +274,7 @@
                     null
                 }
                 .`when`(satelliteManager)
-                .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+                .requestIsCommunicationAllowedForCurrentLocation(
                     any(),
                     any<OutcomeReceiver<Boolean, SatelliteException>>()
                 )
@@ -330,7 +307,7 @@
                     null
                 }
                 .`when`(satelliteManager)
-                .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+                .requestIsCommunicationAllowedForCurrentLocation(
                     any(),
                     any<OutcomeReceiver<Boolean, SatelliteException>>()
                 )
@@ -356,7 +333,7 @@
             val signalStrength by collectLastValue(underTest.signalStrength)
 
             // THEN the manager is not asked for the information, and default values are returned
-            verify(satelliteManager, never()).registerForSatelliteModemStateChanged(any(), any())
+            verify(satelliteManager, never()).registerForModemStateChanged(any(), any())
             verify(satelliteManager, never()).registerForNtnSignalStrengthChanged(any(), any())
         }
 
@@ -382,7 +359,7 @@
             runCurrent()
 
             // THEN we finally register with the satellite manager
-            verify(satelliteManager).registerForSatelliteModemStateChanged(any(), any())
+            verify(satelliteManager).registerForModemStateChanged(any(), any())
         }
 
     private fun setUpRepo(
@@ -396,7 +373,7 @@
                 callback.onResult(satelliteSupported)
             }
             .whenever(satelliteManager)
-            .requestIsSatelliteSupported(any(), any())
+            .requestIsSupported(any(), any())
 
         systemClock.setUptimeMillis(Process.getStartUptimeMillis() + uptime)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index e010b86..d465b47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.pipeline.satellite.domain.interactor
 
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import androidx.test.filters.SmallTest
 import com.android.internal.telephony.flags.Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG
 import com.android.systemui.SysuiTestCase
@@ -49,8 +51,6 @@
 
     @Before
     fun setUp() {
-        mSetFlagsRule.enableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
-
         underTest =
             DeviceBasedSatelliteInteractor(
                 repo,
@@ -60,6 +60,7 @@
     }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun isSatelliteAllowed_falseWhenNotAllowed() =
         testScope.runTest {
             val latest by collectLastValue(underTest.isSatelliteAllowed)
@@ -72,6 +73,7 @@
         }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun isSatelliteAllowed_trueWhenAllowed() =
         testScope.runTest {
             val latest by collectLastValue(underTest.isSatelliteAllowed)
@@ -84,10 +86,10 @@
         }
 
     @Test
+    @DisableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun isSatelliteAllowed_offWhenFlagIsOff() =
         testScope.runTest {
             // GIVEN feature is disabled
-            mSetFlagsRule.disableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
 
             // Remake the interactor so the flag is read
             underTest =
@@ -107,6 +109,7 @@
         }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun connectionState_matchesRepositoryValue() =
         testScope.runTest {
             val latest by collectLastValue(underTest.connectionState)
@@ -129,10 +132,10 @@
         }
 
     @Test
+    @DisableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun connectionState_offWhenFeatureIsDisabled() =
         testScope.runTest {
             // GIVEN the flag is disabled
-            mSetFlagsRule.disableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
 
             // Remake the interactor so the flag is read
             underTest =
@@ -164,6 +167,7 @@
         }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun signalStrength_matchesRepo() =
         testScope.runTest {
             val latest by collectLastValue(underTest.signalStrength)
@@ -182,10 +186,10 @@
         }
 
     @Test
+    @DisableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun signalStrength_zeroWhenDisabled() =
         testScope.runTest {
             // GIVEN the flag is enabled
-            mSetFlagsRule.disableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
 
             // Remake the interactor so the flag is read
             underTest =
@@ -212,6 +216,19 @@
         }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+    fun areAllConnectionsOutOfService_noConnections_yes() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+            // GIVEN, 0 connections
+
+            // THEN the value is propagated to this interactor
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun areAllConnectionsOutOfService_twoConnectionsOos_yes() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -229,6 +246,7 @@
         }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun areAllConnectionsOutOfService_oneConnectionOos_yes() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -244,6 +262,7 @@
         }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun areAllConnectionsOutOfService_oneConnectionInService_no() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -259,6 +278,7 @@
         }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun areAllConnectionsOutOfService_twoConnectionsOneInService_no() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -276,6 +296,7 @@
         }
 
     @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun areAllConnectionsOutOfService_twoConnectionsInService_no() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -293,10 +314,10 @@
         }
 
     @Test
+    @DisableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
     fun areAllConnectionsOutOfService_falseWhenFlagIsOff() =
         testScope.runTest {
             // GIVEN the flag is disabled
-            mSetFlagsRule.disableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
 
             // Remake the interactor so the flag is read
             underTest =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 457acd2..b58a41c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -190,7 +190,7 @@
 
         mWakefulnessLifecycle.dispatchFinishedWakingUp();
         mThemeOverlayController.start();
-        verify(mUserTracker).addCallback(mUserTrackerCallback.capture(), eq(mBgExecutor));
+        verify(mUserTracker).addCallback(mUserTrackerCallback.capture(), eq(mMainExecutor));
         verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null),
                 eq(UserHandle.USER_ALL));
         verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiver.capture(), any(),
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 98f3ede..7eba3f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -548,7 +548,7 @@
         mZenModeConfig.suppressedVisualEffects = 0;
         when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
 
-        mSysUiState = new SysUiState(mDisplayTracker);
+        mSysUiState = new SysUiState(mDisplayTracker, mKosmos.getSceneContainerPlugin());
         mSysUiState.addCallback(sysUiFlags -> {
             mSysUiStateBubblesManageMenuExpanded =
                     (sysUiFlags
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/android/content/PackageManagerKosmos.kt
similarity index 72%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/android/content/PackageManagerKosmos.kt
index 692584d..8901314 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/android/content/PackageManagerKosmos.kt
@@ -13,12 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content
 
-package android.credentials.ui;
+import android.content.pm.PackageManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+val Kosmos.packageManager by Kosmos.Fixture { mock<PackageManager>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index af7f4c8..b62b3a2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -21,17 +21,25 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Instrumentation;
+import android.content.Context;
+import android.content.res.Resources;
 import android.os.Build;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.DisabledOnRavenwood;
 import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.ravenwood.RavenwoodClassRule;
+import android.platform.test.ravenwood.RavenwoodRule;
+import android.test.mock.MockContext;
 import android.testing.DexmakerShareClassLoaderRule;
 import android.testing.LeakCheck;
 import android.testing.TestWithLooperRule;
 import android.testing.TestableLooper;
 import android.util.Log;
+import android.util.Singleton;
 
 import androidx.annotation.NonNull;
 import androidx.core.animation.AndroidXAnimatorIsolationRule;
@@ -44,17 +52,24 @@
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.mockito.Mockito;
 
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
 import java.util.concurrent.Future;
 
 /**
  * Base class that does System UI specific setup.
  */
+// NOTE: This @DisabledOnRavenwood annotation is inherited to all subclasses (unless overridden
+// via a more-specific @EnabledOnRavenwood annotation); this means that by default all
+// subclasses will be "ignored" when executed on the Ravenwood testing environment; more
+// background on Ravenwood is available at go/ravenwood-docs
+@DisabledOnRavenwood
 public abstract class SysuiTestCase {
 
     private static final String TAG = "SysuiTestCase";
@@ -66,6 +81,23 @@
     public AndroidXAnimatorIsolationRule mAndroidXAnimatorIsolationRule =
             new AndroidXAnimatorIsolationRule();
 
+    /**
+     * Rule that respects class-level annotations such as {@code @DisabledOnRavenwood} when tests
+     * are running on Ravenwood; on all other test environments this rule is a no-op passthrough.
+     */
+    @ClassRule(order = Integer.MIN_VALUE + 1)
+    public static final RavenwoodClassRule sRavenwood = new RavenwoodClassRule();
+
+    /**
+     * Rule that defines and prepares the Ravenwood environment when tests are running on
+     * Ravenwood; on all other test environments this rule is a no-op passthrough.
+     */
+    @Rule(order = Integer.MIN_VALUE + 1)
+    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+            .setProcessApp()
+            .setProvideMainThread(true)
+            .build();
+
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
 
@@ -78,7 +110,7 @@
     @NonNull
     private SysuiTestableContext createTestableContext() {
         SysuiTestableContext context = new SysuiTestableContext(
-                InstrumentationRegistry.getContext(), getLeakCheck());
+                getTestableContextBase(), getLeakCheck());
         if (isRobolectricTest()) {
             // Manually associate a Display to context for Robolectric test. Similar to b/214297409
             return context.createDefaultDisplayContext();
@@ -87,6 +119,43 @@
         }
     }
 
+    @NonNull
+    private Context getTestableContextBase() {
+        if (isRavenwoodTest()) {
+            // TODO(b/292141694): build out Ravenwood support for Context
+            // Ravenwood doesn't yet provide a Context, but many SysUI tests assume one exists;
+            // so here we construct just enough of a Context to be useful; this will be replaced
+            // as more of the Ravenwood environment is built out
+            return new MockContext() {
+                @Override
+                public void setTheme(int resid) {
+                    // TODO(b/318393625): build out Ravenwood support for Resources
+                    // until then, ignored as no-op
+                }
+
+                @Override
+                public Resources getResources() {
+                    // TODO(b/318393625): build out Ravenwood support for Resources
+                    return Mockito.mock(Resources.class);
+                }
+
+                private Singleton<Executor> mMainExecutor = new Singleton<>() {
+                    @Override
+                    protected Executor create() {
+                        return new HandlerExecutor(new Handler(Looper.getMainLooper()));
+                    }
+                };
+
+                @Override
+                public Executor getMainExecutor() {
+                    return mMainExecutor.get();
+                }
+            };
+        } else {
+            return InstrumentationRegistry.getContext();
+        }
+    }
+
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
@@ -103,17 +172,22 @@
     public void SysuiSetup() throws Exception {
         mSysuiDependency = new SysuiTestDependency(mContext, shouldFailOnLeakedReceiver());
         mDependency = mSysuiDependency.install();
-        mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
-        Instrumentation inst = spy(mRealInstrumentation);
-        when(inst.getContext()).thenAnswer(invocation -> {
-            throw new RuntimeException(
-                    "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
-        });
-        when(inst.getTargetContext()).thenAnswer(invocation -> {
-            throw new RuntimeException(
-                    "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
-        });
-        InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments());
+        // TODO(b/292141694): build out Ravenwood support for Instrumentation
+        // Ravenwood doesn't yet provide Instrumentation, so we sidestep this global configuration
+        // step; any tests that rely on it are already being excluded on Ravenwood
+        if (!isRavenwoodTest()) {
+            mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
+            Instrumentation inst = spy(mRealInstrumentation);
+            when(inst.getContext()).thenAnswer(invocation -> {
+                throw new RuntimeException(
+                        "Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
+            });
+            when(inst.getTargetContext()).thenAnswer(invocation -> {
+                throw new RuntimeException(
+                        "Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
+            });
+            InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments());
+        }
     }
 
     protected boolean shouldFailOnLeakedReceiver() {
@@ -209,7 +283,11 @@
     }
 
     public static boolean isRobolectricTest() {
-        return Build.FINGERPRINT.contains("robolectric");
+        return !isRavenwoodTest() && Build.FINGERPRINT.contains("robolectric");
+    }
+
+    public static boolean isRavenwoodTest() {
+        return RavenwoodRule.isOnRavenwood();
     }
 
     private static final void validateThread(Looper l) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt
index d89d7b0..364d3b2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt
@@ -34,10 +34,16 @@
         // is missing (constructing the actual one would throw).
         // TODO(b/219008720): Remove this.
         dependency.injectMockDependency(SystemUIDialogManager::class.java)
-        dependency.injectTestDependency(
-            DialogLaunchAnimator::class.java,
-            fakeDialogLaunchAnimator()
-        )
+
+        // TODO(b/292141694): build out Ravenwood support for UI animations
+        // Ravenwood doesn't yet provide UI animations, so we sidestep this global configuration
+        // step; any tests that rely on it are already being excluded under Ravenwood
+        if (!SysuiTestCase.isRavenwoodTest()) {
+            dependency.injectTestDependency(
+                    DialogLaunchAnimator::class.java,
+                    fakeDialogLaunchAnimator()
+            )
+        }
 
         // Many tests end up creating a BroadcastDispatcher. Instead, give them a fake that will
         // record receivers registered. They are not actually leaked as they are kept just as a weak
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
index 7c8a7c8..2bd104d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
@@ -19,12 +19,14 @@
 import com.android.systemui.authentication.data.repository.authenticationRepository
 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.authenticationInteractor by
     Kosmos.Fixture {
         AuthenticationInteractor(
             applicationScope = applicationCoroutineScope,
+            backgroundDispatcher = testDispatcher,
             repository = authenticationRepository,
             selectedUserInteractor = selectedUserInteractor,
         )
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/UdfpsUtilsKosmos.kt
similarity index 75%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/UdfpsUtilsKosmos.kt
index 692584d..4849fec 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/UdfpsUtilsKosmos.kt
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package com.android.systemui.biometrics
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.udfpsUtils by Kosmos.Fixture { mock<UdfpsUtils>() }
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryKosmos.kt
similarity index 72%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryKosmos.kt
index 692584d..961022f 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryKosmos.kt
@@ -12,13 +12,12 @@
  * WITHOUT 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.credentials.ui;
-
-/**
- * Base class for different types of ui results.
  *
- * @hide
  */
-public interface UiResult {}
+
+package com.android.systemui.biometrics.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.biometricStatusRepository by Fixture { FakeBiometricStatusRepository() }
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/PromptRepositoryKosmos.kt
similarity index 73%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/PromptRepositoryKosmos.kt
index 692584d..31fa5d2 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/PromptRepositoryKosmos.kt
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package com.android.systemui.biometrics.data.repository
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+var Kosmos.promptRepository by Fixture { FakePromptRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorKosmos.kt
new file mode 100644
index 0000000..1493f14
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorKosmos.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.biometrics.domain.interactor
+
+import com.android.app.activityTaskManager
+import com.android.systemui.biometrics.data.repository.biometricStatusRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.biometricStatusInteractor by Fixture {
+    BiometricStatusInteractorImpl(
+        activityTaskManager = activityTaskManager,
+        biometricStatusRepository = biometricStatusRepository
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt
new file mode 100644
index 0000000..7f9a71c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.domain.interactor
+
+import com.android.internal.widget.lockPatternUtils
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.promptRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.promptSelectorInteractor by Fixture {
+    PromptSelectorInteractorImpl(
+        fingerprintPropertyRepository = fingerprintPropertyRepository,
+        promptRepository = promptRepository,
+        lockPatternUtils = lockPatternUtils
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt
new file mode 100644
index 0000000..9cbe633
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt
@@ -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 com.android.systemui.biometrics.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.promptSelectorInteractor
+import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor
+import com.android.systemui.biometrics.udfpsUtils
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.promptViewModel by Fixture {
+    PromptViewModel(
+        displayStateInteractor = displayStateInteractor,
+        promptSelectorInteractor = promptSelectorInteractor,
+        context = applicationContext,
+        udfpsOverlayInteractor = udfpsOverlayInteractor,
+        udfpsUtils = udfpsUtils
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt
index 06b6cda6..244ef8d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt
@@ -16,7 +16,40 @@
 
 package com.android.systemui.bouncer.domain.interactor
 
+import android.content.applicationContext
+import com.android.keyguard.keyguardSecurityModel
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.falsingCollector
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.trustRepository
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.policy.KeyguardStateControllerImpl
+import com.android.systemui.user.domain.interactor.selectedUserInteractor
+import com.android.systemui.util.concurrency.mockExecutorHandler
 import com.android.systemui.util.mockito.mock
 
-var Kosmos.primaryBouncerInteractor by Kosmos.Fixture { mock<PrimaryBouncerInteractor>() }
+var Kosmos.mockPrimaryBouncerInteractor by Kosmos.Fixture { mock<PrimaryBouncerInteractor>() }
+var Kosmos.primaryBouncerInteractor by
+    Kosmos.Fixture {
+        PrimaryBouncerInteractor(
+            repository = keyguardBouncerRepository,
+            primaryBouncerView = mock<BouncerView>(),
+            mainHandler = mockExecutorHandler(executor = fakeExecutor),
+            keyguardStateController = mock<KeyguardStateControllerImpl>(),
+            keyguardSecurityModel = keyguardSecurityModel,
+            primaryBouncerCallbackInteractor = mock<PrimaryBouncerCallbackInteractor>(),
+            falsingCollector = falsingCollector,
+            dismissCallbackRegistry = mock<DismissCallbackRegistry>(),
+            context = applicationContext,
+            keyguardUpdateMonitor = keyguardUpdateMonitor,
+            trustRepository = trustRepository,
+            applicationScope = applicationCoroutineScope,
+            selectedUserInteractor = selectedUserInteractor,
+            deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
index e25e8c0..bc7e7af 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
@@ -39,13 +39,4 @@
     private fun onConfigured(id: Int, providerInfo: AppWidgetProviderInfo, priority: Int) {
         _communalWidgets.value += listOf(CommunalWidgetContentModel(id, providerInfo, priority))
     }
-
-    private var isHostActive = false
-    override fun updateAppWidgetHostActive(active: Boolean) {
-        isHostActive = active
-    }
-
-    fun isHostActive(): Boolean {
-        return isHostActive
-    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index 1abf71f..c818e9c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -24,14 +24,12 @@
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.smartspace.data.repository.smartspaceRepository
 import com.android.systemui.user.data.repository.userRepository
 import com.android.systemui.util.mockito.mock
 
 val Kosmos.communalInteractor by Fixture {
     CommunalInteractor(
-        applicationScope = applicationCoroutineScope,
         communalRepository = communalRepository,
         widgetRepository = communalWidgetRepository,
         mediaRepository = communalMediaRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
index 6436a38..77caeaa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt
@@ -16,25 +16,16 @@
 package com.android.systemui.deviceentry.data.repository
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import dagger.Binds
 import dagger.Module
 import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.asStateFlow
 
 /** Fake implementation of [DeviceEntryRepository] */
 @SysUISingleton
 class FakeDeviceEntryRepository @Inject constructor() : DeviceEntryRepository {
-    private val _enteringDeviceFromBiometricUnlock: MutableSharedFlow<BiometricUnlockSource> =
-        MutableSharedFlow()
-    override val enteringDeviceFromBiometricUnlock: Flow<BiometricUnlockSource> =
-        _enteringDeviceFromBiometricUnlock.asSharedFlow()
-
     private var isLockscreenEnabled = true
 
     private val _isBypassEnabled = MutableStateFlow(false)
@@ -62,10 +53,6 @@
     fun setBypassEnabled(isBypassEnabled: Boolean) {
         _isBypassEnabled.value = isBypassEnabled
     }
-
-    suspend fun enteringDeviceFromBiometricUnlock(sourceType: BiometricUnlockSource) {
-        _enteringDeviceFromBiometricUnlock.emit(sourceType)
-    }
 }
 
 @Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt
new file mode 100644
index 0000000..3070cf4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.systemui.deviceentry.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.authRippleInteractor by
+    Kosmos.Fixture {
+        AuthRippleInteractor(
+            deviceEntrySourceInteractor = deviceEntrySourceInteractor,
+            deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt
index 0b1fb40..5575b05 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt
@@ -23,7 +23,7 @@
 import com.android.keyguard.trustManager
 import com.android.systemui.biometrics.data.repository.facePropertyRepository
 import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
 import com.android.systemui.deviceentry.data.repository.faceWakeUpTriggersConfig
 import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.deviceEntryFaceAuthRepository
@@ -46,7 +46,7 @@
             applicationScope = applicationCoroutineScope,
             mainDispatcher = testDispatcher,
             repository = deviceEntryFaceAuthRepository,
-            primaryBouncerInteractor = { primaryBouncerInteractor },
+            primaryBouncerInteractor = { mockPrimaryBouncerInteractor },
             alternateBouncerInteractor = alternateBouncerInteractor,
             keyguardTransitionInteractor = keyguardTransitionInteractor,
             faceAuthenticationLogger = faceAuthLogger,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt
index de58ae5..878e385 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt
@@ -30,7 +30,7 @@
 val Kosmos.deviceEntryHapticsInteractor by
     Kosmos.Fixture {
         DeviceEntryHapticsInteractor(
-            deviceEntryInteractor = deviceEntryInteractor,
+            deviceEntrySourceInteractor = deviceEntrySourceInteractor,
             deviceEntryFingerprintAuthInteractor = deviceEntryFingerprintAuthInteractor,
             deviceEntryBiometricAuthInteractor = deviceEntryBiometricAuthInteractor,
             fingerprintPropertyRepository = fingerprintPropertyRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
index 8dcdd3a..0d1a31f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.deviceentry.domain.interactor
 
 import com.android.systemui.authentication.domain.interactor.authenticationInteractor
@@ -28,6 +26,7 @@
 import com.android.systemui.scene.shared.flag.sceneContainerFlags
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.deviceEntryInteractor by
     Kosmos.Fixture {
         DeviceEntryInteractor(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt
new file mode 100644
index 0000000..0b9ec92
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.systemui.deviceentry.domain.interactor
+
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.kosmos.Kosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.deviceEntrySourceInteractor by
+    Kosmos.Fixture {
+        DeviceEntrySourceInteractor(
+            keyguardInteractor = keyguardInteractor,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt
new file mode 100644
index 0000000..2fead91
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.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.deviceentry.ui.binder
+
+import android.content.packageManager
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.util.sensors.asyncSensorManager
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.liftToRunFaceAuthBinder by
+    Kosmos.Fixture {
+        LiftToRunFaceAuthBinder(
+            scope = applicationCoroutineScope,
+            packageManager = packageManager,
+            asyncSensorManager = asyncSensorManager,
+            keyguardUpdateMonitor = keyguardUpdateMonitor,
+            keyguardInteractor = keyguardInteractor,
+            primaryBouncerInteractor = primaryBouncerInteractor,
+            alternateBouncerInteractor = alternateBouncerInteractor,
+            deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor,
+            powerInteractor = powerInteractor,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 5766f7a..793e2d7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -65,7 +65,7 @@
     override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing
 
     private val _isKeyguardUnlocked = MutableStateFlow(false)
-    override val isKeyguardUnlocked: StateFlow<Boolean> = _isKeyguardUnlocked.asStateFlow()
+    override val isKeyguardDismissible: StateFlow<Boolean> = _isKeyguardUnlocked.asStateFlow()
 
     private val _isKeyguardOccluded = MutableStateFlow(false)
     override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded
@@ -165,7 +165,7 @@
         _isKeyguardOccluded.value = isOccluded
     }
 
-    fun setKeyguardUnlocked(isUnlocked: Boolean) {
+    fun setKeyguardDismissible(isUnlocked: Boolean) {
         _isKeyguardUnlocked.value = isUnlocked
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index 0c1dbfe..e20a0ab 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -28,9 +28,12 @@
 import java.util.UUID
 import javax.inject.Inject
 import junit.framework.Assert.fail
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.channels.BufferOverflow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestCoroutineScheduler
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -150,6 +153,15 @@
         _transitions.emit(step)
     }
 
+    /** Version of [sendTransitionStep] that's usable from Java tests. */
+    fun sendTransitionStepJava(
+        coroutineScope: CoroutineScope,
+        step: TransitionStep,
+        validateStep: Boolean = true
+    ): Job {
+        return coroutineScope.launch { sendTransitionStep(step, validateStep) }
+    }
+
     suspend fun sendTransitionSteps(
         steps: List<TransitionStep>,
         testScope: TestScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt
index 35cfa89..a8f45b0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt
@@ -26,7 +26,7 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.aodBurnInViewModel by Fixture {
+var Kosmos.aodBurnInViewModel by Fixture {
     AodBurnInViewModel(
         burnInInteractor = burnInInteractor,
         configurationInteractor = configurationInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
index c71c1c3..ffa4133 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
@@ -18,7 +18,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
 import com.android.systemui.flags.featureFlagsClassic
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
@@ -31,7 +31,7 @@
 val Kosmos.bouncerToGoneFlows by Fixture {
     BouncerToGoneFlows(
         statusBarStateController = sysuiStatusBarStateController,
-        primaryBouncerInteractor = primaryBouncerInteractor,
+        primaryBouncerInteractor = mockPrimaryBouncerInteractor,
         keyguardDismissActionInteractor = mock(),
         featureFlags = featureFlagsClassic,
         shadeInteractor = shadeInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
index 5ceefde..73fd999 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntrySourceInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.burnInInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
@@ -27,6 +28,7 @@
 import com.android.systemui.scene.shared.flag.sceneContainerFlags
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
 val Kosmos.fakeDeviceEntryIconViewModelTransition by Fixture { FakeDeviceEntryIconTransition() }
 
@@ -34,6 +36,7 @@
     setOf<DeviceEntryIconTransition>(fakeDeviceEntryIconViewModelTransition)
 }
 
+@ExperimentalCoroutinesApi
 val Kosmos.deviceEntryIconViewModel by Fixture {
     DeviceEntryIconViewModel(
         transitions = deviceEntryIconViewModelTransitionsMock,
@@ -46,5 +49,6 @@
         sceneContainerFlags = sceneContainerFlags,
         keyguardViewController = { statusBarKeyguardViewManager },
         deviceEntryInteractor = deviceEntryInteractor,
+        deviceEntrySourceInteractor = deviceEntrySourceInteractor,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
index ab28d0d6..4ecff73 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
@@ -18,7 +18,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
 import com.android.systemui.flags.featureFlagsClassic
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
@@ -30,7 +30,7 @@
 val Kosmos.primaryBouncerToGoneTransitionViewModel by Fixture {
     PrimaryBouncerToGoneTransitionViewModel(
         statusBarStateController = sysuiStatusBarStateController,
-        primaryBouncerInteractor = primaryBouncerInteractor,
+        primaryBouncerInteractor = mockPrimaryBouncerInteractor,
         keyguardDismissActionInteractor = mock(),
         featureFlags = featureFlagsClassic,
         bouncerToGoneFlows = bouncerToGoneFlows,
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 321f944..083de10 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
@@ -32,6 +32,9 @@
 import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.jank.interactionJankMonitor
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.model.sceneContainerPlugin
 import com.android.systemui.plugins.statusbar.statusBarStateController
 import com.android.systemui.power.data.repository.fakePowerRepository
 import com.android.systemui.power.domain.interactor.powerInteractor
@@ -60,6 +63,8 @@
     val bouncerRepository by lazy { kosmos.bouncerRepository }
     val communalRepository by lazy { kosmos.fakeCommunalRepository }
     val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
+    val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
+    val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor }
     val powerRepository by lazy { kosmos.fakePowerRepository }
     val clock by lazy { kosmos.systemClock }
     val mobileConnectionsRepository by lazy { kosmos.fakeMobileConnectionsRepository }
@@ -74,6 +79,7 @@
     val deviceEntryInteractor by lazy { kosmos.deviceEntryInteractor }
     val deviceUnlockedInteractor by lazy { kosmos.deviceUnlockedInteractor }
     val communalInteractor by lazy { kosmos.communalInteractor }
+    val sceneContainerPlugin by lazy { kosmos.sceneContainerPlugin }
 
     init {
         kosmos.applicationContext = testCase.context
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
similarity index 67%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
index 692584d..b1027b9 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package com.android.systemui.model
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+
+val Kosmos.sceneContainerPlugin by Fixture { SceneContainerPlugin { sceneInteractor } }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorKosmos.kt
index 57b272f..d2dd200 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorKosmos.kt
@@ -17,7 +17,12 @@
 package com.android.systemui.shade.domain.interactor
 
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.shade.data.repository.shadeAnimationRepository
 
 var Kosmos.shadeAnimationInteractor: ShadeAnimationInteractor by
     Kosmos.Fixture { ShadeAnimationInteractorEmptyImpl(shadeAnimationRepository) }
+var Kosmos.shadeAnimationInteractorSceneContainerImpl: ShadeAnimationInteractorSceneContainerImpl by
+    Kosmos.Fixture {
+        ShadeAnimationInteractorSceneContainerImpl(shadeAnimationRepository, sceneInteractor)
+    }
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 db40509..7c398cd 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
@@ -19,6 +19,7 @@
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel
 import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.lockscreenToOccludedTransitionViewModel
@@ -40,6 +41,7 @@
         occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
         lockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel,
         glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
-        lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel
+        lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
+        aodBurnInViewModel = aodBurnInViewModel,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt
index 18a2f94..33ed7e6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt
@@ -20,3 +20,5 @@
 import com.android.systemui.util.mockito.mock
 
 val Kosmos.configurationController by Kosmos.Fixture { mock<ConfigurationController>() }
+val Kosmos.fakeConfigurationController: FakeConfigurationController by
+    Kosmos.Fixture { FakeConfigurationController() }
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/sensors/AsyncSensorManagerKosmos.kt
similarity index 74%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/util/sensors/AsyncSensorManagerKosmos.kt
index 692584d..117ae8c 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/sensors/AsyncSensorManagerKosmos.kt
@@ -13,12 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.systemui.util.sensors
 
-package android.credentials.ui;
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+val Kosmos.asyncSensorManager by Kosmos.Fixture { mock<AsyncSensorManager>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt
new file mode 100644
index 0000000..d341073
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt
@@ -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.systemui.volume.panel
+
+import android.content.res.mainResources
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.policy.fakeConfigurationController
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.volume.panel.dagger.factory.KosmosVolumePanelComponentFactory
+import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
+import com.android.systemui.volume.panel.domain.TestComponentAvailabilityCriteria
+import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor
+import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractorImpl
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent
+import com.android.systemui.volume.panel.ui.composable.ComponentsFactory
+import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
+import javax.inject.Provider
+
+val Kosmos.mockVolumePanelUiComponent: VolumePanelUiComponent by Kosmos.Fixture { mock {} }
+val Kosmos.mockVolumePanelUiComponentProvider: Provider<VolumePanelUiComponent> by
+    Kosmos.Fixture { Provider { mockVolumePanelUiComponent } }
+var Kosmos.componentByKey: Map<VolumePanelComponentKey, Provider<VolumePanelUiComponent>> by
+    Kosmos.Fixture { emptyMap() }
+val Kosmos.componentsFactory: ComponentsFactory by
+    Kosmos.Fixture { ComponentsFactory(componentByKey) }
+
+var Kosmos.componentsLayoutManager: ComponentsLayoutManager by Kosmos.Fixture()
+var Kosmos.enabledComponents: Collection<VolumePanelComponentKey> by
+    Kosmos.Fixture { componentByKey.keys }
+val Kosmos.unavailableCriteria: Provider<ComponentAvailabilityCriteria> by
+    Kosmos.Fixture { Provider { TestComponentAvailabilityCriteria(false) } }
+val Kosmos.availableCriteria: Provider<ComponentAvailabilityCriteria> by
+    Kosmos.Fixture { Provider { TestComponentAvailabilityCriteria(true) } }
+var Kosmos.defaultCriteria: Provider<ComponentAvailabilityCriteria> by
+    Kosmos.Fixture { availableCriteria }
+var Kosmos.criteriaByKey: Map<VolumePanelComponentKey, Provider<ComponentAvailabilityCriteria>> by
+    Kosmos.Fixture { emptyMap() }
+var Kosmos.componentsInteractor: ComponentsInteractor by
+    Kosmos.Fixture {
+        ComponentsInteractorImpl(
+            enabledComponents,
+            defaultCriteria,
+            testScope.backgroundScope,
+            criteriaByKey,
+        )
+    }
+
+var Kosmos.volumePanelViewModel: VolumePanelViewModel by
+    Kosmos.Fixture {
+        VolumePanelViewModel(
+            mainResources,
+            KosmosVolumePanelComponentFactory(this),
+            fakeConfigurationController,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt
new file mode 100644
index 0000000..49041ed
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.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.volume.panel.dagger.factory
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.volume.panel.componentsFactory
+import com.android.systemui.volume.panel.componentsInteractor
+import com.android.systemui.volume.panel.componentsLayoutManager
+import com.android.systemui.volume.panel.dagger.VolumePanelComponent
+import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor
+import com.android.systemui.volume.panel.ui.composable.ComponentsFactory
+import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
+import kotlinx.coroutines.CoroutineScope
+
+class KosmosVolumePanelComponentFactory(private val kosmos: Kosmos) : VolumePanelComponentFactory {
+
+    override fun create(viewModel: VolumePanelViewModel): VolumePanelComponent =
+        object : VolumePanelComponent {
+
+            override fun coroutineScope(): CoroutineScope = kosmos.testScope.backgroundScope
+
+            override fun componentsInteractor(): ComponentsInteractor = kosmos.componentsInteractor
+
+            override fun componentsFactory(): ComponentsFactory = kosmos.componentsFactory
+
+            override fun componentsLayoutManager(): ComponentsLayoutManager =
+                kosmos.componentsLayoutManager
+        }
+}
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/TestComponentAvailabilityCriteria.kt
similarity index 67%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/TestComponentAvailabilityCriteria.kt
index 692584d..5ab9274 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/TestComponentAvailabilityCriteria.kt
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.credentials.ui;
+package com.android.systemui.volume.panel.domain
 
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+class TestComponentAvailabilityCriteria(val isAvailable: Boolean) : ComponentAvailabilityCriteria {
+
+    override fun isAvailable(): Flow<Boolean> = flowOf(isAvailable)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.kt
new file mode 100644
index 0000000..655d8f7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.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.volume.panel.ui.layout
+
+import com.android.systemui.volume.panel.ui.viewmodel.ComponentState
+import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
+
+class FakeComponentsLayoutManager(
+    private val isBottomBar: (components: ComponentState) -> Boolean
+) : ComponentsLayoutManager {
+
+    override fun layout(
+        volumePanelState: VolumePanelState,
+        components: Collection<ComponentState>
+    ): ComponentsLayout {
+        return ComponentsLayout(
+            components
+                .filter { componentState -> !isBottomBar(componentState) }
+                .sortedBy { it.key },
+            components.find(isBottomBar)!!,
+        )
+    }
+}
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 3aa9cc8..155c523 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -132,7 +132,7 @@
 
     private static final String CAMERA_EXTENSION_VERSION_NAME =
             "androidx.camera.extensions.impl.ExtensionVersionImpl";
-    private static final String LATEST_VERSION = "1.4.0";
+    private static final String LATEST_VERSION = "1.5.0";
     // No support for the init sequence
     private static final String NON_INIT_VERSION_PREFIX = "1.0";
     // Support advanced API and latency queries
@@ -1693,6 +1693,7 @@
         private final Size mSize;
         private final int mImageFormat;
         private final int mDataspace;
+        private final long mUsage;
 
         public OutputSurfaceImplStub(OutputSurface outputSurface) {
             mSurface = outputSurface.surface;
@@ -1700,8 +1701,10 @@
             mImageFormat = outputSurface.imageFormat;
             if (mSurface != null) {
                 mDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
+                mUsage = SurfaceUtils.getSurfaceUsage(mSurface);
             } else {
                 mDataspace = -1;
+                mUsage = 0;
             }
         }
 
@@ -1724,6 +1727,11 @@
         public int getDataspace() {
             return mDataspace;
         }
+
+        @Override
+        public long getUsage() {
+            return mUsage;
+        }
     }
 
     private class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub implements
@@ -2471,6 +2479,11 @@
             ret.size.height = imageReaderOutputConfig.getSize().getHeight();
             ret.imageFormat = imageReaderOutputConfig.getImageFormat();
             ret.capacity = imageReaderOutputConfig.getMaxImages();
+            if (EFV_SUPPORTED) {
+                ret.usage = imageReaderOutputConfig.getUsage();
+            } else {
+                ret.usage = 0;
+            }
         } else if (output instanceof MultiResolutionImageReaderOutputConfigImpl) {
             MultiResolutionImageReaderOutputConfigImpl multiResReaderConfig =
                     (MultiResolutionImageReaderOutputConfigImpl) output;
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index e013a3e..1ac69f6 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -30,6 +30,9 @@
         "junit-src/**/*.java",
         "junit-impl-src/**/*.java",
     ],
+    static_libs: [
+        "androidx.test.monitor-for-device",
+    ],
     libs: [
         "framework-minus-apex.ravenwood",
         "junit",
@@ -61,3 +64,17 @@
         "core-xml-for-host",
     ],
 }
+
+java_host_for_device {
+    name: "androidx.test.monitor-for-device",
+    libs: [
+        "androidx.test.monitor-for-host",
+    ],
+}
+
+java_device_for_host {
+    name: "androidx.test.monitor-for-host",
+    libs: [
+        "androidx.test.monitor",
+    ],
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 91c522e..a797b1d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -16,13 +16,36 @@
 
 package android.platform.test.ravenwood;
 
+import android.app.Instrumentation;
+import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.Looper;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.io.PrintStream;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
 public class RavenwoodRuleImpl {
     private static final String MAIN_THREAD_NAME = "RavenwoodMain";
 
-    public static boolean isUnderRavenwood() {
+    /**
+     * When enabled, attempt to dump all thread stacks just before we hit the
+     * overall Tradefed timeout, to aid in debugging deadlocks.
+     */
+    private static final boolean ENABLE_TIMEOUT_STACKS = false;
+    private static final int TIMEOUT_MILLIS = 9_000;
+
+    private static final ScheduledExecutorService sTimeoutExecutor =
+            Executors.newScheduledThreadPool(1);
+
+    private static ScheduledFuture<?> sPendingTimeout;
+
+    public static boolean isOnRavenwood() {
         return true;
     }
 
@@ -41,9 +64,22 @@
             main.start();
             Looper.setMainLooperForTest(main.getLooper());
         }
+
+        InstrumentationRegistry.registerInstance(new Instrumentation(), Bundle.EMPTY);
+
+        if (ENABLE_TIMEOUT_STACKS) {
+            sPendingTimeout = sTimeoutExecutor.schedule(RavenwoodRuleImpl::dumpStacks,
+                    TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        }
     }
 
     public static void reset(RavenwoodRule rule) {
+        if (ENABLE_TIMEOUT_STACKS) {
+            sPendingTimeout.cancel(false);
+        }
+
+        InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
+
         if (rule.mProvideMainThread) {
             Looper.getMainLooper().quit();
             Looper.clearMainLooperForTest();
@@ -55,4 +91,19 @@
         android.os.Binder.reset$ravenwood();
         android.os.Process.reset$ravenwood();
     }
+
+    private static void dumpStacks() {
+        final PrintStream out = System.err;
+        out.println("-----BEGIN ALL THREAD STACKS-----");
+        final Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
+        for (Map.Entry<Thread, StackTraceElement[]> stack : stacks.entrySet()) {
+            out.println();
+            Thread t = stack.getKey();
+            out.println(t.toString() + " ID=" + t.getId());
+            for (StackTraceElement e : stack.getValue()) {
+                out.println("\tat " + e);
+            }
+        }
+        out.println("-----END ALL THREAD STACKS-----");
+    }
 }
diff --git a/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
similarity index 74%
rename from ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java
rename to ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
index 2ef381e..4bf0980 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
@@ -23,15 +23,16 @@
 import java.lang.annotation.Target;
 
 /**
- * Tests marked with this annotation are excluded when running under a Ravenwood test environment.
+ * Tests marked with this annotation are disabled when running under a Ravenwood test environment.
  *
  * A more specific method-level annotation always takes precedence over any class-level
- * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over
- * an {@link ExcludeUnderRavenwood} annotation.
+ * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over
+ * an {@link DisabledOnRavenwood} annotation.
  *
  * This annotation only takes effect when the containing class has a {@code
- * RavenwoodRule} configured. Ignoring is accomplished by throwing an {@code org.junit
- * .AssumptionViolatedException} which test infrastructure treats as being ignored.
+ * RavenwoodRule} or {@code RavenwoodClassRule} configured. Ignoring is accomplished by
+ * throwing an {@code org.junit.AssumptionViolatedException} which test infrastructure treats as
+ * being ignored.
  *
  * This annotation has no effect on any other non-Ravenwood test environments.
  *
@@ -40,5 +41,5 @@
 @Inherited
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
-public @interface ExcludeUnderRavenwood {
+public @interface DisabledOnRavenwood {
 }
diff --git a/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java
similarity index 72%
copy from ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java
copy to ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java
index 2ef381e..9dd0a58 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java
@@ -23,15 +23,16 @@
 import java.lang.annotation.Target;
 
 /**
- * Tests marked with this annotation are excluded when running under a Ravenwood test environment.
+ * Tests marked with this annotation are enabled when running under a Ravenwood test environment.
  *
  * A more specific method-level annotation always takes precedence over any class-level
- * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over
- * an {@link ExcludeUnderRavenwood} annotation.
+ * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over
+ * an {@link DisabledOnRavenwood} annotation.
  *
  * This annotation only takes effect when the containing class has a {@code
- * RavenwoodRule} configured. Ignoring is accomplished by throwing an {@code org.junit
- * .AssumptionViolatedException} which test infrastructure treats as being ignored.
+ * RavenwoodRule} or {@code RavenwoodClassRule} configured. Ignoring is accomplished by
+ * throwing an {@code org.junit.AssumptionViolatedException} which test infrastructure treats as
+ * being ignored.
  *
  * This annotation has no effect on any other non-Ravenwood test environments.
  *
@@ -40,5 +41,5 @@
 @Inherited
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
-public @interface ExcludeUnderRavenwood {
+public @interface EnabledOnRavenwood {
 }
diff --git a/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java
deleted file mode 100644
index 0b2e32f..0000000
--- a/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java
+++ /dev/null
@@ -1,44 +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.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Tests marked with this annotation are included when running under a Ravenwood test environment.
- *
- * A more specific method-level annotation always takes precedence over any class-level
- * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over
- * an {@link ExcludeUnderRavenwood} annotation.
- *
- * This annotation only takes effect when the containing class has a {@code
- * RavenwoodRule} configured. Ignoring is accomplished by throwing an {@code org.junit
- * .AssumptionViolatedException} which test infrastructure treats as being ignored.
- *
- * This annotation has no effect on any other non-Ravenwood test environments.
- *
- * @hide
- */
-@Inherited
-@Target({ElementType.METHOD, ElementType.TYPE})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface IncludeUnderRavenwood {
-}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
new file mode 100644
index 0000000..8d76970
--- /dev/null
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
@@ -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 android.platform.test.ravenwood;
+
+import static android.platform.test.ravenwood.RavenwoodRule.ENABLE_PROBE_IGNORED;
+import static android.platform.test.ravenwood.RavenwoodRule.IS_ON_RAVENWOOD;
+import static android.platform.test.ravenwood.RavenwoodRule.shouldEnableOnRavenwood;
+import static android.platform.test.ravenwood.RavenwoodRule.shouldStillIgnoreInProbeIgnoreMode;
+
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.annotations.EnabledOnRavenwood;
+
+import org.junit.Assume;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * {@code @ClassRule} that respects Ravenwood-specific class annotations. This rule has no effect
+ * when tests are run on non-Ravenwood test environments.
+ *
+ * By default, all tests are executed on Ravenwood, but annotations such as
+ * {@link DisabledOnRavenwood} and {@link EnabledOnRavenwood} can be used at both the method
+ * and class level to "ignore" tests that may not be ready.
+ */
+public class RavenwoodClassRule implements TestRule {
+    @Override
+    public Statement apply(Statement base, Description description) {
+        // No special treatment when running outside Ravenwood; run tests as-is
+        if (!IS_ON_RAVENWOOD) {
+            return base;
+        }
+
+        if (ENABLE_PROBE_IGNORED) {
+            Assume.assumeFalse(shouldStillIgnoreInProbeIgnoreMode(description));
+            // Pass through to possible underlying RavenwoodRule for both environment
+            // configuration and handling method-level annotations
+            return base;
+        } else {
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    Assume.assumeTrue(shouldEnableOnRavenwood(description));
+                    // Pass through to possible underlying RavenwoodRule for both environment
+                    // configuration and handling method-level annotations
+                    base.evaluate();
+                }
+            };
+        }
+    }
+}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index dd442f0..1e7cbf6 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -18,41 +18,88 @@
 
 import static org.junit.Assert.fail;
 
-import android.platform.test.annotations.ExcludeUnderRavenwood;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.annotations.EnabledOnRavenwood;
 import android.platform.test.annotations.IgnoreUnderRavenwood;
-import android.platform.test.annotations.IncludeUnderRavenwood;
 
 import org.junit.Assume;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
 
 /**
- * THIS RULE IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
- * QUESTIONS ABOUT IT.
+ * {@code @Rule} that configures the Ravenwood test environment. This rule has no effect when
+ * tests are run on non-Ravenwood test environments.
  *
- * @hide
+ * This rule initializes and resets the Ravenwood environment between each test method to offer a
+ * hermetic testing environment.
+ *
+ * By default, all tests are executed on Ravenwood, but annotations such as
+ * {@link DisabledOnRavenwood} and {@link EnabledOnRavenwood} can be used at both the method
+ * and class level to "ignore" tests that may not be ready. When needed, a
+ * {@link RavenwoodClassRule} can be used in addition to a {@link RavenwoodRule} to ignore tests
+ * before a test class is fully initialized.
  */
 public class RavenwoodRule implements TestRule {
-    private static AtomicInteger sNextPid = new AtomicInteger(100);
-
-    private static final boolean IS_UNDER_RAVENWOOD = RavenwoodRuleImpl.isUnderRavenwood();
+    static final boolean IS_ON_RAVENWOOD = RavenwoodRuleImpl.isOnRavenwood();
 
     /**
-     * When probing is enabled, all tests will be unconditionally run under Ravenwood to detect
+     * When probing is enabled, all tests will be unconditionally run on Ravenwood to detect
      * cases where a test is able to pass despite being marked as {@code IgnoreUnderRavenwood}.
      *
      * This is typically helpful for internal maintainers discovering tests that had previously
      * been ignored, but now have enough Ravenwood-supported functionality to be enabled.
      */
-    private static final boolean ENABLE_PROBE_IGNORED = false; // DO NOT SUBMIT WITH TRUE
+    static final boolean ENABLE_PROBE_IGNORED = "1".equals(
+            System.getenv("RAVENWOOD_RUN_DISABLED_TESTS"));
+
+    /**
+     * When using ENABLE_PROBE_IGNORED, you may still want to skip certain tests,
+     * for example because the test would crash the JVM.
+     *
+     * This regex defines the tests that should still be disabled even if ENABLE_PROBE_IGNORED
+     * is set.
+     *
+     * Before running each test class and method, we check if this pattern can be found in
+     * the full test name (either [class full name], or [class full name] + "#" + [method name]),
+     * and if so, we skip it.
+     *
+     * For example, if you want to skip an entire test class, use:
+     * RAVENWOOD_REALLY_DISABLE='\.CustomTileDefaultsRepositoryTest$'
+     *
+     * For example, if you want to skip an entire test class, use:
+     * RAVENWOOD_REALLY_DISABLE='\.CustomTileDefaultsRepositoryTest#testSimple$'
+     *
+     * To ignore multiple classes, use (...|...), for example:
+     * RAVENWOOD_REALLY_DISABLE='\.(ClassA|ClassB)$'
+     *
+     * Because we use a regex-find, setting "." would disable all tests.
+     */
+    private static final Pattern REALLY_DISABLE_PATTERN = Pattern.compile(
+            Objects.requireNonNullElse(System.getenv("RAVENWOOD_REALLY_DISABLE"), ""));
+
+    private static final boolean ENABLE_REALLY_DISABLE_PATTERN =
+            !REALLY_DISABLE_PATTERN.pattern().isEmpty();
+
+    static {
+        if (ENABLE_PROBE_IGNORED) {
+            System.out.println("$RAVENWOOD_RUN_DISABLED_TESTS enabled: force running all tests");
+            if (ENABLE_REALLY_DISABLE_PATTERN) {
+                System.out.println("$RAVENWOOD_REALLY_DISABLE=" + REALLY_DISABLE_PATTERN.pattern());
+            }
+        }
+    }
 
     private static final int SYSTEM_UID = 1000;
     private static final int NOBODY_UID = 9999;
     private static final int FIRST_APPLICATION_UID = 10000;
 
+    private static final AtomicInteger sNextPid = new AtomicInteger(100);
+
     /**
      * Unless the test author requests differently, run as "nobody", and give each collection of
      * tests its own unique PID.
@@ -75,7 +122,7 @@
 
         /**
          * Configure the identity of this process to be the system UID for the duration of the
-         * test. Has no effect under non-Ravenwood environments.
+         * test. Has no effect on non-Ravenwood environments.
          */
         public Builder setProcessSystem() {
             mRule.mUid = SYSTEM_UID;
@@ -84,7 +131,7 @@
 
         /**
          * Configure the identity of this process to be an app UID for the duration of the
-         * test. Has no effect under non-Ravenwood environments.
+         * test. Has no effect on non-Ravenwood environments.
          */
         public Builder setProcessApp() {
             mRule.mUid = FIRST_APPLICATION_UID;
@@ -93,7 +140,7 @@
 
         /**
          * Configure a "main" thread to be available for the duration of the test, as defined
-         * by {@code Looper.getMainLooper()}. Has no effect under non-Ravenwood environments.
+         * by {@code Looper.getMainLooper()}. Has no effect on non-Ravenwood environments.
          */
         public Builder setProvideMainThread(boolean provideMainThread) {
             mRule.mProvideMainThread = provideMainThread;
@@ -108,7 +155,7 @@
          * All properties in the {@code debug.*} namespace are automatically mutable, with no
          * developer action required.
          *
-         * Has no effect under non-Ravenwood environments.
+         * Has no effect on non-Ravenwood environments.
          */
         public Builder setSystemPropertyImmutable(/* @NonNull */ String key,
                 /* @Nullable */ Object value) {
@@ -125,7 +172,7 @@
          * All properties in the {@code debug.*} namespace are automatically mutable, with no
          * developer action required.
          *
-         * Has no effect under non-Ravenwood environments.
+         * Has no effect on non-Ravenwood environments.
          */
         public Builder setSystemPropertyMutable(/* @NonNull */ String key,
                 /* @Nullable */ Object value) {
@@ -140,42 +187,51 @@
     }
 
     /**
-     * Return if the current process is running under a Ravenwood test environment.
+     * @deprecated replaced by {@link #isOnRavenwood()}
      */
+    @Deprecated
     public static boolean isUnderRavenwood() {
-        return IS_UNDER_RAVENWOOD;
+        return IS_ON_RAVENWOOD;
     }
 
     /**
-     * Determine if the given {@link Description} should be included when running under the
+     * Return if the current process is running on a Ravenwood test environment.
+     */
+    public static boolean isOnRavenwood() {
+        return IS_ON_RAVENWOOD;
+    }
+
+    /**
+     * Determine if the given {@link Description} should be enabled when running on the
      * Ravenwood test environment.
      *
      * A more specific method-level annotation always takes precedence over any class-level
-     * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over
-     * an {@link ExcludeUnderRavenwood} annotation.
+     * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over
+     * an {@link DisabledOnRavenwood} annotation.
      */
-    private boolean shouldIncludeUnderRavenwood(Description description) {
-        // Stopgap for http://g/ravenwood/EPAD-N5ntxM
-        if (description.getMethodName().endsWith("$noRavenwood")) {
-            return false;
-        }
-
+    static boolean shouldEnableOnRavenwood(Description description) {
         // First, consult any method-level annotations
-        if (description.getAnnotation(IncludeUnderRavenwood.class) != null) {
-            return true;
-        }
-        if (description.getAnnotation(ExcludeUnderRavenwood.class) != null) {
-            return false;
-        }
-        if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
-            return false;
+        if (description.isTest()) {
+            // Stopgap for http://g/ravenwood/EPAD-N5ntxM
+            if (description.getMethodName().endsWith("$noRavenwood")) {
+                return false;
+            }
+            if (description.getAnnotation(EnabledOnRavenwood.class) != null) {
+                return true;
+            }
+            if (description.getAnnotation(DisabledOnRavenwood.class) != null) {
+                return false;
+            }
+            if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
+                return false;
+            }
         }
 
         // Otherwise, consult any class-level annotations
-        if (description.getTestClass().getAnnotation(IncludeUnderRavenwood.class) != null) {
+        if (description.getTestClass().getAnnotation(EnabledOnRavenwood.class) != null) {
             return true;
         }
-        if (description.getTestClass().getAnnotation(ExcludeUnderRavenwood.class) != null) {
+        if (description.getTestClass().getAnnotation(DisabledOnRavenwood.class) != null) {
             return false;
         }
         if (description.getTestClass().getAnnotation(IgnoreUnderRavenwood.class) != null) {
@@ -186,10 +242,25 @@
         return true;
     }
 
+    static boolean shouldStillIgnoreInProbeIgnoreMode(Description description) {
+        if (!ENABLE_REALLY_DISABLE_PATTERN) {
+            return false;
+        }
+
+        final var fullname = description.getTestClass().getName()
+                + (description.isTest() ? "#" + description.getMethodName() : "");
+
+        if (REALLY_DISABLE_PATTERN.matcher(fullname).find()) {
+            System.out.println("Still ignoring " + fullname);
+            return true;
+        }
+        return false;
+    }
+
     @Override
     public Statement apply(Statement base, Description description) {
         // No special treatment when running outside Ravenwood; run tests as-is
-        if (!IS_UNDER_RAVENWOOD) {
+        if (!IS_ON_RAVENWOOD) {
             return base;
         }
 
@@ -207,7 +278,7 @@
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                Assume.assumeTrue(shouldIncludeUnderRavenwood(description));
+                Assume.assumeTrue(shouldEnableOnRavenwood(description));
 
                 RavenwoodRuleImpl.init(RavenwoodRule.this);
                 try {
@@ -221,26 +292,27 @@
 
     /**
      * Run the given {@link Statement} with probing enabled. All tests will be unconditionally
-     * run under Ravenwood to detect cases where a test is able to pass despite being marked as
+     * run on Ravenwood to detect cases where a test is able to pass despite being marked as
      * {@code IgnoreUnderRavenwood}.
      */
     private Statement applyProbeIgnored(Statement base, Description description) {
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
+                Assume.assumeFalse(shouldStillIgnoreInProbeIgnoreMode(description));
                 RavenwoodRuleImpl.init(RavenwoodRule.this);
                 try {
                     base.evaluate();
                 } catch (Throwable t) {
                     // If the test isn't included, eat the exception and report the
                     // assumption failure that test authors expect; otherwise throw
-                    Assume.assumeTrue(shouldIncludeUnderRavenwood(description));
+                    Assume.assumeTrue(shouldEnableOnRavenwood(description));
                     throw t;
                 } finally {
                     RavenwoodRuleImpl.reset(RavenwoodRule.this);
                 }
 
-                if (!shouldIncludeUnderRavenwood(description)) {
+                if (!shouldEnableOnRavenwood(description)) {
                     fail("Test wasn't included under Ravenwood, but it actually "
                             + "passed under Ravenwood; consider updating annotations");
                 }
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 0ff6a1a..d0c2e18 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -17,7 +17,7 @@
 package android.platform.test.ravenwood;
 
 public class RavenwoodRuleImpl {
-    public static boolean isUnderRavenwood() {
+    public static boolean isOnRavenwood() {
         return false;
     }
 
diff --git a/ravenwood/mockito/test/com/android/ravenwood/mockito/RavenwoodMockitoTest.java b/ravenwood/mockito/test/com/android/ravenwood/mockito/RavenwoodMockitoTest.java
index 36fa3dd..364a86a 100644
--- a/ravenwood/mockito/test/com/android/ravenwood/mockito/RavenwoodMockitoTest.java
+++ b/ravenwood/mockito/test/com/android/ravenwood/mockito/RavenwoodMockitoTest.java
@@ -22,7 +22,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.platform.test.annotations.IgnoreUnderRavenwood;
 import android.platform.test.ravenwood.RavenwoodRule;
 
 import org.junit.Rule;
@@ -62,31 +61,7 @@
         assertThat(object.exitValue()).isEqualTo(42);
     }
 
-    /*
- - Intent can't be mocked because of the dependency to `org.xmlpull.v1.XmlPullParser`.
-   (The error says "Mockito can only mock non-private & non-final classes", but that's likely a
-   red-herring.)
-
-STACKTRACE:
-org.mockito.exceptions.base.MockitoException:
-Mockito cannot mock this class: class android.content.Intent.
-
-  :
-
-Underlying exception : java.lang.IllegalArgumentException: Could not create type
-    at com.android.ravenwood.mockito.RavenwoodMockitoTest.testMockAndroidClass1
-    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-
-  :
-
-Caused by: java.lang.ClassNotFoundException: org.xmlpull.v1.XmlPullParser
-    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
-    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
-    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
-    ... 54 more
-     */
     @Test
-    @IgnoreUnderRavenwood
     public void testMockAndroidClass1() {
         Intent object = mock(Intent.class);
 
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index eaf01a3..b775f9a 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -72,6 +72,7 @@
 android.os.ServiceSpecificException
 android.os.SystemClock
 android.os.SystemProperties
+android.os.TestLooperManager
 android.os.ThreadLocalWorkSource
 android.os.TimestampedValue
 android.os.Trace
@@ -141,6 +142,8 @@
 
 android.content.ContentProvider
 
+android.app.Instrumentation
+
 android.metrics.LogMaker
 
 android.view.Display$HdrCapabilities
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d656892..63784ba 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.accessibility;
 
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER;
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER_CLIENT;
@@ -30,10 +31,7 @@
 import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID;
 import static android.content.Context.DEVICE_ID_DEFAULT;
 import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
 import static android.view.accessibility.AccessibilityManager.FlashNotificationReason;
-import static android.view.accessibility.AccessibilityManager.ShortcutType;
 
 import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
@@ -142,6 +140,7 @@
 import com.android.internal.accessibility.AccessibilityShortcutController;
 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkFeatureInfo;
 import com.android.internal.accessibility.AccessibilityShortcutController.LaunchableFrameworkFeatureInfo;
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
 import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
 import com.android.internal.accessibility.util.AccessibilityUtils;
@@ -1721,7 +1720,7 @@
         }
         mMainHandler.sendMessage(obtainMessage(
                 AccessibilityManagerService::performAccessibilityShortcutInternal, this,
-                displayId, ACCESSIBILITY_BUTTON, targetName));
+                displayId, ShortcutConstants.UserShortcutType.SOFTWARE, targetName));
     }
 
     /**
@@ -2200,11 +2199,12 @@
     }
 
     private void showAccessibilityTargetsSelection(int displayId,
-            @ShortcutType int shortcutType) {
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         final Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
-        final String chooserClassName = (shortcutType == ACCESSIBILITY_SHORTCUT_KEY)
-                ? AccessibilityShortcutChooserActivity.class.getName()
-                : AccessibilityButtonChooserActivity.class.getName();
+        final String chooserClassName =
+                (shortcutType == ShortcutConstants.UserShortcutType.HARDWARE)
+                        ? AccessibilityShortcutChooserActivity.class.getName()
+                        : AccessibilityButtonChooserActivity.class.getName();
         intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
         final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
@@ -3275,7 +3275,7 @@
         }
 
         final Set<String> currentTargets =
-                userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+                userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.HARDWARE);
         if (targetsFromSetting.equals(currentTargets)) {
             return false;
         }
@@ -3291,7 +3291,7 @@
                 userState.mUserId, str -> str, targetsFromSetting);
 
         final Set<String> currentTargets =
-                userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
+                userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.SOFTWARE);
         if (targetsFromSetting.equals(currentTargets)) {
             return false;
         }
@@ -3346,7 +3346,7 @@
      */
     private void updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState) {
         final Set<String> currentTargets =
-                userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+                userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.HARDWARE);
         final int lastSize = currentTargets.size();
         if (lastSize == 0) {
             return;
@@ -3531,7 +3531,7 @@
         }
 
         final Set<String> currentTargets =
-                userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
+                userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.SOFTWARE);
         final int lastSize = currentTargets.size();
         if (lastSize == 0) {
             return;
@@ -3571,7 +3571,7 @@
             return;
         }
         final Set<String> buttonTargets =
-                userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
+                userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.SOFTWARE);
         int lastSize = buttonTargets.size();
         buttonTargets.removeIf(name -> {
             if (packageName != null && name != null && !name.contains(packageName)) {
@@ -3608,7 +3608,7 @@
         lastSize = buttonTargets.size();
 
         final Set<String> shortcutKeyTargets =
-                userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+                userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.HARDWARE);
         userState.mEnabledServices.forEach(componentName -> {
             if (packageName != null && componentName != null
                     && !packageName.equals(componentName.getPackageName())) {
@@ -3665,16 +3665,18 @@
             return;
         }
         final ComponentName serviceName = service.getComponentName();
-        if (userState.removeShortcutTargetLocked(ACCESSIBILITY_SHORTCUT_KEY, serviceName)) {
+        if (userState.removeShortcutTargetLocked(
+                ShortcutConstants.UserShortcutType.HARDWARE, serviceName)) {
             final Set<String> currentTargets = userState.getShortcutTargetsLocked(
-                    ACCESSIBILITY_SHORTCUT_KEY);
+                    ShortcutConstants.UserShortcutType.HARDWARE);
             persistColonDelimitedSetToSettingLocked(
                     Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
                     userState.mUserId, currentTargets, str -> str);
         }
-        if (userState.removeShortcutTargetLocked(ACCESSIBILITY_BUTTON, serviceName)) {
+        if (userState.removeShortcutTargetLocked(
+                ShortcutConstants.UserShortcutType.SOFTWARE, serviceName)) {
             final Set<String> currentTargets = userState.getShortcutTargetsLocked(
-                    ACCESSIBILITY_BUTTON);
+                    ShortcutConstants.UserShortcutType.SOFTWARE);
             persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
                     userState.mUserId, currentTargets, str -> str);
         }
@@ -3750,7 +3752,7 @@
         }
         mMainHandler.sendMessage(obtainMessage(
                 AccessibilityManagerService::performAccessibilityShortcutInternal, this,
-                Display.DEFAULT_DISPLAY, ACCESSIBILITY_SHORTCUT_KEY, targetName));
+                Display.DEFAULT_DISPLAY, ShortcutConstants.UserShortcutType.HARDWARE, targetName));
     }
 
     /**
@@ -3763,7 +3765,7 @@
      *        specified target.
      */
     private void performAccessibilityShortcutInternal(int displayId,
-            @ShortcutType int shortcutType, @Nullable String targetName) {
+            @ShortcutConstants.UserShortcutType int shortcutType, @Nullable String targetName) {
         final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType);
         if (shortcutTargets.isEmpty()) {
             Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType);
@@ -3814,7 +3816,7 @@
     }
 
     private boolean performAccessibilityFrameworkFeature(int displayId,
-            ComponentName assignedTarget, @ShortcutType int shortcutType) {
+            ComponentName assignedTarget, @ShortcutConstants.UserShortcutType int shortcutType) {
         final Map<ComponentName, FrameworkFeatureInfo> frameworkFeatureMap =
                 AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
         if (!frameworkFeatureMap.containsKey(assignedTarget)) {
@@ -3863,12 +3865,12 @@
     /**
      * Perform accessibility service shortcut action.
      *
-     * 1) For {@link AccessibilityManager#ACCESSIBILITY_BUTTON} type and services targeting sdk
+     * 1) For {@link ShortcutConstants.UserShortcutType.SOFTWARE} type and services targeting sdk
      *    version <= Q: callbacks to accessibility service if service is bounded and requests
      *    accessibility button.
-     * 2) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk
+     * 2) For {@link ShortcutConstants.UserShortcutType.HARDWARE} type and service targeting sdk
      *    version <= Q: turns on / off the accessibility service.
-     * 3) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk
+     * 3) For {@link ShortcutConstants.UserShortcutType.HARDWARE} type and service targeting sdk
      *    version > Q and request accessibility button: turn on the accessibility service if it's
      *    not in the enabled state.
      *    (It'll happen when a service is disabled and assigned to shortcut then upgraded.)
@@ -3879,7 +3881,7 @@
      *       button.
      */
     private boolean performAccessibilityShortcutTargetService(int displayId,
-            @ShortcutType int shortcutType, ComponentName assignedTarget) {
+            @ShortcutConstants.UserShortcutType int shortcutType, ComponentName assignedTarget) {
         synchronized (mLock) {
             final AccessibilityUserState userState = getCurrentUserStateLocked();
             final AccessibilityServiceInfo installedServiceInfo =
@@ -3897,7 +3899,8 @@
             final boolean requestA11yButton = (installedServiceInfo.flags
                     & FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
             // Turns on / off the accessibility service
-            if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == ACCESSIBILITY_SHORTCUT_KEY)
+            if ((targetSdk <= Build.VERSION_CODES.Q
+                    && shortcutType == ShortcutConstants.UserShortcutType.HARDWARE)
                     || (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) {
                 if (serviceConnection == null) {
                     logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
@@ -3911,7 +3914,8 @@
                 }
                 return true;
             }
-            if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY && targetSdk > Build.VERSION_CODES.Q
+            if (shortcutType == ShortcutConstants.UserShortcutType.HARDWARE
+                    && targetSdk > Build.VERSION_CODES.Q
                     && requestA11yButton) {
                 if (!userState.getEnabledServicesLocked().contains(assignedTarget)) {
                     enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
@@ -3941,7 +3945,8 @@
     }
 
     @Override
-    public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
+    public List<String> getAccessibilityShortcutTargets(
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".getAccessibilityShortcutTargets",
                     FLAGS_ACCESSIBILITY_MANAGER, "shortcutType=" + shortcutType);
@@ -3955,12 +3960,13 @@
         return getAccessibilityShortcutTargetsInternal(shortcutType);
     }
 
-    private List<String> getAccessibilityShortcutTargetsInternal(@ShortcutType int shortcutType) {
+    private List<String> getAccessibilityShortcutTargetsInternal(
+            @ShortcutConstants.UserShortcutType int shortcutType) {
         synchronized (mLock) {
             final AccessibilityUserState userState = getCurrentUserStateLocked();
             final ArrayList<String> shortcutTargets = new ArrayList<>(
                     userState.getShortcutTargetsLocked(shortcutType));
-            if (shortcutType != ACCESSIBILITY_BUTTON) {
+            if (shortcutType != ShortcutConstants.UserShortcutType.SOFTWARE) {
                 return shortcutTargets;
             }
             // Adds legacy a11y services requesting a11y button into the list.
@@ -4423,7 +4429,7 @@
             }
         }
         // Warning is not required if the service is already assigned to a shortcut.
-        for (int shortcutType : AccessibilityManager.SHORTCUT_TYPES) {
+        for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
             if (getAccessibilityShortcutTargets(shortcutType).contains(
                     componentName.flattenToString())) {
                 return false;
@@ -4603,8 +4609,8 @@
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
             ResultReceiver resultReceiver) {
-        new AccessibilityShellCommand(this, mSystemActionPerformer).exec(this, in, out, err, args,
-                callback, resultReceiver);
+        new AccessibilityShellCommand(this, mSystemActionPerformer)
+                .exec(this, in, out, err, args, callback, resultReceiver);
     }
 
     private final class InteractionBridge {
@@ -5719,6 +5725,21 @@
     }
 
     @Override
+    public void attachAccessibilityOverlayToDisplay_enforcePermission(
+            int displayId, SurfaceControl sc) {
+        mContext.enforceCallingPermission(
+                INTERNAL_SYSTEM_WINDOW, "attachAccessibilityOverlayToDisplay_enforcePermission");
+        mMainHandler.sendMessage(
+                obtainMessage(
+                        AccessibilityManagerService::attachAccessibilityOverlayToDisplayInternal,
+                        this,
+                        -1,
+                        displayId,
+                        sc,
+                        null));
+    }
+
+    @Override
     public void attachAccessibilityOverlayToDisplay(
             int interactionId,
             int displayId,
@@ -5754,12 +5775,15 @@
             t.close();
             result = AccessibilityService.OVERLAY_RESULT_SUCCESS;
         }
-        // Send the result back to the service.
-        try {
-            callback.sendAttachOverlayResult(result, interactionId);
-        } catch (RemoteException re) {
-            Slog.e(LOG_TAG, "Exception while attaching overlay.", re);
-            // the other side will time out
+
+        if (callback != null) {
+            // Send the result back to the service.
+            try {
+                callback.sendAttachOverlayResult(result, interactionId);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Exception while attaching overlay.", re);
+                // the other side will time out
+            }
         }
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 68ee780..41165b6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -24,9 +24,6 @@
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK;
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-import static android.view.accessibility.AccessibilityManager.ShortcutType;
 
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
 
@@ -51,6 +48,7 @@
 
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.accessibility.common.ShortcutConstants;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -757,13 +755,21 @@
      * @param shortcutType The shortcut type.
      * @return The array set of the strings
      */
-    public ArraySet<String> getShortcutTargetsLocked(@ShortcutType int shortcutType) {
-        if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+    public ArraySet<String> getShortcutTargetsLocked(
+            @ShortcutConstants.UserShortcutType int shortcutType) {
+        if (shortcutType == ShortcutConstants.UserShortcutType.HARDWARE) {
             return mAccessibilityShortcutKeyTargets;
-        } else if (shortcutType == ACCESSIBILITY_BUTTON) {
+        } else if (shortcutType == ShortcutConstants.UserShortcutType.SOFTWARE) {
             return mAccessibilityButtonTargets;
+        } else if ((shortcutType == ShortcutConstants.UserShortcutType.TRIPLETAP
+                && isMagnificationSingleFingerTripleTapEnabledLocked()) || (
+                shortcutType == ShortcutConstants.UserShortcutType.TWO_FINGERS_TRIPLE_TAP
+                        && isMagnificationTwoFingerTripleTapEnabledLocked())) {
+            ArraySet<String> targets = new ArraySet<>();
+            targets.add(MAGNIFICATION_CONTROLLER_NAME);
+            return targets;
         }
-        return null;
+        return new ArraySet<>();
     }
 
     /**
@@ -802,12 +808,22 @@
     /**
      * Removes given shortcut target in the list.
      *
-     * @param shortcutType The shortcut type.
-     * @param target The component name of the shortcut target.
+     * @param shortcutType one of {@link ShortcutConstants.UserShortcutType.HARDWARE} or
+     *                     {@link ShortcutConstants.UserShortcutType.SOFTWARE}. Other types are not
+     *                     implemented.
+     * @param target       The component name of the shortcut target.
      * @return true if the shortcut target is removed.
      */
-    public boolean removeShortcutTargetLocked(@ShortcutType int shortcutType,
+    public boolean removeShortcutTargetLocked(@ShortcutConstants.UserShortcutType int shortcutType,
             ComponentName target) {
+        if (shortcutType == ShortcutConstants.UserShortcutType.TRIPLETAP
+                || shortcutType == ShortcutConstants.UserShortcutType.TWO_FINGERS_TRIPLE_TAP) {
+            throw new UnsupportedOperationException(
+                    "removeShortcutTargetLocked only support shortcut type: "
+                            + "software and hardware for now"
+            );
+        }
+
         return getShortcutTargetsLocked(shortcutType).removeIf(name -> {
             ComponentName componentName;
             if (name == null
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 5c93991..f914ed5 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -31,9 +31,12 @@
 import android.os.ICancellationSignal;
 import android.os.RemoteException;
 import android.service.autofill.AutofillService;
+import android.service.autofill.ConvertCredentialRequest;
+import android.service.autofill.ConvertCredentialResponse;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
+import android.service.autofill.IConvertCredentialCallback;
 import android.service.autofill.IFillCallback;
 import android.service.autofill.ISaveCallback;
 import android.service.autofill.SaveRequest;
@@ -69,6 +72,7 @@
     private int mPendingFillRequestId = INVALID_REQUEST_ID;
     private AtomicReference<IFillCallback> mFillCallback;
     private AtomicReference<ISaveCallback> mSaveCallback;
+    private AtomicReference<IConvertCredentialCallback> mConvertCredentialCallback;
     private final ComponentName mComponentName;
 
     private final boolean mIsCredentialAutofillService;
@@ -81,13 +85,20 @@
             extends AbstractRemoteService.VultureCallback<RemoteFillService> {
         void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
                 @NonNull String servicePackageName, int requestFlags);
+
         void onFillRequestFailure(int requestId, @Nullable CharSequence message);
+
         void onFillRequestTimeout(int requestId);
+
         void onSaveRequestSuccess(@NonNull String servicePackageName,
                 @Nullable IntentSender intentSender);
+
         // TODO(b/80093094): add timeout here too?
         void onSaveRequestFailure(@Nullable CharSequence message,
                 @NonNull String servicePackageName);
+
+        void onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse
+                convertCredentialResponse);
     }
 
     RemoteFillService(Context context, ComponentName componentName, int userId,
@@ -211,6 +222,32 @@
         }
     }
 
+    static class IConvertCredentialCallbackDelegate extends IConvertCredentialCallback.Stub {
+
+        private WeakReference<IConvertCredentialCallback> mCallbackWeakRef;
+
+        IConvertCredentialCallbackDelegate(IConvertCredentialCallback callback) {
+            mCallbackWeakRef = new WeakReference(callback);
+        }
+
+        @Override
+        public void onSuccess(ConvertCredentialResponse convertCredentialResponse)
+                throws RemoteException {
+            IConvertCredentialCallback callback = mCallbackWeakRef.get();
+            if (callback != null) {
+                callback.onSuccess(convertCredentialResponse);
+            }
+        }
+
+        @Override
+        public void onFailure(CharSequence message) throws RemoteException {
+            IConvertCredentialCallback callback = mCallbackWeakRef.get();
+            if (callback != null) {
+                callback.onFailure(message);
+            }
+        }
+    }
+
     /**
      * Wraps an {@link IFillCallback} object using weak reference.
      *
@@ -237,6 +274,18 @@
         return callback;
     }
 
+    /**
+     * Wraps an {@link IConvertCredentialCallback} object using weak reference
+     */
+    private IConvertCredentialCallback maybeWrapWithWeakReference(
+            IConvertCredentialCallback callback) {
+        if (remoteFillServiceUseWeakReference()) {
+            mConvertCredentialCallback = new AtomicReference<>(callback);
+            return new IConvertCredentialCallbackDelegate(callback);
+        }
+        return callback;
+    }
+
     public void onFillCredentialRequest(@NonNull FillRequest request,
             IAutoFillManagerClient autofillCallback) {
         if (sVerbose) {
@@ -378,6 +427,52 @@
         }));
     }
 
+    public void onConvertCredentialRequest(
+            @NonNull ConvertCredentialRequest convertCredentialRequest) {
+        if (sVerbose) Slog.v(TAG, "calling onConvertCredentialRequest()");
+        CompletableFuture<ConvertCredentialResponse>
+                connectThenConvertCredentialRequest = postAsync(
+                    remoteService -> {
+                        if (sVerbose) {
+                            Slog.v(TAG, "calling onConvertCredentialRequest()");
+                        }
+                        CompletableFuture<ConvertCredentialResponse>
+                                convertCredentialCompletableFuture = new CompletableFuture<>();
+                        remoteService.onConvertCredentialRequest(convertCredentialRequest,
+                                maybeWrapWithWeakReference(
+                                        new IConvertCredentialCallback.Stub() {
+                                            @Override
+                                            public void onSuccess(ConvertCredentialResponse
+                                                    convertCredentialResponse) {
+                                                convertCredentialCompletableFuture
+                                                        .complete(convertCredentialResponse);
+                                            }
+
+                                            @Override
+                                            public void onFailure(CharSequence message) {
+                                                String errorMessage =
+                                                        message == null ? "" :
+                                                                    String.valueOf(message);
+                                                convertCredentialCompletableFuture
+                                                        .completeExceptionally(
+                                                            new RuntimeException(errorMessage));
+                                            }
+                                        })
+                        );
+                        return convertCredentialCompletableFuture;
+                    }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
+
+        connectThenConvertCredentialRequest.whenComplete(
+                (res, err) -> Handler.getMain().post(() -> {
+                    if (err == null) {
+                        mCallbacks.onConvertCredentialRequestSuccess(res);
+                    } else {
+                        // TODO: Add a callback function to log this failure
+                        Slog.e(TAG, "Error calling on convert credential request", err);
+                    }
+                }));
+    }
+
     public void onSaveRequest(@NonNull SaveRequest request) {
         postAsync(service -> {
             if (sVerbose) Slog.v(TAG, "calling onSaveRequest()");
diff --git a/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
index 1234703..0af703e 100644
--- a/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
+++ b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.IntentSender;
 import android.os.Bundle;
+import android.service.autofill.ConvertCredentialResponse;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
 import android.util.Slog;
@@ -98,6 +99,12 @@
 
     }
 
+    @Override
+    public void  onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse
+            convertCredentialResponse) {
+
+    }
+
     /**
      * Requests a new fill response.
      */
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f3b74ea..049feee 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -24,6 +24,7 @@
 import static android.service.autofill.Dataset.PICK_REASON_PROVIDER_DETECTION_ONLY;
 import static android.service.autofill.Dataset.PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC;
 import static android.service.autofill.Dataset.PICK_REASON_UNKNOWN;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_CREDMAN_BOTTOM_SHEET;
 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
@@ -44,6 +45,7 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 import static android.view.autofill.AutofillManager.COMMIT_REASON_SESSION_DESTROYED;
 import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN;
+import static android.view.autofill.AutofillManager.EXTRA_AUTOFILL_REQUEST_ID;
 import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
 import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
 
@@ -130,6 +132,7 @@
 import android.service.autofill.AutofillFieldClassificationService.Scores;
 import android.service.autofill.AutofillService;
 import android.service.autofill.CompositeUserData;
+import android.service.autofill.ConvertCredentialResponse;
 import android.service.autofill.Dataset;
 import android.service.autofill.Dataset.DatasetEligibleReason;
 import android.service.autofill.Field;
@@ -2429,6 +2432,29 @@
         removeFromService();
     }
 
+    // FillServiceCallbacks
+    @Override
+    public void onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse
+            convertCredentialResponse) {
+        Dataset dataset = convertCredentialResponse.getDataset();
+        Bundle clientState = convertCredentialResponse.getClientState();
+        if (dataset != null) {
+            int requestId = -1;
+            if (clientState != null) {
+                requestId = clientState.getInt(EXTRA_AUTOFILL_REQUEST_ID);
+            } else {
+                Slog.e(TAG, "onConvertCredentialRequestSuccess(): client state is null, this "
+                        + "would cause loss in logging.");
+            }
+            // TODO: Add autofill related logging; consider whether to log the index
+            fill(requestId, /* datasetIndex=*/ -1, dataset, UI_TYPE_CREDMAN_BOTTOM_SHEET);
+        } else {
+            // TODO: Add logging to log this error case
+            Slog.e(TAG, "onConvertCredentialRequestSuccess(): dataset inside response is "
+                    + "null");
+        }
+    }
+
     /**
      * Gets the {@link FillContext} for a request.
      *
diff --git a/services/backup/flags.aconfig b/services/backup/flags.aconfig
index 4022e33..1416c88 100644
--- a/services/backup/flags.aconfig
+++ b/services/backup/flags.aconfig
@@ -11,7 +11,7 @@
 
 flag {
     name: "enable_metrics_system_backup_agents"
-    namespace: "backup"
+    namespace: "onboarding"
     description: "Enable SystemBackupAgent to collect B&R agent metrics by passing an instance of "
             "the logger to each BackupHelper."
     bug: "296844513"
diff --git a/services/companion/TEST_MAPPING b/services/companion/TEST_MAPPING
index 37c47ba..ae6d591 100644
--- a/services/companion/TEST_MAPPING
+++ b/services/companion/TEST_MAPPING
@@ -9,5 +9,10 @@
     {
       "name": "CtsCompanionDeviceManagerNoCompanionServicesTestCases"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "CtsCompanionDeviceManagerMultiProcessTestCases"
+    }
   ]
 }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 2e01ced..5019428 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -368,8 +368,10 @@
 
         if (blueToothDevices != null) {
             for (BluetoothDevice bluetoothDevice : blueToothDevices) {
-                final List<ParcelUuid> deviceUuids = bluetoothDevice.getUuids() == null
-                        ? Collections.emptyList() : Arrays.asList(bluetoothDevice.getUuids());
+                final ParcelUuid[] bluetoothDeviceUuids = bluetoothDevice.getUuids();
+
+                final List<ParcelUuid> deviceUuids = ArrayUtils.isEmpty(bluetoothDeviceUuids)
+                        ? Collections.emptyList() : Arrays.asList(bluetoothDeviceUuids);
 
                 for (AssociationInfo ai:
                         mAssociationStore.getAssociationsByAddress(bluetoothDevice.getAddress())) {
diff --git a/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java b/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
index 3482863..aac628c 100644
--- a/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
+++ b/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
@@ -36,7 +36,8 @@
  * will be killed if association/role are revoked.
  */
 public class InactiveAssociationsRemovalService extends JobService {
-    private static final int JOB_ID = InactiveAssociationsRemovalService.class.hashCode();
+    private static final String JOB_NAMESPACE = "companion";
+    private static final int JOB_ID = 1;
     private static final long ONE_DAY_INTERVAL = DAYS.toMillis(1);
 
     @Override
@@ -61,7 +62,8 @@
 
     static void schedule(Context context) {
         Slog.i(TAG, "Scheduling the Association Removal job");
-        final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+        final JobScheduler jobScheduler =
+                context.getSystemService(JobScheduler.class).forNamespace(JOB_NAMESPACE);
         final JobInfo job = new JobInfo.Builder(JOB_ID,
                 new ComponentName(context, InactiveAssociationsRemovalService.class))
                 .setRequiresCharging(true)
@@ -71,4 +73,3 @@
         jobScheduler.schedule(job);
     }
 }
-
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index 7eca119..c514f3e 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -38,6 +38,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.companion.AssociationStore;
 import com.android.server.companion.ObservableUuid;
 import com.android.server.companion.ObservableUuidStore;
@@ -172,8 +173,10 @@
                 mAssociationStore.getAssociationsByAddress(device.getAddress());
         final List<ObservableUuid> observableUuids =
                 mObservableUuidStore.getObservableUuidsForUser(userId);
-        final List<ParcelUuid> deviceUuids = device.getUuids() == null
-                ? Collections.emptyList() : Arrays.asList(device.getUuids());
+        final ParcelUuid[] bluetoothDeviceUuids = device.getUuids();
+
+        final List<ParcelUuid> deviceUuids = ArrayUtils.isEmpty(bluetoothDeviceUuids)
+                ? Collections.emptyList() : Arrays.asList(bluetoothDeviceUuids);
 
         if (DEBUG) {
             Log.d(TAG, "onDevice_ConnectivityChanged() " + btDeviceToString(device)
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index 3b9d92d..8962bf0 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -163,7 +163,7 @@
         createDeviceInternal(InputDeviceDescriptor.TYPE_MOUSE, deviceName, vendorId, productId,
                 deviceToken, displayId, phys,
                 () -> mNativeWrapper.openUinputMouse(deviceName, vendorId, productId, phys));
-        mInputManagerInternal.setVirtualMousePointerDisplayId(displayId);
+        setVirtualMousePointerDisplayId(displayId);
     }
 
     void createTouchscreen(@NonNull String deviceName, int vendorId, int productId,
@@ -235,8 +235,7 @@
         // id if there's another mouse (choose the most recent). The inputDeviceDescriptor must be
         // removed from the mInputDeviceDescriptors instance variable prior to this point.
         if (inputDeviceDescriptor.isMouse()) {
-            if (mInputManagerInternal.getVirtualMousePointerDisplayId()
-                    == inputDeviceDescriptor.getDisplayId()) {
+            if (getVirtualMousePointerDisplayId() == inputDeviceDescriptor.getDisplayId()) {
                 updateActivePointerDisplayIdLocked();
             }
         }
@@ -271,6 +270,7 @@
         mWindowManager.setDisplayImePolicy(displayId, policy);
     }
 
+    // TODO(b/293587049): Remove after pointer icon refactor is complete.
     @GuardedBy("mLock")
     private void updateActivePointerDisplayIdLocked() {
         InputDeviceDescriptor mostRecentlyCreatedMouse = null;
@@ -285,11 +285,11 @@
             }
         }
         if (mostRecentlyCreatedMouse != null) {
-            mInputManagerInternal.setVirtualMousePointerDisplayId(
+            setVirtualMousePointerDisplayId(
                     mostRecentlyCreatedMouse.getDisplayId());
         } else {
             // All mice have been unregistered
-            mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY);
+            setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY);
         }
     }
 
@@ -349,10 +349,8 @@
             if (inputDeviceDescriptor == null) {
                 return false;
             }
-            if (inputDeviceDescriptor.getDisplayId()
-                    != mInputManagerInternal.getVirtualMousePointerDisplayId()) {
-                mInputManagerInternal.setVirtualMousePointerDisplayId(
-                        inputDeviceDescriptor.getDisplayId());
+            if (inputDeviceDescriptor.getDisplayId() != getVirtualMousePointerDisplayId()) {
+                setVirtualMousePointerDisplayId(inputDeviceDescriptor.getDisplayId());
             }
             return mNativeWrapper.writeButtonEvent(inputDeviceDescriptor.getNativePointer(),
                     event.getButtonCode(), event.getAction(), event.getEventTimeNanos());
@@ -380,10 +378,8 @@
             if (inputDeviceDescriptor == null) {
                 return false;
             }
-            if (inputDeviceDescriptor.getDisplayId()
-                    != mInputManagerInternal.getVirtualMousePointerDisplayId()) {
-                mInputManagerInternal.setVirtualMousePointerDisplayId(
-                        inputDeviceDescriptor.getDisplayId());
+            if (inputDeviceDescriptor.getDisplayId() != getVirtualMousePointerDisplayId()) {
+                setVirtualMousePointerDisplayId(inputDeviceDescriptor.getDisplayId());
             }
             return mNativeWrapper.writeRelativeEvent(inputDeviceDescriptor.getNativePointer(),
                     event.getRelativeX(), event.getRelativeY(), event.getEventTimeNanos());
@@ -397,10 +393,8 @@
             if (inputDeviceDescriptor == null) {
                 return false;
             }
-            if (inputDeviceDescriptor.getDisplayId()
-                    != mInputManagerInternal.getVirtualMousePointerDisplayId()) {
-                mInputManagerInternal.setVirtualMousePointerDisplayId(
-                        inputDeviceDescriptor.getDisplayId());
+            if (inputDeviceDescriptor.getDisplayId() != getVirtualMousePointerDisplayId()) {
+                setVirtualMousePointerDisplayId(inputDeviceDescriptor.getDisplayId());
             }
             return mNativeWrapper.writeScrollEvent(inputDeviceDescriptor.getNativePointer(),
                     event.getXAxisMovement(), event.getYAxisMovement(), event.getEventTimeNanos());
@@ -415,12 +409,11 @@
                 throw new IllegalArgumentException(
                         "Could not get cursor position for input device for given token");
             }
-            if (inputDeviceDescriptor.getDisplayId()
-                    != mInputManagerInternal.getVirtualMousePointerDisplayId()) {
-                mInputManagerInternal.setVirtualMousePointerDisplayId(
-                        inputDeviceDescriptor.getDisplayId());
+            if (inputDeviceDescriptor.getDisplayId() != getVirtualMousePointerDisplayId()) {
+                setVirtualMousePointerDisplayId(inputDeviceDescriptor.getDisplayId());
             }
-            return LocalServices.getService(InputManagerInternal.class).getCursorPosition();
+            return LocalServices.getService(InputManagerInternal.class).getCursorPosition(
+                    inputDeviceDescriptor.getDisplayId());
         }
     }
 
@@ -847,4 +840,22 @@
         /** Returns true if the calling thread is a valid thread for device creation. */
         boolean isValidThread();
     }
+
+    // TODO(b/293587049): Remove after pointer icon refactor is complete.
+    private void setVirtualMousePointerDisplayId(int displayId) {
+        if (com.android.input.flags.Flags.enablePointerChoreographer()) {
+            // We no longer need to set the pointer display when pointer choreographer is enabled.
+            return;
+        }
+        mInputManagerInternal.setVirtualMousePointerDisplayId(displayId);
+    }
+
+    // TODO(b/293587049): Remove after pointer icon refactor is complete.
+    private int getVirtualMousePointerDisplayId() {
+        if (com.android.input.flags.Flags.enablePointerChoreographer()) {
+            // We no longer need to get the pointer display when pointer choreographer is enabled.
+            return Display.INVALID_DISPLAY;
+        }
+        return mInputManagerInternal.getVirtualMousePointerDisplayId();
+    }
 }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a54a48a..8e35b74 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -139,6 +139,7 @@
 
     libs: [
         "services.net",
+        "android.frameworks.location.altitude-V2-java",
         "android.hardware.common-V2-java",
         "android.hardware.light-V2.0-java",
         "android.hardware.gnss-V2-java",
@@ -160,7 +161,6 @@
     ],
 
     static_libs: [
-        "android.frameworks.location.altitude-V2-java", // AIDL
         "android.frameworks.vibrator-V1-java", // AIDL
         "android.hardware.authsecret-V1.0-java",
         "android.hardware.authsecret-V1-java",
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index b87184a..416b36f 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -288,22 +288,23 @@
                         CachedDeviceState.Readonly.class);
                 mBinderCallsStats.setDeviceState(deviceState);
 
-                BatteryStatsInternal batteryStatsInternal = getLocalService(
-                        BatteryStatsInternal.class);
-                mBinderCallsStats.setCallStatsObserver(new BinderInternal.CallStatsObserver() {
-                    @Override
-                    public void noteCallStats(int workSourceUid, long incrementalCallCount,
-                            Collection<BinderCallsStats.CallStat> callStats) {
-                        batteryStatsInternal.noteBinderCallStats(workSourceUid,
-                                incrementalCallCount, callStats);
-                    }
+                if (!com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+                    BatteryStatsInternal batteryStatsInternal = getLocalService(
+                            BatteryStatsInternal.class);
+                    mBinderCallsStats.setCallStatsObserver(new BinderInternal.CallStatsObserver() {
+                        @Override
+                        public void noteCallStats(int workSourceUid, long incrementalCallCount,
+                                Collection<BinderCallsStats.CallStat> callStats) {
+                            batteryStatsInternal.noteBinderCallStats(workSourceUid,
+                                    incrementalCallCount, callStats);
+                        }
 
-                    @Override
-                    public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
-                        batteryStatsInternal.noteBinderThreadNativeIds(binderThreadNativeTids);
-                    }
-                });
-
+                        @Override
+                        public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
+                            batteryStatsInternal.noteBinderThreadNativeIds(binderThreadNativeTids);
+                        }
+                    });
+                }
                 // It needs to be called before mService.systemReady to make sure the observer is
                 // initialized before installing it.
                 mWorkSourceProvider.systemReady(getContext());
diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
index c391642..f619ca3 100644
--- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
+++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
@@ -49,12 +50,12 @@
     private static final String TAG = "SensitiveContentProtect";
     private static final boolean DEBUG = false;
 
-    @VisibleForTesting
-    NotificationListener mNotificationListener;
+    @VisibleForTesting NotificationListener mNotificationListener;
     private @Nullable MediaProjectionManager mProjectionManager;
     private @Nullable WindowManagerInternal mWindowManager;
 
     final Object mSensitiveContentProtectionLock = new Object();
+
     @GuardedBy("mSensitiveContentProtectionLock")
     private boolean mProjectionActive = false;
 
@@ -63,13 +64,24 @@
                 @Override
                 public void onStart(MediaProjectionInfo info) {
                     if (DEBUG) Log.d(TAG, "onStart projection: " + info);
-                    onProjectionStart();
+                    Trace.beginSection(
+                            "SensitiveContentProtectionManagerService.onProjectionStart");
+                    try {
+                        onProjectionStart();
+                    } finally {
+                        Trace.endSection();
+                    }
                 }
 
                 @Override
                 public void onStop(MediaProjectionInfo info) {
                     if (DEBUG) Log.d(TAG, "onStop projection: " + info);
-                    onProjectionEnd();
+                    Trace.beginSection("SensitiveContentProtectionManagerService.onProjectionStop");
+                    try {
+                        onProjectionEnd();
+                    } finally {
+                        Trace.endSection();
+                    }
                 }
             };
 
@@ -94,8 +106,7 @@
     }
 
     @VisibleForTesting
-    void init(MediaProjectionManager projectionManager,
-            WindowManagerInternal windowManager) {
+    void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager) {
         if (DEBUG) Log.d(TAG, "init");
 
         checkNotNull(projectionManager, "Failed to get valid MediaProjectionManager");
@@ -109,7 +120,8 @@
         mProjectionManager.addCallback(mProjectionCallback, new Handler(Looper.getMainLooper()));
 
         try {
-            mNotificationListener.registerAsSystemService(getContext(),
+            mNotificationListener.registerAsSystemService(
+                    getContext(),
                     new ComponentName(getContext(), NotificationListener.class),
                     UserHandle.USER_ALL);
         } catch (RemoteException e) {
@@ -174,8 +186,8 @@
         }
 
         // notify windowmanager of any currently posted sensitive content notifications
-        ArraySet<PackageInfo> packageInfos = getSensitivePackagesFromNotifications(
-                notifications, rankingMap);
+        ArraySet<PackageInfo> packageInfos =
+                getSensitivePackagesFromNotifications(notifications, rankingMap);
 
         mWindowManager.addBlockScreenCaptureForApps(packageInfos);
     }
@@ -197,8 +209,8 @@
         return sensitivePackages;
     }
 
-    private PackageInfo getSensitivePackageFromNotification(StatusBarNotification sbn,
-            RankingMap rankingMap) {
+    private PackageInfo getSensitivePackageFromNotification(
+            StatusBarNotification sbn, RankingMap rankingMap) {
         if (sbn == null) {
             Log.w(TAG, "Unable to protect null notification");
             return null;
@@ -220,38 +232,55 @@
         @Override
         public void onListenerConnected() {
             super.onListenerConnected();
-            // Projection started before notification listener was connected
-            synchronized (mSensitiveContentProtectionLock) {
-                if (mProjectionActive) {
-                    updateAppsThatShouldBlockScreenCapture();
+            Trace.beginSection("SensitiveContentProtectionManagerService.onListenerConnected");
+            try {
+                // Projection started before notification listener was connected
+                synchronized (mSensitiveContentProtectionLock) {
+                    if (mProjectionActive) {
+                        updateAppsThatShouldBlockScreenCapture();
+                    }
                 }
+            } finally {
+                Trace.endSection();
             }
         }
 
         @Override
         public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
             super.onNotificationPosted(sbn, rankingMap);
-            synchronized (mSensitiveContentProtectionLock) {
-                if (!mProjectionActive) {
-                    return;
-                }
+            Trace.beginSection("SensitiveContentProtectionManagerService.onNotificationPosted");
+            try {
+                synchronized (mSensitiveContentProtectionLock) {
+                    if (!mProjectionActive) {
+                        return;
+                    }
 
-                // notify windowmanager of any currently posted sensitive content notifications
-                PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap);
+                    // notify windowmanager of any currently posted sensitive content notifications
+                    PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap);
 
-                if (packageInfo != null) {
-                    mWindowManager.addBlockScreenCaptureForApps(new ArraySet(Set.of(packageInfo)));
+                    if (packageInfo != null) {
+                        mWindowManager.addBlockScreenCaptureForApps(
+                                new ArraySet(Set.of(packageInfo)));
+                    }
                 }
+            } finally {
+                Trace.endSection();
             }
         }
 
         @Override
         public void onNotificationRankingUpdate(RankingMap rankingMap) {
             super.onNotificationRankingUpdate(rankingMap);
-            synchronized (mSensitiveContentProtectionLock) {
-                if (mProjectionActive) {
-                    updateAppsThatShouldBlockScreenCapture(rankingMap);
+            Trace.beginSection(
+                    "SensitiveContentProtectionManagerService.onNotificationRankingUpdate");
+            try {
+                synchronized (mSensitiveContentProtectionLock) {
+                    if (mProjectionActive) {
+                        updateAppsThatShouldBlockScreenCapture(rankingMap);
+                    }
                 }
+            } finally {
+                Trace.endSection();
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index afb8345..adc0255 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -181,7 +181,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.ServiceInfo.ForegroundServiceType;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
@@ -306,6 +305,57 @@
     @interface FgsStopReason {}
 
     /**
+     * The policy to be applied to the service bindings; this one means it follows the legacy
+     * behavior.
+     */
+    static final int SERVICE_BIND_OOMADJ_POLICY_LEGACY = 0;
+
+    /**
+     * The policy to be applied to the service bindings; this one means we'll skip
+     * updating the target process's oom adj score / process state for its {@link Service#onCreate}.
+     */
+    static final int SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE = 1;
+
+    /**
+     * The policy to be applied to the service bindings; this one means we'll skip
+     * updating the target process's oom adj score / process state for its {@link Service#onBind}.
+     */
+    static final int SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND = 1 << 1;
+
+    /**
+     * The policy to be applied to the service bindings; this one means we'll skip
+     * updating the target process's oom adj score / process state on setting up the service
+     * connection between the client and the service host process.
+     */
+    static final int SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT = 1 << 2;
+    /**
+     * The policy to be applied to the service bindings; this one means the caller
+     * will be frozen upon calling the bindService APIs.
+     */
+    static final int SERVICE_BIND_OOMADJ_POLICY_FREEZE_CALLER = 1 << 3;
+
+    @IntDef(flag = true, prefix = { "SERVICE_BIND_OOMADJ_POLICY_" }, value = {
+            SERVICE_BIND_OOMADJ_POLICY_LEGACY,
+            SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE,
+            SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND,
+            SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT,
+            SERVICE_BIND_OOMADJ_POLICY_FREEZE_CALLER,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ServiceBindingOomAdjPolicy {}
+
+    @ServiceBindingOomAdjPolicy
+    static final int DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG =
+            SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE
+            | SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND
+            | SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT;
+
+    @ServiceBindingOomAdjPolicy
+    static final int DEFAULT_SERVICE_CACHED_BIND_POLICY_FLAG =
+            SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE
+            | SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND;
+
+    /**
      * Disables foreground service background starts from BOOT_COMPLETED broadcasts for all types
      * except:
      * <ul>
@@ -1244,7 +1294,7 @@
                             @Override
                             public void onResult(Bundle result) {
                                 synchronized (mAm) {
-                                    final long identity = Binder.clearCallingIdentity();
+                                    final long identity = mAm.mInjector.clearCallingIdentity();
                                     try {
                                         if (!mPendingServices.contains(r)) {
                                             return;
@@ -1263,7 +1313,8 @@
                                                         false /* whileRestarting */,
                                                         false /* permissionsReviewRequired */,
                                                         false /* packageFrozen */,
-                                                        true /* enqueueOomAdj */);
+                                                        true /* enqueueOomAdj */,
+                                                        SERVICE_BIND_OOMADJ_POLICY_LEGACY);
                                             } catch (RemoteException e) {
                                                 /* ignore - local call */
                                             } finally {
@@ -1275,7 +1326,7 @@
                                             unbindServiceLocked(connection);
                                         }
                                     } finally {
-                                        Binder.restoreCallingIdentity(identity);
+                                        mAm.mInjector.restoreCallingIdentity(identity);
                                     }
                                 }
                             }
@@ -1353,7 +1404,8 @@
                                     false /* whileRestarting */,
                                     false /* permissionsReviewRequired */,
                                     false /* packageFrozen */,
-                                    true /* enqueueOomAdj */);
+                                    true /* enqueueOomAdj */,
+                                    SERVICE_BIND_OOMADJ_POLICY_LEGACY);
                         } catch (TransactionTooLargeException e) {
                             /* ignore - local call */
                         } finally {
@@ -1431,7 +1483,8 @@
                 false /* whileRestarting */,
                 false /* permissionsReviewRequired */,
                 false /* packageFrozen */,
-                true /* enqueueOomAdj */);
+                true /* enqueueOomAdj */,
+                SERVICE_BIND_OOMADJ_POLICY_LEGACY);
         /* Will be a no-op if nothing pending */
         mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE);
         if (error != null) {
@@ -1550,22 +1603,22 @@
         if (caller != null && callerApp == null) {
             throw new SecurityException(
                     "Unable to find app for caller " + caller
-                    + " (pid=" + Binder.getCallingPid()
+                    + " (pid=" + mAm.mInjector.getCallingPid()
                     + ") when stopping service " + service);
         }
 
         // If this service is active, make sure it is stopped.
         ServiceLookupResult r = retrieveServiceLocked(service, instanceName, isSdkSandboxService,
                 sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, null,
-                Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false,
-                null, false, false);
+                mAm.mInjector.getCallingPid(), mAm.mInjector.getCallingUid(),
+                userId, false, false, false, false, null, false, false);
         if (r != null) {
             if (r.record != null) {
-                final long origId = Binder.clearCallingIdentity();
+                final long origId = mAm.mInjector.clearCallingIdentity();
                 try {
                     stopServiceLocked(r.record, false);
                 } finally {
-                    Binder.restoreCallingIdentity(origId);
+                    mAm.mInjector.restoreCallingIdentity(origId);
                 }
                 return 1;
             }
@@ -1649,7 +1702,7 @@
 
     IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
         ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, callingPackage,
-                Binder.getCallingPid(), Binder.getCallingUid(),
+                mAm.mInjector.getCallingPid(), mAm.mInjector.getCallingUid(),
                 UserHandle.getCallingUserId(), false, false, false, false, false, false);
 
         IBinder ret = null;
@@ -1658,8 +1711,8 @@
             if (r.record == null) {
                 throw new SecurityException(
                         "Permission Denial: Accessing service"
-                        + " from pid=" + Binder.getCallingPid()
-                        + ", uid=" + Binder.getCallingUid()
+                        + " from pid=" + mAm.mInjector.getCallingPid()
+                        + ", uid=" + mAm.mInjector.getCallingUid()
                         + " requires " + r.permission);
             }
             IntentBindRecord ib = r.record.bindings.get(r.record.intent);
@@ -1719,9 +1772,9 @@
                 }
             }
             r.callStart = false;
-            final long origId = Binder.clearCallingIdentity();
+            final long origId = mAm.mInjector.clearCallingIdentity();
             bringDownServiceIfNeededLocked(r, false, false, false, "stopServiceToken");
-            Binder.restoreCallingIdentity(origId);
+            mAm.mInjector.restoreCallingIdentity(origId);
             return true;
         }
         return false;
@@ -1734,14 +1787,14 @@
     public void setServiceForegroundLocked(ComponentName className, IBinder token,
             int id, Notification notification, int flags, int foregroundServiceType) {
         final int userId = UserHandle.getCallingUserId();
-        final long origId = Binder.clearCallingIdentity();
+        final long origId = mAm.mInjector.clearCallingIdentity();
         try {
             ServiceRecord r = findServiceLocked(className, token, userId);
             if (r != null) {
                 setServiceForegroundInnerLocked(r, id, notification, flags, foregroundServiceType);
             }
         } finally {
-            Binder.restoreCallingIdentity(origId);
+            mAm.mInjector.restoreCallingIdentity(origId);
         }
     }
 
@@ -1753,7 +1806,7 @@
      */
     public int getForegroundServiceTypeLocked(ComponentName className, IBinder token) {
         final int userId = UserHandle.getCallingUserId();
-        final long origId = Binder.clearCallingIdentity();
+        final long origId = mAm.mInjector.clearCallingIdentity();
         int ret = ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
         try {
             ServiceRecord r = findServiceLocked(className, token, userId);
@@ -1761,7 +1814,7 @@
                 ret = r.foregroundServiceType;
             }
         } finally {
-            Binder.restoreCallingIdentity(origId);
+            mAm.mInjector.restoreCallingIdentity(origId);
         }
         return ret;
     }
@@ -3483,7 +3536,7 @@
 
     boolean shouldServiceTimeOutLocked(ComponentName className, IBinder token) {
         final int userId = UserHandle.getCallingUserId();
-        final long ident = Binder.clearCallingIdentity();
+        final long ident = mAm.mInjector.clearCallingIdentity();
         try {
             ServiceRecord sr = findServiceLocked(className, token, userId);
             if (sr == null) {
@@ -3492,7 +3545,7 @@
             final long nowUptime = SystemClock.uptimeMillis();
             return sr.shouldTriggerShortFgsTimeout(nowUptime);
         } finally {
-            Binder.restoreCallingIdentity(ident);
+            mAm.mInjector.restoreCallingIdentity(ident);
         }
     }
 
@@ -3636,8 +3689,8 @@
         if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
                 + " type=" + resolvedType + " conn=" + connection.asBinder()
                 + " flags=0x" + Long.toHexString(flags));
-        final int callingPid = Binder.getCallingPid();
-        final int callingUid = Binder.getCallingUid();
+        final int callingPid = mAm.mInjector.getCallingPid();
+        final int callingUid = mAm.mInjector.getCallingUid();
         final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller);
         if (callerApp == null) {
             throw new SecurityException(
@@ -3778,7 +3831,7 @@
                 && !requestStartTargetPermissionsReviewIfNeededLocked(s, callingPackage, null,
                         callingUid, service, callerFg, userId, true, connection);
 
-        final long origId = Binder.clearCallingIdentity();
+        final long origId = mAm.mInjector.clearCallingIdentity();
 
         try {
             if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
@@ -3859,12 +3912,34 @@
             }
             clist.add(c);
 
+            final boolean isolated = (s.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
+            final ProcessRecord hostApp = isolated
+                    ? null
+                    : mAm.getProcessRecordLocked(s.processName, s.appInfo.uid);
+            final int serviceBindingOomAdjPolicy = hostApp != null
+                    ? getServiceBindingOomAdjPolicyForAddLocked(b.client, hostApp, c)
+                    : SERVICE_BIND_OOMADJ_POLICY_LEGACY;
+
+            final boolean shouldFreezeCaller = !packageFrozen && !permissionsReviewRequired
+                    && (serviceBindingOomAdjPolicy & SERVICE_BIND_OOMADJ_POLICY_FREEZE_CALLER) != 0
+                    && callerApp.isFreezable();
+
+            if (shouldFreezeCaller) {
+                // Freeze the caller immediately, so the following #onBind/#onConnected will be
+                // queued up in the app side as they're one way calls. And we'll also hold off
+                // the service timeout timer until the process is unfrozen.
+                mAm.mOomAdjuster.updateAppFreezeStateLSP(callerApp, OOM_ADJ_REASON_BIND_SERVICE,
+                        true);
+            }
+
             boolean needOomAdj = false;
             if (c.hasFlag(Context.BIND_AUTO_CREATE)) {
                 s.lastActivity = SystemClock.uptimeMillis();
-                needOomAdj = true;
+                needOomAdj = (serviceBindingOomAdjPolicy
+                        & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE) == 0;
                 if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
-                        permissionsReviewRequired, packageFrozen, true) != null) {
+                        permissionsReviewRequired, packageFrozen, true, serviceBindingOomAdjPolicy)
+                        != null) {
                     mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_BIND_SERVICE);
                     return 0;
                 }
@@ -3886,8 +3961,11 @@
                         || (callerApp.mState.getCurProcState() <= PROCESS_STATE_TOP
                             && c.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)),
                         b.client);
-                needOomAdj = true;
-                mAm.enqueueOomAdjTargetLocked(s.app);
+                if ((serviceBindingOomAdjPolicy
+                        & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) == 0) {
+                    needOomAdj = true;
+                    mAm.enqueueOomAdjTargetLocked(s.app);
+                }
             }
             if (needOomAdj) {
                 mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_BIND_SERVICE);
@@ -3937,10 +4015,12 @@
                 // and the service had previously asked to be told when
                 // rebound, then do so.
                 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
-                    requestServiceBindingLocked(s, b.intent, callerFg, true);
+                    requestServiceBindingLocked(s, b.intent, callerFg, true,
+                            serviceBindingOomAdjPolicy);
                 }
             } else if (!b.intent.requested) {
-                requestServiceBindingLocked(s, b.intent, callerFg, false);
+                requestServiceBindingLocked(s, b.intent, callerFg, false,
+                        serviceBindingOomAdjPolicy);
             }
 
             maybeLogBindCrossProfileService(userId, callingPackage, callerApp.info.uid);
@@ -3948,7 +4028,7 @@
             getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
 
         } finally {
-            Binder.restoreCallingIdentity(origId);
+            mAm.mInjector.restoreCallingIdentity(origId);
         }
 
         notifyBindingServiceEventLocked(callerApp, callingPackage);
@@ -3982,7 +4062,7 @@
     }
 
     void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
-        final long origId = Binder.clearCallingIdentity();
+        final long origId = mAm.mInjector.clearCallingIdentity();
         try {
             if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                     + " " + intent + ": " + service);
@@ -4025,10 +4105,11 @@
                 }
 
                 serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false,
-                        OOM_ADJ_REASON_EXECUTING_SERVICE);
+                        !Flags.serviceBindingOomAdjPolicy() || b == null || !b.mSkippedOomAdj
+                        ? OOM_ADJ_REASON_EXECUTING_SERVICE : OOM_ADJ_REASON_NONE);
             }
         } finally {
-            Binder.restoreCallingIdentity(origId);
+            mAm.mInjector.restoreCallingIdentity(origId);
         }
     }
 
@@ -4078,8 +4159,8 @@
             return false;
         }
 
-        final int callingPid = Binder.getCallingPid();
-        final long origId = Binder.clearCallingIdentity();
+        final int callingPid = mAm.mInjector.getCallingPid();
+        final long origId = mAm.mInjector.clearCallingIdentity();
         try {
             if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                 String info;
@@ -4092,9 +4173,10 @@
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "unbindServiceLocked: " + info);
             }
 
+            boolean needOomAdj = false;
             while (clist.size() > 0) {
                 ConnectionRecord r = clist.get(0);
-                removeConnectionLocked(r, null, null, true);
+                int serviceBindingOomAdjPolicy = removeConnectionLocked(r, null, null, true);
                 if (clist.size() > 0 && clist.get(0) == r) {
                     // In case it didn't get removed above, do it now.
                     Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
@@ -4112,22 +4194,28 @@
                         psr.setTreatLikeActivity(true);
                         mAm.updateLruProcessLocked(app, true, null);
                     }
-                    mAm.enqueueOomAdjTargetLocked(app);
+                    // If the bindee is more important than the binder, we may skip the OomAdjuster.
+                    if (serviceBindingOomAdjPolicy == SERVICE_BIND_OOMADJ_POLICY_LEGACY) {
+                        mAm.enqueueOomAdjTargetLocked(app);
+                        needOomAdj = true;
+                    }
                 }
             }
 
-            mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_UNBIND_SERVICE);
+            if (needOomAdj) {
+                mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_UNBIND_SERVICE);
+            }
 
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-            Binder.restoreCallingIdentity(origId);
+            mAm.mInjector.restoreCallingIdentity(origId);
         }
 
         return true;
     }
 
     void unbindFinishedLocked(ServiceRecord r, Intent intent, boolean doRebind) {
-        final long origId = Binder.clearCallingIdentity();
+        final long origId = mAm.mInjector.clearCallingIdentity();
         try {
             if (r != null) {
                 Intent.FilterComparison filter
@@ -4138,6 +4226,7 @@
                         + (b != null ? b.apps.size() : 0));
 
                 boolean inDestroying = mDestroyingServices.contains(r);
+                boolean skipOomAdj = false;
                 if (b != null) {
                     if (b.apps.size() > 0 && !inDestroying) {
                         // Applications have already bound since the last
@@ -4152,7 +4241,8 @@
                             }
                         }
                         try {
-                            requestServiceBindingLocked(r, b, inFg, true);
+                            requestServiceBindingLocked(r, b, inFg, true,
+                                    SERVICE_BIND_OOMADJ_POLICY_LEGACY);
                         } catch (TransactionTooLargeException e) {
                             // Don't pass this back to ActivityThread, it's unrelated.
                         }
@@ -4161,13 +4251,14 @@
                         // a new client.
                         b.doRebind = true;
                     }
+                    skipOomAdj = Flags.serviceBindingOomAdjPolicy() && b.mSkippedOomAdj;
                 }
 
                 serviceDoneExecutingLocked(r, inDestroying, false, false,
-                        OOM_ADJ_REASON_UNBIND_SERVICE);
+                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
             }
         } finally {
-            Binder.restoreCallingIdentity(origId);
+            mAm.mInjector.restoreCallingIdentity(origId);
         }
     }
 
@@ -4503,7 +4594,7 @@
                         userId = 0;
                         smap = getServiceMapLocked(0);
                         // Bypass INTERACT_ACROSS_USERS permission check
-                        final long token = Binder.clearCallingIdentity();
+                        final long token = mAm.mInjector.clearCallingIdentity();
                         try {
                             ResolveInfo rInfoForUserId0 =
                                     mAm.getPackageManagerInternal().resolveService(service,
@@ -4516,7 +4607,7 @@
                             }
                             sInfo = rInfoForUserId0.serviceInfo;
                         } finally {
-                            Binder.restoreCallingIdentity(token);
+                            mAm.mInjector.restoreCallingIdentity(token);
                         }
                     }
                     sInfo = new ServiceInfo(sInfo);
@@ -4645,7 +4736,8 @@
      * @return {@code true} if it performed oomAdjUpdate.
      */
     private boolean bumpServiceExecutingLocked(
-            ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason) {
+            ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason,
+            boolean skipTimeoutIfPossible) {
         if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
                 + why + " of " + r + " in app " + r.app);
         else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
@@ -4669,6 +4761,10 @@
             timeoutNeeded = false;
         }
 
+        // If the process is frozen or to be frozen, and we want to skip the timeout, skip it.
+        final boolean shouldSkipTimeout = skipTimeoutIfPossible && r.app != null
+                && (r.app.mOptRecord.isPendingFreeze() || r.app.mOptRecord.isFrozen());
+
         ProcessServiceRecord psr;
         if (r.executeNesting == 0) {
             r.executeFg = fg;
@@ -4684,7 +4780,11 @@
                 psr.startExecutingService(r);
                 psr.setExecServicesFg(psr.shouldExecServicesFg() || fg);
                 if (timeoutNeeded && psr.numberOfExecutingServices() == 1) {
-                    scheduleServiceTimeoutLocked(r.app);
+                    if (!shouldSkipTimeout) {
+                        scheduleServiceTimeoutLocked(r.app);
+                    } else {
+                        r.app.mServices.noteScheduleServiceTimeoutPending(true);
+                    }
                 }
             }
         } else if (r.app != null && fg) {
@@ -4692,7 +4792,11 @@
             if (!psr.shouldExecServicesFg()) {
                 psr.setExecServicesFg(true);
                 if (timeoutNeeded) {
-                    scheduleServiceTimeoutLocked(r.app);
+                    if (!shouldSkipTimeout) {
+                        scheduleServiceTimeoutLocked(r.app);
+                    } else {
+                        r.app.mServices.noteScheduleServiceTimeoutPending(true);
+                    }
                 }
             }
         }
@@ -4712,16 +4816,22 @@
     }
 
     private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
-            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
+            boolean execInFg, boolean rebind,
+            @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
+            throws TransactionTooLargeException {
         if (r.app == null || r.app.getThread() == null) {
             // If service is not currently running, can't yet bind.
             return false;
         }
         if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
                 + " rebind=" + rebind);
+        final boolean skipOomAdj = (serviceBindingOomAdjPolicy
+                & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND) != 0;
         if ((!i.requested || rebind) && i.apps.size() > 0) {
             try {
-                bumpServiceExecutingLocked(r, execInFg, "bind", OOM_ADJ_REASON_BIND_SERVICE);
+                i.mSkippedOomAdj = !bumpServiceExecutingLocked(r, execInFg, "bind",
+                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_BIND_SERVICE,
+                        skipOomAdj /* skipTimeoutIfPossible */);
                 if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                     Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestServiceBinding="
                             + i.intent.getIntent() + ". bindSeq=" + mBindServiceSeqCounter);
@@ -4738,14 +4848,14 @@
                 if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
                 final boolean inDestroying = mDestroyingServices.contains(r);
                 serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
-                        OOM_ADJ_REASON_UNBIND_SERVICE);
+                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
                 throw e;
             } catch (RemoteException e) {
                 if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                 // Keep the executeNesting count accurate.
                 final boolean inDestroying = mDestroyingServices.contains(r);
                 serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
-                        OOM_ADJ_REASON_UNBIND_SERVICE);
+                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
                 return false;
             }
         }
@@ -5117,7 +5227,7 @@
         }
         try {
             bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false,
-                    false, true);
+                    false, true, SERVICE_BIND_OOMADJ_POLICY_LEGACY);
         } catch (TransactionTooLargeException e) {
             // Ignore, it's been logged and nothing upstack cares.
         } finally {
@@ -5217,7 +5327,7 @@
 
     private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
             boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
-            boolean enqueueOomAdj)
+            boolean enqueueOomAdj, @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
             throws TransactionTooLargeException {
         try {
             if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
@@ -5225,7 +5335,8 @@
                         "bringUpServiceLocked: " + r.shortInstanceName);
             }
             return bringUpServiceInnerLocked(r, intentFlags, execInFg, whileRestarting,
-                    permissionsReviewRequired, packageFrozen, enqueueOomAdj);
+                    permissionsReviewRequired, packageFrozen, enqueueOomAdj,
+                    serviceBindingOomAdjPolicy);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
@@ -5233,7 +5344,7 @@
 
     private String bringUpServiceInnerLocked(ServiceRecord r, int intentFlags, boolean execInFg,
             boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
-            boolean enqueueOomAdj)
+            boolean enqueueOomAdj, @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
             throws TransactionTooLargeException {
         if (r.app != null && r.app.isThreadReady()) {
             sendServiceArgsLocked(r, execInFg, false);
@@ -5317,7 +5428,7 @@
                         app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode,
                                 mAm.mProcessStats);
                         realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
-                                enqueueOomAdj);
+                                enqueueOomAdj, serviceBindingOomAdjPolicy);
                         return null;
                     } catch (TransactionTooLargeException e) {
                         throw e;
@@ -5347,7 +5458,7 @@
                                         "realStartServiceLocked: " + r.shortInstanceName);
                             }
                             realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
-                                    enqueueOomAdj);
+                                    enqueueOomAdj, SERVICE_BIND_OOMADJ_POLICY_LEGACY);
                             return null;
                         } catch (TransactionTooLargeException e) {
                             throw e;
@@ -5452,16 +5563,61 @@
         return HostingRecord.TRIGGER_TYPE_UNKNOWN;
     }
 
-    private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
+    private void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg,
+            @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
             throws TransactionTooLargeException {
         for (int i=r.bindings.size()-1; i>=0; i--) {
             IntentBindRecord ibr = r.bindings.valueAt(i);
-            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
+            if (!requestServiceBindingLocked(r, ibr, execInFg, false, serviceBindingOomAdjPolicy)) {
                 break;
             }
         }
     }
 
+    @ServiceBindingOomAdjPolicy
+    private int getServiceBindingOomAdjPolicyForAddLocked(ProcessRecord clientApp,
+            ProcessRecord hostApp, ConnectionRecord cr) {
+        @ServiceBindingOomAdjPolicy int policy = SERVICE_BIND_OOMADJ_POLICY_LEGACY;
+        if (Flags.serviceBindingOomAdjPolicy() && clientApp != null && hostApp != null) {
+            if (clientApp == hostApp) {
+                policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+            } else if (clientApp.isCached()) {
+                policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+                if (clientApp.isFreezable()) {
+                    policy |= SERVICE_BIND_OOMADJ_POLICY_FREEZE_CALLER;
+                }
+            }
+            if ((policy & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) == 0) {
+                // Binding between two different processes.
+                // Check if the caller has a better process state, oom adj score,
+                // or if the caller has more capabilities.
+                if (!mAm.mOomAdjuster.evaluateServiceConnectionAdd(clientApp, hostApp, cr)) {
+                    // Running an oom adjuster won't be give the host app a better score, skip it.
+                    policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+                }
+            }
+        }
+        return policy;
+    }
+
+    @ServiceBindingOomAdjPolicy
+    private int getServiceBindingOomAdjPolicyForRemovalLocked(ProcessRecord clientApp,
+            ProcessRecord hostApp, ConnectionRecord cr) {
+        @ServiceBindingOomAdjPolicy int policy = SERVICE_BIND_OOMADJ_POLICY_LEGACY;
+        if (Flags.serviceBindingOomAdjPolicy() && clientApp != null && hostApp != null
+                && cr != null) {
+            if (clientApp == hostApp) {
+                policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+            } else {
+                if (!mAm.mOomAdjuster.evaluateServiceConnectionRemoval(clientApp, hostApp, cr)) {
+                    // Running an oom adjuster won't be give the host app a better score, skip it.
+                    policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+                }
+            }
+        }
+        return policy;
+    }
+
     /**
      * Note the name of this method should not be confused with the started services concept.
      * The "start" here means bring up the instance in the client, and this method is called
@@ -5469,7 +5625,8 @@
      */
     private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
             IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
-            boolean enqueueOomAdj) throws RemoteException {
+            boolean enqueueOomAdj, @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
+            throws RemoteException {
         if (thread == null) {
             throw new RemoteException();
         }
@@ -5478,17 +5635,28 @@
                     + ", ProcessRecord.uid = " + app.uid);
         r.setProcess(app, thread, pid, uidRecord);
         r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
-
+        final boolean skipOomAdj = (serviceBindingOomAdjPolicy
+                & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE) != 0;
         final ProcessServiceRecord psr = app.mServices;
         final boolean newService = psr.startService(r);
         bumpServiceExecutingLocked(r, execInFg, "create",
-                OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */);
+                OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */,
+                skipOomAdj /* skipTimeoutIfPossible */);
         mAm.updateLruProcessLocked(app, false, null);
         updateServiceForegroundLocked(psr, /* oomAdj= */ false);
-        // Force an immediate oomAdjUpdate, so the client app could be in the correct process state
-        // before doing any service related transactions
-        mAm.enqueueOomAdjTargetLocked(app);
-        mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE);
+        // Skip the oom adj update if it's a self-binding, the Service#onCreate() will be running
+        // at its current adj score.
+        if (!skipOomAdj) {
+            // Force an immediate oomAdjUpdate, so the host app could be in the correct
+            // process state before doing any service related transactions
+            mAm.enqueueOomAdjTargetLocked(app);
+            mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE);
+        } else {
+            // Since we skipped the oom adj update, the Service#onCreate() might be running in
+            // the cached state, if the service process drops into the cached state after the call.
+            // But there is still a grace period before freezing it, so we should be fine
+            // in terms of not getting an ANR.
+        }
 
         boolean created = false;
         try {
@@ -5523,7 +5691,7 @@
                 // Keep the executeNesting count accurate.
                 final boolean inDestroying = mDestroyingServices.contains(r);
                 serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
-                        OOM_ADJ_REASON_STOP_SERVICE);
+                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_STOP_SERVICE);
 
                 // Cleanup.
                 if (newService) {
@@ -5542,7 +5710,7 @@
             psr.mAllowlistManager = true;
         }
 
-        requestServiceBindingsLocked(r, execInFg);
+        requestServiceBindingsLocked(r, execInFg, serviceBindingOomAdjPolicy);
 
         updateServiceClientActivitiesLocked(psr, null, true);
 
@@ -5610,7 +5778,8 @@
                     UserHandle.getAppId(r.appInfo.uid)
             );
             bumpServiceExecutingLocked(r, execInFg, "start",
-                    OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */);
+                    OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */,
+                    false /* skipTimeoutIfPossible */);
             if (r.fgRequired && !r.fgWaiting) {
                 if (!r.isForeground) {
                     if (DEBUG_BACKGROUND_CHECK) {
@@ -5753,7 +5922,8 @@
                 if (ibr.hasBound) {
                     try {
                         oomAdjusted |= bumpServiceExecutingLocked(r, false, "bring down unbind",
-                                OOM_ADJ_REASON_UNBIND_SERVICE);
+                                OOM_ADJ_REASON_UNBIND_SERVICE,
+                                false /* skipTimeoutIfPossible */);
                         ibr.hasBound = false;
                         ibr.requested = false;
                         r.app.getThread().scheduleUnbindService(r,
@@ -5909,7 +6079,8 @@
                 } else {
                     try {
                         oomAdjusted |= bumpServiceExecutingLocked(r, false, "destroy",
-                                oomAdjusted ? 0 : OOM_ADJ_REASON_STOP_SERVICE);
+                                oomAdjusted ? 0 : OOM_ADJ_REASON_STOP_SERVICE,
+                                false /* skipTimeoutIfPossible */);
                         mDestroyingServices.add(r);
                         r.destroying = true;
                         r.app.getThread().scheduleStopService(r);
@@ -5992,11 +6163,17 @@
         }
     }
 
-    void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
+    /**
+     * @return The ServiceBindingOomAdjPolicy used in this removal.
+     */
+    @ServiceBindingOomAdjPolicy
+    int removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
             ActivityServiceConnectionsHolder skipAct, boolean enqueueOomAdj) {
         IBinder binder = c.conn.asBinder();
         AppBindRecord b = c.binding;
         ServiceRecord s = b.service;
+        @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy =
+                SERVICE_BIND_OOMADJ_POLICY_LEGACY;
         ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
         if (clist != null) {
             clist.remove(c);
@@ -6055,8 +6232,14 @@
                     + ": shouldUnbind=" + b.intent.hasBound);
             if (s.app != null && s.app.isThreadReady() && b.intent.apps.size() == 0
                     && b.intent.hasBound) {
+                serviceBindingOomAdjPolicy = getServiceBindingOomAdjPolicyForRemovalLocked(b.client,
+                        s.app, c);
+                final boolean skipOomAdj = (serviceBindingOomAdjPolicy
+                        & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) != 0;
                 try {
-                    bumpServiceExecutingLocked(s, false, "unbind", OOM_ADJ_REASON_UNBIND_SERVICE);
+                    b.intent.mSkippedOomAdj = !bumpServiceExecutingLocked(s, false, "unbind",
+                            skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE,
+                            skipOomAdj /* skipTimeoutIfPossible */);
                     if (b.client != s.app && c.notHasFlag(Context.BIND_WAIVE_PRIORITY)
                             && s.app.mState.getSetProcState() <= PROCESS_STATE_HEAVY_WEIGHT) {
                         // If this service's process is not already in the cached list,
@@ -6096,12 +6279,14 @@
                         "removeConnection");
             }
         }
+        return serviceBindingOomAdjPolicy;
     }
 
     void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res,
-            boolean enqueueOomAdj) {
+            boolean enqueueOomAdj, Intent intent) {
         boolean inDestroying = mDestroyingServices.contains(r);
         if (r != null) {
+            boolean skipOomAdj = false;
             if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
                 // This is a call from a service start...  take care of
                 // book-keeping.
@@ -6177,14 +6362,19 @@
                     // Fake it to keep from ANR due to orphaned entry.
                     r.executeNesting = 1;
                 }
+            } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_REBIND
+                    || type == ActivityThread.SERVICE_DONE_EXECUTING_UNBIND) {
+                final Intent.FilterComparison filter = new Intent.FilterComparison(intent);
+                final IntentBindRecord b = r.bindings.get(filter);
+                skipOomAdj = Flags.serviceBindingOomAdjPolicy() && b != null && b.mSkippedOomAdj;
             }
-            final long origId = Binder.clearCallingIdentity();
+            final long origId = mAm.mInjector.clearCallingIdentity();
             serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj,
-                    OOM_ADJ_REASON_EXECUTING_SERVICE);
-            Binder.restoreCallingIdentity(origId);
+                    skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_EXECUTING_SERVICE);
+            mAm.mInjector.restoreCallingIdentity(origId);
         } else {
             Slog.w(TAG, "Done executing unknown service from pid "
-                    + Binder.getCallingPid());
+                    + mAm.mInjector.getCallingPid());
         }
     }
 
@@ -6236,10 +6426,17 @@
                     mDestroyingServices.remove(r);
                     r.bindings.clear();
                 }
-                if (enqueueOomAdj) {
-                    mAm.enqueueOomAdjTargetLocked(r.app);
+                boolean oomAdjusted = false;
+                if (oomAdjReason != OOM_ADJ_REASON_NONE) {
+                    if (enqueueOomAdj) {
+                        mAm.enqueueOomAdjTargetLocked(r.app);
+                    } else {
+                        mAm.updateOomAdjLocked(r.app, oomAdjReason);
+                    }
+                    oomAdjusted = true;
                 } else {
-                    mAm.updateOomAdjLocked(r.app, oomAdjReason);
+                    // Skip oom adj if it wasn't bumped during the bumpServiceExecutingLocked()
+                    oomAdjusted = false;
                 }
             }
             r.executeFg = false;
@@ -6296,7 +6493,7 @@
                                     "realStartServiceLocked: " + sr.shortInstanceName);
                         }
                         realStartServiceLocked(sr, proc, thread, pid, uidRecord, sr.createdFromFg,
-                                true);
+                                true, SERVICE_BIND_OOMADJ_POLICY_LEGACY);
                     } finally {
                         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     }
@@ -6786,6 +6983,7 @@
         }
 
         psr.stopAllExecutingServices();
+        psr.noteScheduleServiceTimeoutPending(false);
     }
 
     ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
@@ -6836,7 +7034,7 @@
         ArrayList<ActivityManager.RunningServiceInfo> res
                 = new ArrayList<ActivityManager.RunningServiceInfo>();
 
-        final long ident = Binder.clearCallingIdentity();
+        final long ident = mAm.mInjector.clearCallingIdentity();
         try {
             if (canInteractAcrossUsers) {
                 int[] users = mAm.mUserController.getUsers();
@@ -6878,14 +7076,14 @@
                 }
             }
         } finally {
-            Binder.restoreCallingIdentity(ident);
+            mAm.mInjector.restoreCallingIdentity(ident);
         }
 
         return res;
     }
 
     public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
-        int userId = UserHandle.getUserId(Binder.getCallingUid());
+        int userId = UserHandle.getUserId(mAm.mInjector.getCallingUid());
         ServiceRecord r = getServiceByNameLocked(name, userId);
         if (r != null) {
             ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
@@ -7077,6 +7275,7 @@
         final long delay = proc.mServices.shouldExecServicesFg()
                 ? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT;
         mActiveServiceAnrTimer.start(proc, delay);
+        proc.mServices.noteScheduleServiceTimeoutPending(false);
     }
 
     void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ca04e41..374a17a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -135,6 +135,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH;
 import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED;
+import static com.android.sdksandbox.flags.Flags.sdkSandboxInstrumentationInfo;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
@@ -1751,7 +1752,7 @@
     @GuardedBy("mProcLock")
     private long mLastBinderHeavyHitterAutoSamplerStart = 0L;
 
-    final AppProfiler mAppProfiler;
+    AppProfiler mAppProfiler;
 
     private static final int INDEX_NATIVE_PSS = 0;
     private static final int INDEX_NATIVE_SWAP_PSS = 1;
@@ -2496,7 +2497,7 @@
         mInjector = injector;
         mContext = mInjector.getContext();
         mUiContext = null;
-        mAppErrors = null;
+        mAppErrors = injector.getAppErrors();
         mPackageWatchdog = null;
         mAppOpsService = mInjector.getAppOpsService(null /* recentAccessesFile */,
             null /* storageFile */, null /* handler */);
@@ -2514,7 +2515,7 @@
                 ? new OomAdjusterModernImpl(this, mProcessList, activeUids, handlerThread)
                 : new OomAdjuster(this, mProcessList, activeUids, handlerThread);
 
-        mIntentFirewall = null;
+        mIntentFirewall = injector.getIntentFirewall();
         mProcessStats = new ProcessStatsService(this, mContext.getCacheDir());
         mCpHelper = new ContentProviderHelper(this, false);
         mServices = mInjector.getActiveServices(this);
@@ -13889,13 +13890,15 @@
         }
     }
 
-    public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
+    @Override
+    public void serviceDoneExecuting(IBinder token, int type, int startId, int res, Intent intent) {
         synchronized(this) {
             if (!(token instanceof ServiceRecord)) {
                 Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
                 throw new IllegalArgumentException("Invalid service token");
             }
-            mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res, false);
+            mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res, false,
+                    intent);
         }
     }
 
@@ -16139,10 +16142,22 @@
         }
 
         final ApplicationInfo sdkSandboxInfo;
+        final String processName;
         try {
-            sdkSandboxInfo =
-                    sandboxManagerLocal.getSdkSandboxApplicationInfoForInstrumentation(
-                            sdkSandboxClientAppInfo, isSdkInSandbox);
+            if (sdkSandboxInstrumentationInfo()) {
+                sdkSandboxInfo =
+                        sandboxManagerLocal.getSdkSandboxApplicationInfoForInstrumentation(
+                                sdkSandboxClientAppInfo, isSdkInSandbox);
+                processName = sdkSandboxInfo.processName;
+            } else {
+                final PackageManager pm = mContext.getPackageManager();
+                sdkSandboxInfo =
+                        pm.getApplicationInfoAsUser(pm.getSdkSandboxPackageName(), 0, userId);
+                processName =
+                        sandboxManagerLocal.getSdkSandboxProcessNameForInstrumentation(
+                                sdkSandboxClientAppInfo);
+                sdkSandboxInfo.uid = Process.toSdkSandboxUid(sdkSandboxClientAppInfo.uid);
+            }
         } catch (NameNotFoundException e) {
             reportStartInstrumentationFailureLocked(
                     watcher, className, "Can't find SdkSandbox package");
@@ -16151,7 +16166,7 @@
 
         ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
         activeInstr.mClass = className;
-        activeInstr.mTargetProcesses = new String[]{sdkSandboxInfo.processName};
+        activeInstr.mTargetProcesses = new String[]{processName};
         activeInstr.mTargetInfo = sdkSandboxInfo;
         activeInstr.mIsSdkInSandbox = isSdkInSandbox;
         activeInstr.mProfileFile = profileFile;
@@ -16194,7 +16209,7 @@
 
                 ProcessRecord app = addAppLocked(
                         sdkSandboxInfo,
-                        sdkSandboxInfo.processName,
+                        processName,
                         /* isolated= */ false,
                         /* isSdkSandbox= */ true,
                         sdkSandboxInfo.uid,
@@ -20236,6 +20251,36 @@
             }
             return broadcastQueues;
         }
+
+        /** @see Binder#getCallingUid */
+        public int getCallingUid() {
+            return Binder.getCallingUid();
+        }
+
+        /** @see Binder#getCallingPid */
+        public int getCallingPid() {
+            return Binder.getCallingUid();
+        }
+
+        /** @see Binder#clearCallingIdentity */
+        public long clearCallingIdentity() {
+            return Binder.clearCallingIdentity();
+        }
+
+        /** @see Binder#clearCallingIdentity */
+        public void restoreCallingIdentity(long ident) {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        /** @return the default instance of AppErrors */
+        public AppErrors getAppErrors() {
+            return null;
+        }
+
+        /** @return the default instance of intent firewall */
+        public IntentFirewall getIntentFirewall() {
+            return null;
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
index b07d9a6..9c2e69b 100644
--- a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
@@ -520,7 +520,7 @@
         /**
          * Default value to {@link #mTrackerEnabled}.
          */
-        static final boolean DEFAULT_BG_BATTERY_EXEMPTION_ENABLED = true;
+        static final boolean DEFAULT_BG_BATTERY_EXEMPTION_ENABLED = false;
 
         AppBatteryExemptionPolicy(@NonNull Injector injector,
                 @NonNull AppBatteryExemptionTracker tracker) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3487ae3..4f46ecd 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -422,7 +422,9 @@
         mStats.setExternalStatsSyncLocked(mWorker);
         mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
-        mStats.startTrackingSystemServerCpuTime();
+        if (!Flags.disableSystemServicePowerAttr()) {
+            mStats.startTrackingSystemServerCpuTime();
+        }
 
         mAggregatedPowerStatsConfig = createAggregatedPowerStatsConfig();
         mPowerStatsStore = new PowerStatsStore(systemDir, mHandler, mAggregatedPowerStatsConfig);
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 626b70b..d92a24b 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1419,6 +1419,11 @@
     }
 
     @GuardedBy({"mAm", "mProcLock"})
+    void freezeAppAsyncAtEarliestLSP(ProcessRecord app) {
+        freezeAppAsyncLSP(app, updateEarliestFreezableTime(app, 0));
+    }
+
+    @GuardedBy({"mAm", "mProcLock"})
     void freezeAppAsyncInternalLSP(ProcessRecord app, @UptimeMillisLong long delayMillis,
             boolean force) {
         final ProcessCachedOptimizerRecord opt = app.mOptRecord;
@@ -1714,6 +1719,14 @@
                 compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false);
             }
         }
+        frozenProc.onProcessFrozen();
+    }
+
+    /**
+     * Callback received when an attempt to freeze a process is cancelled (failed).
+     */
+    void onProcessFrozenCancelled(ProcessRecord app) {
+        app.onProcessFrozenCancelled();
     }
 
     /**
@@ -2203,6 +2216,8 @@
                         onProcessFrozen(proc);
                         removeMessages(DEADLOCK_WATCHDOG_MSG);
                         sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS);
+                    } else {
+                        onProcessFrozenCancelled(proc);
                     }
                 } break;
                 case REPORT_UNFREEZE_MSG: {
@@ -2460,7 +2475,7 @@
                                 pr = mAm.mPidsSelfLocked.get(blocked);
                             }
                             if (pr != null
-                                    && pr.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ) {
+                                    && pr.mState.getCurAdj() < ProcessList.FREEZER_CUTOFF_ADJ) {
                                 Slog.d(TAG_AM, app.processName + " (" + pid + ") blocks "
                                         + pr.processName + " (" + blocked + ")");
                                 // Found at least one blocked non-cached process
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 30f21a6..cb7898d 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -35,6 +35,7 @@
 import static com.android.internal.util.FrameworkStatsLog.PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
 import static com.android.server.am.ActivityManagerService.TAG_MU;
+import static com.android.server.am.Flags.serviceBindingOomAdjPolicy;
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -319,8 +320,10 @@
 
                     checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
                     final int verifiedAdj = cpr.proc.mState.getVerifiedAdj();
-                    boolean success = mService.updateOomAdjLocked(cpr.proc,
-                            OOM_ADJ_REASON_GET_PROVIDER);
+                    boolean success = !serviceBindingOomAdjPolicy()
+                            || mService.mOomAdjuster.evaluateProviderConnectionAdd(r, cpr.proc)
+                            ? mService.updateOomAdjLocked(cpr.proc, OOM_ADJ_REASON_GET_PROVIDER)
+                            : true;
                     // XXX things have changed so updateOomAdjLocked doesn't actually tell us
                     // if the process has been successfully adjusted.  So to reduce races with
                     // it, we will check whether the process still exists.  Note that this doesn't
@@ -1529,7 +1532,9 @@
             }
             mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
                     cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
-            if (updateOomAdj) {
+            if (updateOomAdj && (!serviceBindingOomAdjPolicy()
+                    || mService.mOomAdjuster.evaluateProviderConnectionRemoval(conn.client,
+                            cpr.proc))) {
                 mService.updateOomAdjLocked(conn.provider.proc, OOM_ADJ_REASON_REMOVE_PROVIDER);
             }
         }
diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
index abc7ab1..db47e3f 100644
--- a/services/core/java/com/android/server/am/IntentBindRecord.java
+++ b/services/core/java/com/android/server/am/IntentBindRecord.java
@@ -46,9 +46,17 @@
     boolean hasBound;
     /** Set when the service's onUnbind() has asked to be told about new clients. */
     boolean doRebind;
-    
+
     String stringName;      // caching of toString
-    
+
+    /**
+     * Mark if we've skipped oom adj update before calling into the {@link Service#onBind()}
+     * or {@link Service#onUnbind()}.
+     *
+     * <p>If it's true, we'll skip the oom adj update too during the serviceDoneExecuting.
+     */
+    boolean mSkippedOomAdj;
+
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("service="); pw.println(service);
         dumpInService(pw, prefix);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index ef7a0e0..862542e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -103,6 +103,7 @@
 import static com.android.server.am.ProcessList.CACHED_APP_MAX_ADJ;
 import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
 import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ;
+import static com.android.server.am.ProcessList.FREEZER_CUTOFF_ADJ;
 import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ;
 import static com.android.server.am.ProcessList.HOME_APP_ADJ;
 import static com.android.server.am.ProcessList.INVALID_ADJ;
@@ -2309,7 +2310,7 @@
                     }
 
                     computeServiceHostOomAdjLSP(cr, app, cr.binding.client, now, topApp, doingAll,
-                            cycleReEval, computeClients, oomAdjReason, cachedAdj, true);
+                            cycleReEval, computeClients, oomAdjReason, cachedAdj, true, false);
 
                     adj = state.getCurRawAdj();
                     procState = state.getCurRawProcState();
@@ -2341,7 +2342,7 @@
                     ContentProviderConnection conn = cpr.connections.get(i);
                     ProcessRecord client = conn.client;
                     computeProviderHostOomAdjLSP(conn, app, client, now, topApp, doingAll,
-                            cycleReEval, computeClients, oomAdjReason, cachedAdj, true);
+                            cycleReEval, computeClients, oomAdjReason, cachedAdj, true, false);
 
                     adj = state.getCurRawAdj();
                     procState = state.getCurRawProcState();
@@ -2558,17 +2559,18 @@
     }
 
     @GuardedBy({"mService", "mProcLock"})
-    protected void computeServiceHostOomAdjLSP(ConnectionRecord cr, ProcessRecord app,
+    protected boolean computeServiceHostOomAdjLSP(ConnectionRecord cr, ProcessRecord app,
             ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll,
             boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj,
-            boolean couldRecurse) {
+            boolean couldRecurse, boolean dryRun) {
         if (app.isPendingFinishAttach()) {
             // We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here.
-            return;
+            return false;
         }
 
         final ProcessStateRecord state = app.mState;
         ProcessStateRecord cstate = client.mState;
+        boolean updated = false;
 
         if (couldRecurse) {
             if (app.isSdkSandbox && cr.binding.attributedClient != null) {
@@ -2599,19 +2601,25 @@
         final int prevRawAdj = adj;
         final int prevProcState = procState;
         final int prevSchedGroup = schedGroup;
+        final int prevCapability = capability;
 
         final int appUid = app.info.uid;
         final int logUid = mService.mCurOomAdjUid;
 
-        state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
-                || cstate.isCurBoundByNonBgRestrictedApp()
-                || clientProcState <= PROCESS_STATE_BOUND_TOP
-                || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
-                        && !cstate.isBackgroundRestricted()));
+        if (!dryRun) {
+            state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
+                    || cstate.isCurBoundByNonBgRestrictedApp()
+                    || clientProcState <= PROCESS_STATE_BOUND_TOP
+                    || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+                            && !cstate.isBackgroundRestricted()));
+        }
 
         if (client.mOptRecord.shouldNotFreeze()) {
             // Propagate the shouldNotFreeze flag down the bindings.
-            app.mOptRecord.setShouldNotFreeze(true);
+            if (app.mOptRecord.setShouldNotFreeze(true, dryRun)) {
+                // Bail out early, as we only care about the return value for a dryrun.
+                return true;
+            }
         }
 
         boolean trackedProcState = false;
@@ -2653,7 +2661,7 @@
             }
 
             if (couldRecurse && shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
-                return;
+                return false;
             }
 
             if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
@@ -2666,7 +2674,10 @@
             if (cr.hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) {
                 // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen.
                 if (clientAdj < CACHED_APP_MIN_ADJ) {
-                    app.mOptRecord.setShouldNotFreeze(true);
+                    if (app.mOptRecord.setShouldNotFreeze(true, dryRun)) {
+                        // Bail out early, as we only care about the return value for a dryrun.
+                        return true;
+                    }
                 }
                 // Not doing bind OOM management, so treat
                 // this guy more like a started service.
@@ -2678,7 +2689,10 @@
                     if (adj > clientAdj) {
                         adjType = "cch-bound-ui-services";
                     }
-                    state.setCached(false);
+                    if (state.setCached(false, dryRun)) {
+                        // Bail out early, as we only care about the return value for a dryrun.
+                        return true;
+                    }
                     clientAdj = adj;
                     clientProcState = procState;
                 } else {
@@ -2721,7 +2735,9 @@
                             newAdj = PERSISTENT_SERVICE_ADJ;
                             schedGroup = SCHED_GROUP_DEFAULT;
                             procState = ActivityManager.PROCESS_STATE_PERSISTENT;
-                            cr.trackProcState(procState, mAdjSeq);
+                            if (!dryRun) {
+                                cr.trackProcState(procState, mAdjSeq);
+                            }
                             trackedProcState = true;
                         }
                     } else if (cr.hasFlag(Context.BIND_NOT_PERCEPTIBLE)
@@ -2762,11 +2778,16 @@
                         }
                     }
                     if (!cstate.isCached()) {
-                        state.setCached(false);
+                        if (state.setCached(false, dryRun)) {
+                            // Bail out early, as we only care about the return value for a dryrun.
+                            return true;
+                        }
                     }
                     if (adj >  newAdj) {
                         adj = newAdj;
-                        state.setCurRawAdj(adj);
+                        if (state.setCurRawAdj(adj, dryRun)) {
+                            // Bail out early, as we only care about the return value for a dryrun.
+                        }
                         adjType = "service";
                     }
                 }
@@ -2833,25 +2854,35 @@
 
             if (cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP) && clientIsSystem) {
                 schedGroup = SCHED_GROUP_TOP_APP;
-                state.setScheduleLikeTopApp(true);
+                if (dryRun) {
+                    if (prevSchedGroup < schedGroup) {
+                        // Bail out early, as we only care about the return value for a dryrun.
+                        return true;
+                    }
+                } else {
+                    state.setScheduleLikeTopApp(true);
+                }
             }
 
-            if (!trackedProcState) {
+            if (!trackedProcState && !dryRun) {
                 cr.trackProcState(clientProcState, mAdjSeq);
             }
 
             if (procState > clientProcState) {
                 procState = clientProcState;
-                state.setCurRawProcState(procState);
+                if (state.setCurRawProcState(procState, dryRun)) {
+                    // Bail out early, as we only care about the return value for a dryrun.
+                    return true;
+                }
                 if (adjType == null) {
                     adjType = "service";
                 }
             }
             if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
-                    && cr.hasFlag(Context.BIND_SHOWING_UI)) {
+                    && cr.hasFlag(Context.BIND_SHOWING_UI) && !dryRun) {
                 app.setPendingUiClean(true);
             }
-            if (adjType != null) {
+            if (adjType != null && !dryRun) {
                 state.setAdjType(adjType);
                 state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
                         .REASON_SERVICE_IN_USE);
@@ -2876,11 +2907,16 @@
             // bound by an unfrozen app via a WPRI binding has to remain
             // unfrozen.
             if (clientAdj < CACHED_APP_MIN_ADJ) {
-                app.mOptRecord.setShouldNotFreeze(true);
+                if (app.mOptRecord.setShouldNotFreeze(true, dryRun)) {
+                    // Bail out early, as we only care about the return value for a dryrun.
+                    return true;
+                }
             }
         }
         if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
-            app.mServices.setTreatLikeActivity(true);
+            if (!dryRun) {
+                app.mServices.setTreatLikeActivity(true);
+            }
             if (clientProcState <= PROCESS_STATE_CACHED_ACTIVITY
                     && procState > PROCESS_STATE_CACHED_ACTIVITY) {
                 // This is a cached process, but somebody wants us to treat it like it has
@@ -2894,7 +2930,9 @@
             if (a != null && adj > FOREGROUND_APP_ADJ
                     && a.isActivityVisible()) {
                 adj = FOREGROUND_APP_ADJ;
-                state.setCurRawAdj(adj);
+                if (state.setCurRawAdj(adj, dryRun)) {
+                    return true;
+                }
                 if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND)) {
                     if (cr.hasFlag(Context.BIND_IMPORTANT)) {
                         schedGroup = SCHED_GROUP_TOP_APP_BOUND;
@@ -2902,16 +2940,18 @@
                         schedGroup = SCHED_GROUP_DEFAULT;
                     }
                 }
-                state.setCached(false);
-                state.setAdjType("service");
-                state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
-                        .REASON_SERVICE_IN_USE);
-                state.setAdjSource(a);
-                state.setAdjSourceProcState(procState);
-                state.setAdjTarget(cr.binding.service.instanceName);
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                            "Raise to service w/activity: " + app);
+                if (!dryRun) {
+                    state.setCached(false);
+                    state.setAdjType("service");
+                    state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
+                            .REASON_SERVICE_IN_USE);
+                    state.setAdjSource(a);
+                    state.setAdjSourceProcState(procState);
+                    state.setAdjTarget(cr.binding.service.instanceName);
+                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                "Raise to service w/activity: " + app);
+                    }
                 }
             }
         }
@@ -2922,7 +2962,15 @@
         if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
             capability &= ~PROCESS_CAPABILITY_BFSL;
         }
+        if (!updated) {
+            updated = adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup
+                || (capability != prevCapability
+                        && (capability & prevCapability) == prevCapability);
+        }
 
+        if (dryRun) {
+            return updated;
+        }
         if (adj < prevRawAdj) {
             schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
         }
@@ -2935,15 +2983,16 @@
         state.setCurCapability(capability);
 
         state.setEmpty(false);
+        return updated;
     }
 
-    protected void computeProviderHostOomAdjLSP(ContentProviderConnection conn, ProcessRecord app,
-            ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll,
-            boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj,
-            boolean couldRecurse) {
+    protected boolean computeProviderHostOomAdjLSP(ContentProviderConnection conn,
+            ProcessRecord app, ProcessRecord client, long now, ProcessRecord topApp,
+            boolean doingAll, boolean cycleReEval, boolean computeClients, int oomAdjReason,
+            int cachedAdj, boolean couldRecurse, boolean dryRun) {
         if (app.isPendingFinishAttach()) {
             // We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here.
-            return;
+            return false;
         }
 
         final ProcessStateRecord state = app.mState;
@@ -2951,7 +3000,7 @@
 
         if (client == app) {
             // Being our own client is not interesting.
-            return;
+            return false;
         }
         if (couldRecurse) {
             if (computeClients) {
@@ -2964,7 +3013,7 @@
 
             if (shouldSkipDueToCycle(app, cstate, state.getCurRawProcState(), state.getCurRawAdj(),
                     cycleReEval)) {
-                return;
+                return false;
             }
         }
 
@@ -2979,6 +3028,7 @@
         final int prevRawAdj = adj;
         final int prevProcState = procState;
         final int prevSchedGroup = schedGroup;
+        final int prevCapability = capability;
 
         final int appUid = app.info.uid;
         final int logUid = mService.mCurOomAdjUid;
@@ -2995,14 +3045,19 @@
         }
         if (client.mOptRecord.shouldNotFreeze()) {
             // Propagate the shouldNotFreeze flag down the bindings.
-            app.mOptRecord.setShouldNotFreeze(true);
+            if (app.mOptRecord.setShouldNotFreeze(true, dryRun)) {
+                // Bail out early, as we only care about the return value for a dryrun.
+                return true;
+            }
         }
 
-        state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
-                || cstate.isCurBoundByNonBgRestrictedApp()
-                || clientProcState <= PROCESS_STATE_BOUND_TOP
-                || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
-                        && !cstate.isBackgroundRestricted()));
+        if (!dryRun) {
+            state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
+                    || cstate.isCurBoundByNonBgRestrictedApp()
+                    || clientProcState <= PROCESS_STATE_BOUND_TOP
+                    || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+                            && !cstate.isBackgroundRestricted()));
+        }
 
         String adjType = null;
         if (adj > clientAdj) {
@@ -3011,10 +3066,16 @@
                 adjType = "cch-ui-provider";
             } else {
                 adj = Math.max(clientAdj, FOREGROUND_APP_ADJ);
-                state.setCurRawAdj(adj);
+                if (state.setCurRawAdj(adj, dryRun)) {
+                    // Bail out early, as we only care about the return value for a dryrun.
+                    return true;
+                }
                 adjType = "provider";
             }
-            state.setCached(state.isCached() & cstate.isCached());
+            if (state.setCached(state.isCached() & cstate.isCached(), dryRun)) {
+                // Bail out early, as we only care about the return value for a dryrun.
+                return true;
+            }
         }
 
         if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -3028,15 +3089,20 @@
             }
         }
 
-        conn.trackProcState(clientProcState, mAdjSeq);
+        if (!dryRun) {
+            conn.trackProcState(clientProcState, mAdjSeq);
+        }
         if (procState > clientProcState) {
             procState = clientProcState;
-            state.setCurRawProcState(procState);
+            if (state.setCurRawProcState(procState, dryRun)) {
+                // Bail out early, as we only care about the return value for a dryrun.
+                return true;
+            }
         }
         if (cstate.getCurrentSchedulingGroup() > schedGroup) {
             schedGroup = SCHED_GROUP_DEFAULT;
         }
-        if (adjType != null) {
+        if (adjType != null && !dryRun) {
             state.setAdjType(adjType);
             state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
                     .REASON_PROVIDER_IN_USE);
@@ -3056,6 +3122,12 @@
             capability &= ~PROCESS_CAPABILITY_BFSL;
         }
 
+        if (dryRun && (adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup
+                || (capability != prevCapability
+                        && (capability & prevCapability) == prevCapability))) {
+            return true;
+        }
+
         if (adj < prevRawAdj) {
             schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
         }
@@ -3068,6 +3140,7 @@
         state.setCurCapability(capability);
 
         state.setEmpty(false);
+        return false;
     }
 
     protected int getDefaultCapability(ProcessRecord app, int procState) {
@@ -3342,7 +3415,7 @@
             changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
         }
 
-        updateAppFreezeStateLSP(app, oomAdjReson);
+        updateAppFreezeStateLSP(app, oomAdjReson, false);
 
         if (state.getReportedProcState() != state.getCurProcState()) {
             state.setReportedProcState(state.getCurProcState());
@@ -3727,7 +3800,8 @@
     }
 
     @GuardedBy({"mService", "mProcLock"})
-    private void updateAppFreezeStateLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
+    void updateAppFreezeStateLSP(ProcessRecord app, @OomAdjReason int oomAdjReason,
+            boolean immediate) {
         if (!mCachedAppOptimizer.useFreezer()) {
             return;
         }
@@ -3746,10 +3820,14 @@
 
         final ProcessStateRecord state = app.mState;
         // Use current adjustment when freezing, set adjustment when unfreezing.
-        if (state.getCurAdj() >= CACHED_APP_MIN_ADJ && !opt.isFrozen()
+        if (state.getCurAdj() >= FREEZER_CUTOFF_ADJ && !opt.isFrozen()
                 && !opt.shouldNotFreeze()) {
-            mCachedAppOptimizer.freezeAppAsyncLSP(app);
-        } else if (state.getSetAdj() < CACHED_APP_MIN_ADJ) {
+            if (!immediate) {
+                mCachedAppOptimizer.freezeAppAsyncLSP(app);
+            } else {
+                mCachedAppOptimizer.freezeAppAsyncAtEarliestLSP(app);
+            }
+        } else if (state.getSetAdj() < FREEZER_CUTOFF_ADJ) {
             mCachedAppOptimizer.unfreezeAppLSP(app,
                     CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason));
         }
@@ -3826,4 +3904,89 @@
         // The caller will set the initial value in this implementation.
         return app.mState.isCurBoundByNonBgRestrictedApp();
     }
+
+    /**
+     * Evaluate the service connection, return {@code true} if the client will change the state
+     * of the service host process by the given connection.
+     */
+    @GuardedBy("mService")
+    boolean evaluateServiceConnectionAdd(ProcessRecord client, ProcessRecord app,
+            ConnectionRecord cr) {
+        if (evaluateConnectionPrelude(client, app)) {
+            return true;
+        }
+        if (app.getSetAdj() <= client.getSetAdj()
+                && app.getSetProcState() <= client.getSetProcState()
+                && ((app.getSetCapability() & client.getSetCapability())
+                        == client.getSetCapability()
+                        || cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES
+                                | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS))) {
+            // The service host process has better states than the client, so no change.
+            return false;
+        }
+        // Take a dry run of the computeServiceHostOomAdjLSP, this would't be expensive
+        // since it's only evaluating one service connection.
+        return computeServiceHostOomAdjLSP(cr, app, client, SystemClock.uptimeMillis(),
+                mService.getTopApp(), false, false, false, OOM_ADJ_REASON_NONE,
+                CACHED_APP_MIN_ADJ, false, true /* dryRun */);
+    }
+
+    @GuardedBy("mService")
+    boolean evaluateServiceConnectionRemoval(ProcessRecord client, ProcessRecord app,
+            ConnectionRecord cr) {
+        if (evaluateConnectionPrelude(client, app)) {
+            return true;
+        }
+
+        if (app.getSetAdj() < client.getSetAdj()
+                && app.getSetProcState() < client.getSetProcState()) {
+            // The service host process has better states than the client.
+            if (((app.getSetCapability() & client.getSetCapability()) == PROCESS_CAPABILITY_NONE)
+                    || cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES
+                            | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) {
+                // The service host app doesn't get any capabilities from the client.
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @GuardedBy("mService")
+    boolean evaluateProviderConnectionAdd(ProcessRecord client, ProcessRecord app) {
+        if (evaluateConnectionPrelude(client, app)) {
+            return true;
+        }
+        if (app.getSetAdj() <= client.getSetAdj()
+                && app.getSetProcState() <= client.getSetProcState()) {
+            // The provider host process has better states than the client, so no change.
+            return false;
+        }
+        return computeProviderHostOomAdjLSP(null, app, client, SystemClock.uptimeMillis(),
+                mService.getTopApp(), false, false, false, OOM_ADJ_REASON_NONE, CACHED_APP_MIN_ADJ,
+                false, true /* dryRun */);
+    }
+
+    @GuardedBy("mService")
+    boolean evaluateProviderConnectionRemoval(ProcessRecord client, ProcessRecord app) {
+        if (evaluateConnectionPrelude(client, app)) {
+            return true;
+        }
+        if (app.getSetAdj() < client.getSetAdj()
+                && app.getSetProcState() < client.getSetProcState()) {
+            // The provider host process has better states than the client, so no change.
+            return false;
+        }
+        return true;
+    }
+
+    private boolean evaluateConnectionPrelude(ProcessRecord client, ProcessRecord app) {
+        if (client == null || app == null) {
+            return true;
+        }
+        if (app.isSdkSandbox || app.isolated || app.isKilledByAm() || app.isKilled()) {
+            // Let's always re-evaluate them for now.
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index 5a3fbe9..f85b03e 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -1002,7 +1002,7 @@
 
 
             computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
-                    oomAdjReason, cachedAdj, false);
+                    oomAdjReason, cachedAdj, false, false);
         }
 
         for (int i = psr.numberOfSdkSandboxConnections() - 1; i >= 0; i--) {
@@ -1018,7 +1018,7 @@
             }
 
             computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
-                    oomAdjReason, cachedAdj, false);
+                    oomAdjReason, cachedAdj, false, false);
         }
 
         final ProcessProviderRecord ppr = app.mProviders;
@@ -1035,7 +1035,7 @@
             }
 
             computeProviderHostOomAdjLSP(cpc, provider, app, now, topApp, fullUpdate, false, false,
-                    oomAdjReason, cachedAdj, false);
+                    oomAdjReason, cachedAdj, false, false);
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index a20623c..5df9107 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -30,6 +30,7 @@
 import android.app.AppGlobals;
 import android.app.PendingIntent;
 import android.app.PendingIntentStats;
+import android.app.compat.CompatChanges;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.os.Binder;
@@ -136,6 +137,11 @@
                         + "intent creator ("
                         + packageName
                         + ") because this option is meant for the pending intent sender");
+                if (CompatChanges.isChangeEnabled(PendingIntent.PENDING_INTENT_OPTIONS_CHECK,
+                        callingUid)) {
+                    throw new IllegalArgumentException("pendingIntentBackgroundActivityStartMode "
+                            + "must not be set when creating a PendingIntent");
+                }
                 opts.setPendingIntentBackgroundActivityStartMode(
                         ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED);
             }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 10d5fd3..95e130e 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -406,6 +406,9 @@
             String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver,
             String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
             int flagsMask, int flagsValues, Bundle options) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+
         if (intent != null) intent.setDefusable(true);
         if (options != null) options.setDefusable(true);
 
@@ -458,6 +461,12 @@
                                     + key.packageName
                                     + ") because this option is meant for the pending intent "
                                     + "creator");
+                    if (CompatChanges.isChangeEnabled(PendingIntent.PENDING_INTENT_OPTIONS_CHECK,
+                            callingUid)) {
+                        throw new IllegalArgumentException(
+                                "pendingIntentCreatorBackgroundActivityStartMode "
+                                + "must not be set when sending a PendingIntent");
+                    }
                     opts.setPendingIntentCreatorBackgroundActivityStartMode(
                             ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED);
                 }
@@ -494,9 +503,6 @@
         }
         // We don't hold the controller lock beyond this point as we will be calling into AM and WM.
 
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-
         // Only system senders can declare a broadcast to be alarm-originated.  We check
         // this here rather than in the general case handling below to fail before the other
         // invocation side effects such as allowlisting.
diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
index f5c5ea8..a8fe734 100644
--- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
+++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
@@ -274,7 +274,20 @@
 
     @GuardedBy("mProcLock")
     void setShouldNotFreeze(boolean shouldNotFreeze) {
+        setShouldNotFreeze(shouldNotFreeze, false);
+    }
+
+    /**
+     * @return {@code true} if it's a dry run and it's going to unfreeze the process
+     * if it was a real run.
+     */
+    @GuardedBy("mProcLock")
+    boolean setShouldNotFreeze(boolean shouldNotFreeze, boolean dryRun) {
+        if (dryRun) {
+            return mFrozen && !shouldNotFreeze;
+        }
         mShouldNotFreeze = shouldNotFreeze;
+        return false;
     }
 
     @GuardedBy("mProcLock")
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index f5c34a5..10cd6e5 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -371,6 +371,12 @@
     private static final long LMKD_RECONNECT_DELAY_MS = 1000;
 
     /**
+     * The cuttoff adj for the freezer, app processes with adj greater than this value will be
+     * eligible for the freezer.
+     */
+    static final int FREEZER_CUTOFF_ADJ = CACHED_APP_MIN_ADJ;
+
+    /**
      * Apps have no access to the private data directories of any other app, even if the other
      * app has made them world-readable.
      */
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index e5c4a66..de6f034 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -720,6 +720,11 @@
         return mState.getSetProcState();
     }
 
+    @GuardedBy(anyOf = {"mService", "mProcLock"})
+    int getSetCapability() {
+        return mState.getSetCapability();
+    }
+
     @GuardedBy({"mService", "mProcLock"})
     public void makeActive(IApplicationThread thread, ProcessStatsService tracker) {
         mProfile.onProcessActive(thread, tracker);
@@ -1401,8 +1406,12 @@
 
     void onProcessUnfrozen() {
         mProfile.onProcessUnfrozen();
+        mServices.onProcessUnfrozen();
     }
 
+    void onProcessFrozenCancelled() {
+        mServices.onProcessFrozenCancelled();
+    }
 
     /*
      *  Delete all packages from list except the package indicated in info
@@ -1644,6 +1653,13 @@
         return mWasForceStopped;
     }
 
+    boolean isFreezable() {
+        return mService.mOomAdjuster.mCachedAppOptimizer.useFreezer()
+                && !mOptRecord.isFreezeExempt()
+                && !mOptRecord.shouldNotFreeze()
+                && mState.getCurAdj() >= ProcessList.FREEZER_CUTOFF_ADJ;
+    }
+
     /**
      * Traverses all client processes and feed them to consumer.
      */
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index f5f2b10..57d233e 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -19,6 +19,8 @@
 import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
 import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE;
 
+import static com.android.server.am.Flags.serviceBindingOomAdjPolicy;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.Context;
@@ -144,6 +146,11 @@
      */
     private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
 
+    /**
+     * The process should schedule a service timeout timer but haven't done so.
+     */
+    private boolean mScheduleServiceTimeoutPending;
+
     final ProcessRecord mApp;
 
     private final ActivityManagerService mService;
@@ -657,6 +664,41 @@
         setHasClientActivities(false);
     }
 
+    @GuardedBy("mService")
+    void noteScheduleServiceTimeoutPending(boolean pending) {
+        mScheduleServiceTimeoutPending = pending;
+    }
+
+    @GuardedBy("mService")
+    boolean isScheduleServiceTimeoutPending() {
+        return mScheduleServiceTimeoutPending;
+    }
+
+    @GuardedBy("mService")
+    void onProcessUnfrozen() {
+        scheduleServiceTimeoutIfNeededLocked();
+    }
+
+    @GuardedBy("mService")
+    void onProcessFrozenCancelled() {
+        scheduleServiceTimeoutIfNeededLocked();
+    }
+
+    @GuardedBy("mService")
+    private void scheduleServiceTimeoutIfNeededLocked() {
+        if (!serviceBindingOomAdjPolicy()) {
+            return;
+        }
+        if (mScheduleServiceTimeoutPending && mExecutingServices.size() > 0) {
+            mService.mServices.scheduleServiceTimeoutLocked(mApp);
+            // We'll need to reset the executingStart since the app was frozen.
+            final long now = SystemClock.uptimeMillis();
+            for (int i = 0, size = mExecutingServices.size(); i < size; i++) {
+                mExecutingServices.valueAt(i).executingStart = now;
+            }
+        }
+    }
+
     void dump(PrintWriter pw, String prefix, long nowUptime) {
         if (mHasForegroundServices || mApp.mState.getForcingToImportant() != null) {
             pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices);
@@ -701,5 +743,10 @@
                 pw.print(prefix); pw.print("  - "); pw.println(mConnections.valueAt(i));
             }
         }
+        if (serviceBindingOomAdjPolicy()) {
+            pw.print(prefix);
+            pw.print("scheduleServiceTimeoutPending=");
+            pw.println(mScheduleServiceTimeoutPending);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 3391ec7..8362eaf 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -479,9 +479,22 @@
 
     @GuardedBy({"mService", "mProcLock"})
     void setCurRawAdj(int curRawAdj) {
+        setCurRawAdj(curRawAdj, false);
+    }
+
+    /**
+     * @return {@code true} if it's a dry run and it's going to bump the adj score of the process
+     * if it was a real run.
+     */
+    @GuardedBy({"mService", "mProcLock"})
+    boolean setCurRawAdj(int curRawAdj, boolean dryRun) {
+        if (dryRun) {
+            return mCurRawAdj > curRawAdj;
+        }
         mCurRawAdj = curRawAdj;
         mApp.getWindowProcessController().setPerceptible(
                 curRawAdj <= ProcessList.PERCEPTIBLE_APP_ADJ);
+        return false;
     }
 
     @GuardedBy(anyOf = {"mService", "mProcLock"})
@@ -594,7 +607,20 @@
 
     @GuardedBy({"mService", "mProcLock"})
     void setCurRawProcState(int curRawProcState) {
+        setCurRawProcState(curRawProcState, false);
+    }
+
+    /**
+     * @return {@code true} if it's a dry run and it's going to bump the procstate of the process
+     * if it was a real run.
+     */
+    @GuardedBy({"mService", "mProcLock"})
+    boolean setCurRawProcState(int curRawProcState, boolean dryRun) {
+        if (dryRun) {
+            return mCurRawProcState > curRawProcState;
+        }
         mCurRawProcState = curRawProcState;
+        return false;
     }
 
     @GuardedBy(anyOf = {"mService", "mProcLock"})
@@ -900,7 +926,20 @@
 
     @GuardedBy("mService")
     void setCached(boolean cached) {
+        setCached(cached, false);
+    }
+
+    /**
+     * @return {@code true} if it's a dry run and it's going to uncache the process
+     * if it was a real run.
+     */
+    @GuardedBy("mService")
+    boolean setCached(boolean cached, boolean dryRun) {
+        if (dryRun) {
+            return mCached && !cached;
+        }
         mCached = cached;
+        return false;
     }
 
     @GuardedBy("mService")
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 654aebd..31d9cc9 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -35,3 +35,10 @@
      description: "Enable the new FGS restriction logic"
      bug: "276963716"
 }
+
+flag {
+    name: "service_binding_oom_adj_policy"
+    namespace: "backstage_power"
+    description: "Optimize the service bindings by different policies like skipping oom adjuster"
+    bug: "318717054"
+}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 57b19cd..690c37a 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -914,28 +914,27 @@
                         di.mDeviceCodecFormat = codec;
                         mConnectedDevices.replace(key, di);
                         codecChange = true;
-                    }
-                    final int res = mAudioSystem.handleDeviceConfigChange(
-                            btInfo.mAudioSystemDevice, address, BtHelper.getName(btDevice), codec);
+                        final int res = mAudioSystem.handleDeviceConfigChange(
+                                btInfo.mAudioSystemDevice, address,
+                                BtHelper.getName(btDevice), codec);
+                        if (res != AudioSystem.AUDIO_STATUS_OK) {
+                            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+                                    "APM handleDeviceConfigChange failed for A2DP device addr="
+                                            + address + " codec="
+                                            + AudioSystem.audioFormatToString(codec))
+                                    .printLog(TAG));
 
-                    if (res != AudioSystem.AUDIO_STATUS_OK) {
-                        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
-                                "APM handleDeviceConfigChange failed for A2DP device addr="
-                                        + address + " codec="
-                                        + AudioSystem.audioFormatToString(codec))
-                                .printLog(TAG));
-
-                        // force A2DP device disconnection in case of error so that AudioService
-                        // state is consistent with audio policy manager state
-                        setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btInfo,
-                                BluetoothProfile.STATE_DISCONNECTED));
-                    } else {
-                        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
-                                "APM handleDeviceConfigChange success for A2DP device addr="
-                                        + address
-                                        + " codec=" + AudioSystem.audioFormatToString(codec))
-                                .printLog(TAG));
-
+                            // force A2DP device disconnection in case of error so that AudioService
+                            // state is consistent with audio policy manager state
+                            setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btInfo,
+                                    BluetoothProfile.STATE_DISCONNECTED));
+                        } else {
+                            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+                                    "APM handleDeviceConfigChange success for A2DP device addr="
+                                            + address
+                                            + " codec=" + AudioSystem.audioFormatToString(codec))
+                                    .printLog(TAG));
+                        }
                     }
                 }
                 if (!codecChange) {
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index a30cdc4..9610034ca 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -1203,7 +1203,7 @@
     @GuardedBy("mCsdStateLock")
     private void sanitizeDoseRecords_l() {
         if (mDoseRecords.size() > MAX_NUMBER_OF_CACHED_RECORDS) {
-            int nrToRemove = MAX_NUMBER_OF_CACHED_RECORDS - mDoseRecords.size();
+            int nrToRemove = mDoseRecords.size() - MAX_NUMBER_OF_CACHED_RECORDS;
             Log.w(TAG,
                     "Removing " + nrToRemove + " records from the total of " + mDoseRecords.size());
             // Remove older elements to fit into persisted settings max length
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 21e6bac..3f3540e 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -20,7 +20,7 @@
 // TODO(b/141025588): Create separate internal and external permissions for AuthService.
 // TODO(b/141025588): Get rid of the USE_FINGERPRINT permission.
 
-import static android.Manifest.permission.MANAGE_BIOMETRIC_DIALOG;
+import static android.Manifest.permission.SET_BIOMETRIC_DIALOG_LOGO;
 import static android.Manifest.permission.TEST_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
@@ -305,7 +305,7 @@
             if (promptInfo.containsPrivateApiConfigurations()) {
                 checkInternalPermission();
             }
-            if (promptInfo.containsManageBioApiConfigurations()) {
+            if (promptInfo.containsSetLogoApiConfigurations()) {
                 checkManageBiometricPermission();
             }
 
@@ -997,8 +997,8 @@
     }
 
     private void checkManageBiometricPermission() {
-        getContext().enforceCallingOrSelfPermission(MANAGE_BIOMETRIC_DIALOG,
-                "Must have MANAGE_BIOMETRIC_DIALOG permission");
+        getContext().enforceCallingOrSelfPermission(SET_BIOMETRIC_DIALOG_LOGO,
+                "Must have SET_BIOMETRIC_DIALOG_LOGO permission");
     }
 
     private void checkPermission() {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index df179a9..5b23364c 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -138,6 +138,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Random;
 import java.util.Set;
@@ -3870,8 +3871,12 @@
             final SyncStorageEngine.EndPoint info = syncOperation.target;
 
             if (activeSyncContext.mIsLinkedToDeath) {
-                activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
-                activeSyncContext.mIsLinkedToDeath = false;
+                try {
+                    activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
+                    activeSyncContext.mIsLinkedToDeath = false;
+                } catch (NoSuchElementException e) {
+                    Slog.wtf(TAG, "Failed to unlink active sync adapter to death", e);
+                }
             }
             final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
             String historyMessage;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 9cf9119..93addcd 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1656,14 +1656,16 @@
             ContentRecordingSession session = null;
             try {
                 if (projection != null) {
-                    IBinder launchCookie = projection.getLaunchCookie();
-                    if (launchCookie == null) {
+                    IBinder taskWindowContainerToken = projection.getLaunchCookie() == null ? null
+                            : projection.getLaunchCookie().binder;
+                    if (taskWindowContainerToken == null) {
                         // Record a particular display.
                         session = ContentRecordingSession.createDisplaySession(
                                 virtualDisplayConfig.getDisplayIdToMirror());
                     } else {
                         // Record a single task indicated by the launch cookie.
-                        session = ContentRecordingSession.createTaskSession(launchCookie);
+                        session = ContentRecordingSession.createTaskSession(
+                                taskWindowContainerToken);
                     }
                 }
             } catch (RemoteException e) {
@@ -2776,17 +2778,17 @@
     }
 
     private ScreenCapture.ScreenshotHardwareBuffer userScreenshotInternal(int displayId) {
+        final ScreenCapture.DisplayCaptureArgs captureArgs;
         synchronized (mSyncRoot) {
             final IBinder token = getDisplayToken(displayId);
             if (token == null) {
                 return null;
             }
 
-            final ScreenCapture.DisplayCaptureArgs captureArgs =
-                    new ScreenCapture.DisplayCaptureArgs.Builder(token)
+            captureArgs = new ScreenCapture.DisplayCaptureArgs.Builder(token)
                             .build();
-            return ScreenCapture.captureDisplay(captureArgs);
         }
+        return ScreenCapture.captureDisplay(captureArgs);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 82461fa..8b4e1ff 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -394,6 +394,8 @@
             if (mDisplayObserver.isExternalDisplayLocked(displayId)) {
                 primarySummary.maxRenderFrameRate = Math.max(baseMode.getRefreshRate(),
                         primarySummary.maxRenderFrameRate);
+                appRequestSummary.maxRenderFrameRate = Math.max(baseMode.getRefreshRate(),
+                        appRequestSummary.maxRenderFrameRate);
             }
 
             return new DesiredDisplayModeSpecs(baseMode.getModeId(),
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index ba4d320..731c78e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -514,6 +514,18 @@
     protected int handleRoutingInformation(HdmiCecMessage message) {
         assertRunOnServiceThread();
         int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        HdmiDeviceInfo sourceDevice = mService.getHdmiCecNetwork()
+                .getCecDeviceInfo(message.getSource());
+        // Ignore <Routing Information> messages pointing to the same physical address as the
+        // message sender. In this case, we shouldn't consider the sender to be the active source.
+        // See more b/321771821#comment7.
+        if (sourceDevice != null
+                && sourceDevice.getLogicalAddress() != Constants.ADDR_TV
+                && sourceDevice.getPhysicalAddress() == physicalAddress) {
+            Slog.d(TAG, "<Routing Information> is ignored, it is pointing to the same physical"
+                    + " address as the message sender");
+            return Constants.HANDLED;
+        }
         handleRoutingChangeAndInformation(physicalAddress, message);
         return Constants.HANDLED;
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 34e75c0..46061a5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -482,6 +482,22 @@
     @Override
     @ServiceThreadOnly
     @Constants.HandleMessageResult
+    protected int handleStandby(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        // Ignore <Standby> from non-active source device.
+        if (getActiveSource().logicalAddress != message.getSource()) {
+            Slog.d(TAG, "<Standby> was not sent by the current active source, ignoring."
+                    + " Current active source has logical address "
+                    + getActiveSource().logicalAddress);
+            return Constants.HANDLED;
+        }
+        return super.handleStandby(message);
+    }
+
+    @Override
+    @ServiceThreadOnly
+    @Constants.HandleMessageResult
     protected int handleInactiveSource(HdmiCecMessage message) {
         assertRunOnServiceThread();
         // Seq #10
diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java
index 380106b..b963a4b 100644
--- a/services/core/java/com/android/server/input/InputManagerInternal.java
+++ b/services/core/java/com/android/server/input/InputManagerInternal.java
@@ -87,12 +87,16 @@
      * connected, the caller may be blocked for an arbitrary period of time.
      *
      * @return true if the pointer displayId was set successfully, or false if it fails.
+     *
+     * @deprecated TODO(b/293587049): Not needed - remove after Pointer Icon Refactor is complete.
      */
     public abstract boolean setVirtualMousePointerDisplayId(int pointerDisplayId);
 
     /**
      * Gets the display id that the MouseCursorController is being forced to target. Returns
      * {@link android.view.Display#INVALID_DISPLAY} if there is no override
+     *
+     * @deprecated TODO(b/293587049): Not needed - remove after Pointer Icon Refactor is complete.
      */
     public abstract int getVirtualMousePointerDisplayId();
 
@@ -101,7 +105,7 @@
      *
      * Returns NaN-s as the coordinates if the cursor is not available.
      */
-    public abstract PointF getCursorPosition();
+    public abstract PointF getCursorPosition(int displayId);
 
     /**
      * Enables or disables pointer acceleration for mouse movements.
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 67c23fc..687def0 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1448,6 +1448,10 @@
     }
 
     private boolean setVirtualMousePointerDisplayIdBlocking(int overrideDisplayId) {
+        if (com.android.input.flags.Flags.enablePointerChoreographer()) {
+            throw new IllegalStateException(
+                    "This must not be used when PointerChoreographer is enabled");
+        }
         final boolean isRemovingOverride = overrideDisplayId == Display.INVALID_DISPLAY;
 
         // Take care to not make calls to window manager while holding internal locks.
@@ -1486,6 +1490,10 @@
     }
 
     private int getVirtualMousePointerDisplayId() {
+        if (com.android.input.flags.Flags.enablePointerChoreographer()) {
+            throw new IllegalStateException(
+                    "This must not be used when PointerChoreographer is enabled");
+        }
         synchronized (mAdditionalDisplayInputPropertiesLock) {
             return mOverriddenPointerDisplayId;
         }
@@ -3332,8 +3340,8 @@
         }
 
         @Override
-        public PointF getCursorPosition() {
-            final float[] p = mNative.getMouseCursorPosition();
+        public PointF getCursorPosition(int displayId) {
+            final float[] p = mNative.getMouseCursorPosition(displayId);
             if (p == null || p.length != 2) {
                 throw new IllegalStateException("Failed to get mouse cursor position");
             }
@@ -3614,6 +3622,13 @@
     }
 
     /**
+     * Sets Accessibility slow keys threshold in milliseconds.
+     */
+    public void setAccessibilitySlowKeysThreshold(int thresholdTimeMs) {
+        mNative.setAccessibilitySlowKeysThreshold(thresholdTimeMs);
+    }
+
+    /**
      * Sets whether Accessibility sticky keys is enabled.
      */
     public void setAccessibilityStickyKeysEnabled(boolean enabled) {
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 572d844..165dfe4 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -89,6 +89,8 @@
                         (reason) -> updateShowRotaryInput()),
                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS),
                         (reason) -> updateAccessibilityBounceKeys()),
+                Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SLOW_KEYS),
+                        (reason) -> updateAccessibilitySlowKeys()),
                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_STICKY_KEYS),
                         (reason) -> updateAccessibilityStickyKeys()));
     }
@@ -228,6 +230,11 @@
                 InputSettings.getAccessibilityBounceKeysThreshold(mContext));
     }
 
+    private void updateAccessibilitySlowKeys() {
+        mService.setAccessibilitySlowKeysThreshold(
+                InputSettings.getAccessibilitySlowKeysThreshold(mContext));
+    }
+
     private void updateAccessibilityStickyKeys() {
         mService.setAccessibilityStickyKeysEnabled(
                 InputSettings.isAccessibilityStickyKeysEnabled(mContext));
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 8aec8ca..bc82078 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -233,14 +233,15 @@
     void setStylusButtonMotionEventsEnabled(boolean enabled);
 
     /**
-     * Get the current position of the mouse cursor.
+     * Get the current position of the mouse cursor on the given display.
      *
-     * If the mouse cursor is not currently shown, the coordinate values will be NaN-s.
+     * If the mouse cursor is not currently shown, the coordinate values will be NaN-s. Use
+     * {@link android.view.Display#INVALID_DISPLAY} to get the position of the default mouse cursor.
      *
      * NOTE: This will grab the PointerController's lock, so we must be careful about calling this
      * from the InputReader or Display threads, which may result in a deadlock.
      */
-    float[] getMouseCursorPosition();
+    float[] getMouseCursorPosition(int displayId);
 
     /** Set whether showing a pointer icon for styluses is enabled. */
     void setStylusPointerIconEnabled(boolean enabled);
@@ -257,6 +258,11 @@
     void setAccessibilityBounceKeysThreshold(int thresholdTimeMs);
 
     /**
+     * Notify if Accessibility slow keys threshold is changed from InputSettings.
+     */
+    void setAccessibilitySlowKeysThreshold(int thresholdTimeMs);
+
+    /**
      * Notify if Accessibility sticky keys is enabled/disabled from InputSettings.
      */
     void setAccessibilityStickyKeysEnabled(boolean enabled);
@@ -514,7 +520,7 @@
         public native void setStylusButtonMotionEventsEnabled(boolean enabled);
 
         @Override
-        public native float[] getMouseCursorPosition();
+        public native float[] getMouseCursorPosition(int displayId);
 
         @Override
         public native void setStylusPointerIconEnabled(boolean enabled);
@@ -526,6 +532,9 @@
         public native void setAccessibilityBounceKeysThreshold(int thresholdTimeMs);
 
         @Override
+        public native void setAccessibilitySlowKeysThreshold(int thresholdTimeMs);
+
+        @Override
         public native void setAccessibilityStickyKeysEnabled(boolean enabled);
     }
 }
diff --git a/services/core/java/com/android/server/inputmethod/ClientController.java b/services/core/java/com/android/server/inputmethod/ClientController.java
index 21b952b..86f4db9 100644
--- a/services/core/java/com/android/server/inputmethod/ClientController.java
+++ b/services/core/java/com/android/server/inputmethod/ClientController.java
@@ -17,12 +17,11 @@
 package com.android.server.inputmethod;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.pm.PackageManagerInternal;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.ArrayMap;
-import android.util.SparseArray;
-import android.view.inputmethod.InputBinding;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -31,6 +30,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Store and manage {@link InputMethodManagerService} clients. This class was designed to be a
@@ -64,7 +64,7 @@
 
     // TODO(b/314150112): Make this field private when breaking the cycle with IMMS.
     @GuardedBy("ImfLock.class")
-    final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
+    private final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
 
     @GuardedBy("ImfLock.class")
     private final List<ClientControllerCallback> mCallbacks = new ArrayList<>();
@@ -147,6 +147,19 @@
     }
 
     @GuardedBy("ImfLock.class")
+    @Nullable
+    ClientState getClient(IBinder binder) {
+        return mClients.get(binder);
+    }
+
+    @GuardedBy("ImfLock.class")
+    void forAllClients(Consumer<ClientState> consumer) {
+        for (int i = 0; i < mClients.size(); i++) {
+            consumer.accept(mClients.valueAt(i));
+        }
+    }
+
+    @GuardedBy("ImfLock.class")
     boolean verifyClientAndPackageMatch(
             @NonNull IInputMethodClient client, @NonNull String packageName) {
         final ClientState cs = mClients.get(client.asBinder());
@@ -156,48 +169,4 @@
         return InputMethodUtils.checkIfPackageBelongsToUid(
                 mPackageManagerInternal, cs.mUid, packageName);
     }
-
-    static final class ClientState {
-        final IInputMethodClientInvoker mClient;
-        final IRemoteInputConnection mFallbackInputConnection;
-        final int mUid;
-        final int mPid;
-        final int mSelfReportedDisplayId;
-        final InputBinding mBinding;
-        final IBinder.DeathRecipient mClientDeathRecipient;
-
-        @GuardedBy("ImfLock.class")
-        boolean mSessionRequested;
-
-        @GuardedBy("ImfLock.class")
-        boolean mSessionRequestedForAccessibility;
-
-        @GuardedBy("ImfLock.class")
-        InputMethodManagerService.SessionState mCurSession;
-
-        @GuardedBy("ImfLock.class")
-        SparseArray<InputMethodManagerService.AccessibilitySessionState> mAccessibilitySessions =
-                new SparseArray<>();
-
-        @Override
-        public String toString() {
-            return "ClientState{" + Integer.toHexString(
-                    System.identityHashCode(this)) + " mUid=" + mUid
-                    + " mPid=" + mPid + " mSelfReportedDisplayId=" + mSelfReportedDisplayId + "}";
-        }
-
-        ClientState(IInputMethodClientInvoker client,
-                IRemoteInputConnection fallbackInputConnection,
-                int uid, int pid, int selfReportedDisplayId,
-                IBinder.DeathRecipient clientDeathRecipient) {
-            mClient = client;
-            mFallbackInputConnection = fallbackInputConnection;
-            mUid = uid;
-            mPid = pid;
-            mSelfReportedDisplayId = selfReportedDisplayId;
-            mBinding = new InputBinding(null /*conn*/, mFallbackInputConnection.asBinder(), mUid,
-                    mPid);
-            mClientDeathRecipient = clientDeathRecipient;
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/ClientState.java b/services/core/java/com/android/server/inputmethod/ClientState.java
new file mode 100644
index 0000000..e98a5a7
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ClientState.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.inputmethod;
+
+import android.os.IBinder;
+import android.util.SparseArray;
+import android.view.inputmethod.InputBinding;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.IRemoteInputConnection;
+
+final class ClientState {
+    final IInputMethodClientInvoker mClient;
+    final IRemoteInputConnection mFallbackInputConnection;
+    final int mUid;
+    final int mPid;
+    final int mSelfReportedDisplayId;
+    final InputBinding mBinding;
+    final IBinder.DeathRecipient mClientDeathRecipient;
+
+    @GuardedBy("ImfLock.class")
+    boolean mSessionRequested;
+
+    @GuardedBy("ImfLock.class")
+    boolean mSessionRequestedForAccessibility;
+
+    @GuardedBy("ImfLock.class")
+    InputMethodManagerService.SessionState mCurSession;
+
+    @GuardedBy("ImfLock.class")
+    SparseArray<InputMethodManagerService.AccessibilitySessionState> mAccessibilitySessions =
+            new SparseArray<>();
+
+    @Override
+    public String toString() {
+        return "ClientState{" + Integer.toHexString(
+                System.identityHashCode(this)) + " mUid=" + mUid
+                + " mPid=" + mPid + " mSelfReportedDisplayId=" + mSelfReportedDisplayId + "}";
+    }
+
+    ClientState(IInputMethodClientInvoker client,
+            IRemoteInputConnection fallbackInputConnection,
+            int uid, int pid, int selfReportedDisplayId,
+            IBinder.DeathRecipient clientDeathRecipient) {
+        mClient = client;
+        mFallbackInputConnection = fallbackInputConnection;
+        mUid = uid;
+        mPid = pid;
+        mSelfReportedDisplayId = selfReportedDisplayId;
+        mBinding = new InputBinding(null /*conn*/, mFallbackInputConnection.asBinder(), mUid,
+                mPid);
+        mClientDeathRecipient = clientDeathRecipient;
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 50340d2..f031b7b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -48,7 +48,6 @@
 import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 
-import static com.android.server.inputmethod.ClientController.ClientState;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeVisibilityResult;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
@@ -116,7 +115,6 @@
 import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.InputChannel;
 import android.view.InputDevice;
@@ -207,6 +205,7 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 import java.util.function.IntConsumer;
 
 /**
@@ -272,7 +271,6 @@
     @NonNull
     private final String[] mNonPreemptibleInputMethods;
 
-    // TODO(b/314150112): Move this to ClientController.
     @UserIdInt
     private int mLastSwitchUserId;
 
@@ -282,8 +280,6 @@
     @NonNull
     private InputMethodSettings mSettings;
     final SettingsObserver mSettingsObserver;
-    private final SparseBooleanArray mLoggedDeniedGetInputMethodWindowVisibleHeightForUid =
-            new SparseBooleanArray(0);
     final WindowManagerInternal mWindowManagerInternal;
     private final ActivityManagerInternal mActivityManagerInternal;
     final PackageManagerInternal mPackageManagerInternal;
@@ -1355,13 +1351,6 @@
             clearPackageChangeState();
         }
 
-        @Override
-        public void onUidRemoved(int uid) {
-            synchronized (ImfLock.class) {
-                mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.delete(uid);
-            }
-        }
-
         private void clearPackageChangeState() {
             // No need to lock them because we access these fields only on getRegisteredHandler().
             mChangedPackages.clear();
@@ -1830,10 +1819,8 @@
         }
 
         mLastSwitchUserId = newUserId;
-
         if (mIsInteractive && clientToBeReset != null) {
-            final ClientState cs =
-                    mClientController.mClients.get(clientToBeReset.asBinder());
+            final ClientState cs = mClientController.getClient(clientToBeReset.asBinder());
             if (cs == null) {
                 // The client is already gone.
                 return;
@@ -2176,26 +2163,25 @@
     /**
      * Hide the IME if the removed user is the current user.
      */
-    private void onClientRemoved(ClientController.ClientState client) {
-        synchronized (ImfLock.class) {
-            clearClientSessionLocked(client);
-            clearClientSessionForAccessibilityLocked(client);
-            if (mCurClient == client) {
-                hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                        null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
-                if (mBoundToMethod) {
-                    mBoundToMethod = false;
-                    IInputMethodInvoker curMethod = getCurMethodLocked();
-                    if (curMethod != null) {
-                        // When we unbind input, we are unbinding the client, so we always
-                        // unbind ime and a11y together.
-                        curMethod.unbindInput();
-                        AccessibilityManagerInternal.get().unbindInput();
-                    }
+    @GuardedBy("ImfLock.class")
+    private void onClientRemoved(ClientState client) {
+        clearClientSessionLocked(client);
+        clearClientSessionForAccessibilityLocked(client);
+        if (mCurClient == client) {
+            hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
+                    null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
+            if (mBoundToMethod) {
+                mBoundToMethod = false;
+                IInputMethodInvoker curMethod = getCurMethodLocked();
+                if (curMethod != null) {
+                    // When we unbind input, we are unbinding the client, so we always
+                    // unbind ime and a11y together.
+                    curMethod.unbindInput();
+                    AccessibilityManagerInternal.get().unbindInput();
                 }
-                mBoundToAccessibility = false;
-                mCurClient = null;
             }
+            mBoundToAccessibility = false;
+            mCurClient = null;
             if (mCurFocusedWindowClient == client) {
                 mCurFocusedWindowClient = null;
                 mCurFocusedWindowEditorInfo = null;
@@ -2203,7 +2189,6 @@
         }
     }
 
-    // TODO(b/314150112): Move this to ClientController.
     @GuardedBy("ImfLock.class")
     void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
         if (mCurClient != null) {
@@ -2400,16 +2385,6 @@
             @StartInputReason int startInputReason,
             int unverifiedTargetSdkVersion,
             @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
-        String selectedMethodId = getSelectedMethodIdLocked();
-
-        if (!mSystemReady) {
-            // If the system is not yet ready, we shouldn't be running third
-            // party code.
-            return new InputBindResult(
-                    InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
-                    null, null, null, selectedMethodId, getSequenceNumberLocked(), false);
-        }
-
         if (!InputMethodUtils.checkIfPackageBelongsToUid(mPackageManagerInternal, cs.mUid,
                 editorInfo.packageName)) {
             Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
@@ -2430,6 +2405,7 @@
 
         // Potentially override the selected input method if the new display belongs to a virtual
         // device with a custom IME.
+        String selectedMethodId = getSelectedMethodIdLocked();
         if (oldDisplayIdToShowIme != mDisplayIdToShowIme) {
             final String deviceMethodId = computeCurrentDeviceMethodIdLocked(selectedMethodId);
             if (deviceMethodId == null) {
@@ -2903,11 +2879,16 @@
     @GuardedBy("ImfLock.class")
     void clearClientSessionsLocked() {
         if (getCurMethodLocked() != null) {
-            final int numClients = mClientController.mClients.size();
-            for (int i = 0; i < numClients; ++i) {
-                clearClientSessionLocked(mClientController.mClients.valueAt(i));
-                clearClientSessionForAccessibilityLocked(mClientController.mClients.valueAt(i));
-            }
+            // TODO(b/322816970): Replace this with lambda.
+            mClientController.forAllClients(new Consumer<ClientState>() {
+
+                @GuardedBy("ImfLock.class")
+                @Override
+                public void accept(ClientState c) {
+                    clearClientSessionLocked(c);
+                    clearClientSessionForAccessibilityLocked(c);
+                }
+            });
 
             finishSessionLocked(mEnabledSession);
             for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
@@ -3674,7 +3655,6 @@
                         + "specified for cross-user startInputOrWindowGainedFocus()");
             }
         }
-
         if (windowToken == null) {
             Slog.e(TAG, "windowToken cannot be null.");
             return InputBindResult.NULL;
@@ -3686,6 +3666,14 @@
                     "InputMethodManagerService#startInputOrWindowGainedFocus");
             final InputBindResult result;
             synchronized (ImfLock.class) {
+                if (!mSystemReady) {
+                    // If the system is not yet ready, we shouldn't be running third arty code.
+                    return new InputBindResult(
+                            InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
+                            null /* method */, null /* accessibilitySessions */, null /* channel */,
+                            getSelectedMethodIdLocked(), getSequenceNumberLocked(),
+                            false /* isInputMethodSuppressingSpellChecker */);
+                }
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
@@ -3745,9 +3733,9 @@
             return InputBindResult.INVALID_USER;
         }
 
-        final ClientState cs = mClientController.mClients.get(client.asBinder());
+        final ClientState cs = mClientController.getClient(client.asBinder());
         if (cs == null) {
-            throw new IllegalArgumentException("unknown client " + client.asBinder());
+            throw new IllegalArgumentException("Unknown client " + client.asBinder());
         }
 
         final int imeClientFocus = mWindowManagerInternal.hasInputMethodClientFocus(
@@ -3919,8 +3907,7 @@
             // We need to check if this is the current client with
             // focus in the window manager, to allow this call to
             // be made before input is started in it.
-            final ClientState cs =
-                    mClientController.mClients.get(client.asBinder());
+            final ClientState cs = mClientController.getClient(client.asBinder());
             if (cs == null) {
                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
                 throw new IllegalArgumentException("unknown client " + client.asBinder());
@@ -4277,10 +4264,6 @@
             synchronized (ImfLock.class) {
                 if (!canInteractWithImeLocked(callingUid, client,
                         "getInputMethodWindowVisibleHeight", null /* statsToken */)) {
-                    if (!mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.get(callingUid)) {
-                        EventLog.writeEvent(0x534e4554, "204906124", callingUid, "");
-                        mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.put(callingUid, true);
-                    }
                     return 0;
                 }
                 // This should probably use the caller's display id, but because this is unsupported
@@ -4535,16 +4518,17 @@
     @Override
     public void startImeTrace() {
         super.startImeTrace_enforcePermission();
-
         ImeTracing.getInstance().startTrace(null /* printwriter */);
-        ArrayMap<IBinder, ClientState> clients;
         synchronized (ImfLock.class) {
-            clients = new ArrayMap<>(mClientController.mClients);
-        }
-        for (ClientState state : clients.values()) {
-            if (state != null) {
-                state.mClient.setImeTraceEnabled(true /* enabled */);
-            }
+            // TODO(b/322816970): Replace this with lambda.
+            mClientController.forAllClients(new Consumer<ClientState>() {
+
+                @GuardedBy("ImfLock.class")
+                @Override
+                public void accept(ClientState c) {
+                    c.mClient.setImeTraceEnabled(true /* enabled */);
+                }
+            });
         }
     }
 
@@ -4555,14 +4539,16 @@
         super.stopImeTrace_enforcePermission();
 
         ImeTracing.getInstance().stopTrace(null /* printwriter */);
-        ArrayMap<IBinder, ClientState> clients;
         synchronized (ImfLock.class) {
-            clients = new ArrayMap<>(mClientController.mClients);
-        }
-        for (ClientState state : clients.values()) {
-            if (state != null) {
-                state.mClient.setImeTraceEnabled(false /* enabled */);
-            }
+            // TODO(b/322816970): Replace this with lambda.
+            mClientController.forAllClients(new Consumer<ClientState>() {
+
+                @GuardedBy("ImfLock.class")
+                @Override
+                public void accept(ClientState c) {
+                    c.mClient.setImeTraceEnabled(false /* enabled */);
+                }
+            });
         }
     }
 
@@ -5796,11 +5782,15 @@
                 // We only have sessions when we bound to an input method. Remove this session
                 // from all clients.
                 if (getCurMethodLocked() != null) {
-                    final int numClients = mClientController.mClients.size();
-                    for (int i = 0; i < numClients; ++i) {
-                        clearClientSessionForAccessibilityLocked(
-                                mClientController.mClients.valueAt(i), accessibilityConnectionId);
-                    }
+                    // TODO(b/322816970): Replace this with lambda.
+                    mClientController.forAllClients(new Consumer<ClientState>() {
+
+                        @GuardedBy("ImfLock.class")
+                        @Override
+                        public void accept(ClientState c) {
+                            clearClientSessionForAccessibilityLocked(c, accessibilityConnectionId);
+                        }
+                    });
                     AccessibilitySessionState session = mEnabledAccessibilitySessions.get(
                             accessibilityConnectionId);
                     if (session != null) {
@@ -5984,19 +5974,26 @@
                 p.println("  InputMethod #" + i + ":");
                 info.dump(p, "    ");
             }
+            // Dump ClientController#mClients
             p.println("  ClientStates:");
-            // TODO(b/314150112): move client related dump info to ClientController#dump
-            final int numClients = mClientController.mClients.size();
-            for (int i = 0; i < numClients; ++i) {
-                final ClientState ci = mClientController.mClients.valueAt(i);
-                p.println("  " + ci + ":");
-                p.println("    client=" + ci.mClient);
-                p.println("    fallbackInputConnection=" + ci.mFallbackInputConnection);
-                p.println("    sessionRequested=" + ci.mSessionRequested);
-                p.println("    sessionRequestedForAccessibility="
-                        + ci.mSessionRequestedForAccessibility);
-                p.println("    curSession=" + ci.mCurSession);
-            }
+            // TODO(b/322816970): Replace this with lambda.
+            mClientController.forAllClients(new Consumer<ClientState>() {
+
+                @GuardedBy("ImfLock.class")
+                @Override
+                public void accept(ClientState c) {
+                    p.println("  " + c + ":");
+                    p.println("    client=" + c.mClient);
+                    p.println("    fallbackInputConnection="
+                            + c.mFallbackInputConnection);
+                    p.println("    sessionRequested="
+                            + c.mSessionRequested);
+                    p.println(
+                            "    sessionRequestedForAccessibility="
+                                    + c.mSessionRequestedForAccessibility);
+                    p.println("    curSession=" + c.mCurSession);
+                }
+            });
             p.println("  mCurMethodId=" + getSelectedMethodIdLocked());
             client = mCurClient;
             p.println("  mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
@@ -6600,14 +6597,16 @@
             }
         }
         boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
-        ArrayMap<IBinder, ClientState> clients;
         synchronized (ImfLock.class) {
-            clients = new ArrayMap<>(mClientController.mClients);
-        }
-        for (ClientState state : clients.values()) {
-            if (state != null) {
-                state.mClient.setImeTraceEnabled(isImeTraceEnabled);
-            }
+            // TODO(b/322816970): Replace this with lambda.
+            mClientController.forAllClients(new Consumer<ClientState>() {
+
+                @GuardedBy("ImfLock.class")
+                @Override
+                public void accept(ClientState c) {
+                    c.mClient.setImeTraceEnabled(isImeTraceEnabled);
+                }
+            });
         }
         return ShellCommandResult.SUCCESS;
     }
diff --git a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
index 5e38bca..2522f7b 100644
--- a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
@@ -27,6 +27,7 @@
 
 import android.annotation.Nullable;
 import android.location.Location;
+import android.location.LocationRequest;
 import android.location.LocationResult;
 import android.location.provider.ProviderRequest;
 import android.os.SystemClock;
@@ -179,6 +180,7 @@
     private void onThrottlingChangedLocked(boolean deliverImmediate) {
         long throttlingIntervalMs = INTERVAL_DISABLED;
         if (mDeviceStationary && mDeviceIdle && !mIncomingRequest.isLocationSettingsIgnored()
+                && mIncomingRequest.getQuality() != LocationRequest.QUALITY_HIGH_ACCURACY
                 && mLastLocation != null
                 && mLastLocation.getElapsedRealtimeAgeMillis(mDeviceStationaryRealtimeMs)
                 <= MAX_STATIONARY_LOCATION_AGE_MS) {
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index cc205d4..cc58f38 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -1541,8 +1541,14 @@
      */
     public @NonNull AuthenticationResult unlockTokenBasedProtector(
             IGateKeeperService gatekeeper, long protectorId, byte[] token, int userId) {
-        SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(loadState(SP_BLOB_NAME,
-                    protectorId, userId));
+        byte[] data = loadState(SP_BLOB_NAME, protectorId, userId);
+        if (data == null) {
+            AuthenticationResult result = new AuthenticationResult();
+            result.gkResponse = VerifyCredentialResponse.ERROR;
+            Slogf.w(TAG, "spblob not found for protector %016x, user %d", protectorId, userId);
+            return result;
+        }
+        SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(data);
         return unlockTokenBasedProtectorInternal(gatekeeper, protectorId, blob.mProtectorType,
                 token, userId);
     }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 2cd3ab1..7fabdf2 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -34,6 +34,8 @@
 import android.app.KeyguardManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.usage.UsageStatsManager;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -68,6 +70,7 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.PowerExemptionManager;
 import android.os.PowerManager;
 import android.os.Process;
@@ -100,7 +103,9 @@
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * System implementation of MediaSessionManager
@@ -145,6 +150,8 @@
     private AudioManager mAudioManager;
     private boolean mHasFeatureLeanback;
     private ActivityManagerInternal mActivityManagerInternal;
+    private UsageStatsManagerInternal mUsageStatsManagerInternal;
+    private final Set<Integer> mUserEngagingSessions = new HashSet<>();
 
     // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
     // It's always not null after the MediaSessionService is started.
@@ -230,6 +237,7 @@
         mContext.registerReceiver(mNotificationListenerEnabledChangedReceiver, filter);
 
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
     }
 
     @Override
@@ -287,10 +295,14 @@
                 }
                 user.mPriorityStack.onSessionActiveStateChanged(record);
             }
-            setForegroundServiceAllowance(
-                    record,
-                    /* allowRunningInForeground= */ record.isActive()
-                            && (playbackState == null || playbackState.isActive()));
+            boolean allowRunningInForeground = record.isActive()
+                    && (playbackState == null || playbackState.isActive());
+
+            Log.d(TAG, "onSessionActiveStateChanged: "
+                    + "record=" + record
+                    + "playbackState=" + playbackState
+                    + "allowRunningInForeground=" + allowRunningInForeground);
+            setForegroundServiceAllowance(record, allowRunningInForeground);
             mHandler.postSessionsChanged(record);
         }
     }
@@ -388,10 +400,12 @@
             }
             user.mPriorityStack.onPlaybackStateChanged(record, shouldUpdatePriority);
             if (playbackState != null) {
-                setForegroundServiceAllowance(
-                        record,
-                        /* allowRunningInForeground= */ playbackState.isActive()
-                                && record.isActive());
+                boolean allowRunningInForeground = playbackState.isActive() && record.isActive();
+                Log.d(TAG, "onSessionPlaybackStateChanged: "
+                        + "record=" + record
+                        + "playbackState=" + playbackState
+                        + "allowRunningInForeground=" + allowRunningInForeground);
+                setForegroundServiceAllowance(record, allowRunningInForeground);
             }
         }
     }
@@ -556,6 +570,8 @@
         }
 
         session.close();
+
+        Log.d(TAG, "destroySessionLocked: record=" + session);
         setForegroundServiceAllowance(session, /* allowRunningInForeground= */ false);
         mHandler.postSessionsChanged(session);
     }
@@ -574,12 +590,43 @@
         if (allowRunningInForeground) {
             mActivityManagerInternal.startForegroundServiceDelegate(
                     foregroundServiceDelegationOptions, /* connection= */ null);
+            reportMediaInteractionEvent(record, /* userEngaged= */ true);
         } else {
             mActivityManagerInternal.stopForegroundServiceDelegate(
                     foregroundServiceDelegationOptions);
+            reportMediaInteractionEvent(record, /* userEngaged= */ false);
         }
     }
 
+    private void reportMediaInteractionEvent(MediaSessionRecordImpl record, boolean userEngaged) {
+           if (!android.app.usage.Flags.userInteractionTypeApi()) {
+                return;
+            }
+
+            String packageName = record.getPackageName();
+            int sessionUid = record.getUid();
+            String actionToLog = null;
+            if (userEngaged) {
+                if (!mUserEngagingSessions.contains(sessionUid)) {
+                    actionToLog = "start";
+                }
+                mUserEngagingSessions.add(sessionUid);
+            } else {
+                if (mUserEngagingSessions.contains(sessionUid)) {
+                    actionToLog = "stop";
+                }
+                mUserEngagingSessions.remove(sessionUid);
+            }
+
+            if (actionToLog != null) {
+                PersistableBundle extras = new PersistableBundle();
+                extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "android.media");
+                extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, actionToLog);
+                mUsageStatsManagerInternal.reportUserInteractionEvent(
+                        packageName, record.getUserId(), extras);
+            }
+    }
+
     void tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage,
             int callingPid, int callingUid, String callingPackage, String reason) {
         final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
index df612e6..bbe6d3a 100644
--- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
@@ -20,6 +20,7 @@
 import android.content.pm.PackageManager;
 import android.media.MediaMetrics;
 import android.media.metrics.BundleSession;
+import android.media.metrics.EditingEndedEvent;
 import android.media.metrics.IMediaMetricsManager;
 import android.media.metrics.NetworkEvent;
 import android.media.metrics.PlaybackErrorEvent;
@@ -346,6 +347,24 @@
             StatsLog.write(statsEvent);
         }
 
+        @Override
+        public void reportEditingEndedEvent(String sessionId, EditingEndedEvent event, int userId) {
+            int level = loggingLevel();
+            if (level == LOGGING_LEVEL_BLOCKED) {
+                return;
+            }
+            StatsEvent statsEvent =
+                    StatsEvent.newBuilder()
+                            .setAtomId(798)
+                            .writeString(sessionId)
+                            .writeInt(event.getFinalState())
+                            .writeInt(event.getErrorCode())
+                            .writeLong(event.getTimeSinceCreatedMillis())
+                            .usePooledBuffer()
+                            .build();
+            StatsLog.write(statsEvent);
+        }
+
         private int loggingLevel() {
             synchronized (mLock) {
                 int uid = Binder.getCallingUid();
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 978f468..bbb19e3 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -35,6 +35,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions.LaunchCookie;
 import android.app.AppOpsManager;
 import android.app.IProcessObserver;
 import android.app.compat.CompatChanges;
@@ -548,8 +549,11 @@
                             DEFAULT_DISPLAY));
                     break;
                 case RECORD_CONTENT_TASK:
-                    setReviewedConsentSessionLocked(ContentRecordingSession.createTaskSession(
-                            mProjectionGrant.getLaunchCookie()));
+                    IBinder taskWindowContainerToken =
+                            mProjectionGrant.getLaunchCookie() == null ? null
+                                    : mProjectionGrant.getLaunchCookie().binder;
+                    setReviewedConsentSessionLocked(
+                            ContentRecordingSession.createTaskSession(taskWindowContainerToken));
                     break;
             }
         }
@@ -973,7 +977,7 @@
         private IBinder mToken;
         private IBinder.DeathRecipient mDeathEater;
         private boolean mRestoreSystemAlertWindow;
-        private IBinder mLaunchCookie = null;
+        private LaunchCookie mLaunchCookie = null;
 
         // Values for tracking token validity.
         // Timeout value to compare creation time against.
@@ -1186,14 +1190,14 @@
 
         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
         @Override // Binder call
-        public void setLaunchCookie(IBinder launchCookie) {
+        public void setLaunchCookie(LaunchCookie launchCookie) {
             setLaunchCookie_enforcePermission();
             mLaunchCookie = launchCookie;
         }
 
         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
         @Override // Binder call
-        public IBinder getLaunchCookie() {
+        public LaunchCookie getLaunchCookie() {
             getLaunchCookie_enforcePermission();
             return mLaunchCookie;
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 425659e..4da2cc9 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -10869,6 +10869,7 @@
             ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions();
             ArrayList<CharSequence> smartReplies = record.getSmartReplies();
             if (redactSensitiveNotificationsFromUntrustedListeners()
+                    && info != null
                     && !mListeners.isUidTrusted(info.uid)
                     && mListeners.hasSensitiveContent(record)) {
                 smartActions = null;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index c067fa0..fb95632 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -840,9 +840,13 @@
                 && !PACKAGE_ANDROID.equals(ruleToRemove.pkg)) {
             String deletedKey = ZenModeConfig.deletedRuleKey(ruleToRemove);
             if (deletedKey != null) {
-                ruleToRemove.deletionInstant = Instant.now(mClock);
+                ZenRule deletedRule = ruleToRemove.copy();
+                deletedRule.deletionInstant = Instant.now(mClock);
+                // If the rule is restored it shouldn't be active (or snoozed).
+                deletedRule.snoozing = false;
+                deletedRule.condition = null;
                 // Overwrites a previously-deleted rule with the same conditionId, but that's okay.
-                config.deletedRules.put(deletedKey, ruleToRemove);
+                config.deletedRules.put(deletedKey, deletedRule);
             }
         }
     }
@@ -1183,7 +1187,7 @@
                     != newPolicy.getPriorityConversationSenders()) {
                 userModifiedFields |= ZenPolicy.FIELD_CONVERSATIONS;
             }
-            if (oldPolicy.getPriorityChannels() != newPolicy.getPriorityChannels()) {
+            if (oldPolicy.getPriorityChannelsAllowed() != newPolicy.getPriorityChannelsAllowed()) {
                 userModifiedFields |= ZenPolicy.FIELD_ALLOW_CHANNELS;
             }
             if (oldPolicy.getPriorityCategoryReminders()
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 1660c3e..8452c0e 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -152,14 +152,13 @@
         @RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS,
                 conditional = true)
         void ensureCallerPreviouslyGeneratedFile(
-                Context context, Pair<Integer, String> callingInfo, int userId,
-                String bugreportFile, boolean forceUpdateMapping) {
+                Context context, PackageManager packageManager, Pair<Integer, String> callingInfo,
+                int userId, String bugreportFile, boolean forceUpdateMapping) {
             synchronized (mLock) {
                 if (onboardingBugreportV2Enabled()) {
                     final int uidForUser = Binder.withCleanCallingIdentity(() -> {
                         try {
-                            return context.getPackageManager()
-                                    .getPackageUidAsUser(callingInfo.second, userId);
+                            return packageManager.getPackageUidAsUser(callingInfo.second, userId);
                         } catch (PackageManager.NameNotFoundException exception) {
                             throwInvalidBugreportFileForCallerException(
                                     bugreportFile, callingInfo.second);
@@ -441,8 +440,8 @@
         Slogf.i(TAG, "Retrieving bugreport for %s / %d", callingPackage, callingUid);
         try {
             mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                    mContext, new Pair<>(callingUid, callingPackage), userId, bugreportFile,
-                    /* forceUpdateMapping= */ false);
+                    mContext, mContext.getPackageManager(), new Pair<>(callingUid, callingPackage),
+                    userId, bugreportFile, /* forceUpdateMapping= */ false);
         } catch (IllegalArgumentException e) {
             Slog.e(TAG, e.getMessage());
             reportError(listener, IDumpstateListener.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index a5bc2c3..98b7c96 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -24,6 +24,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.Flags;
 import android.content.pm.SigningDetails;
 import android.os.Binder;
 import android.os.Handler;
@@ -318,6 +319,11 @@
                 existingSettings.untrackedStorage());
     }
 
+    private static boolean isQueryableBySdkSandbox(int callingUid, int targetUid) {
+        return Flags.allowSdkSandboxQueryIntentActivities()
+                && targetUid == Process.getAppUidForSdkSandboxUid(callingUid);
+    }
+
     /**
      * See
      * {@link AppsFilterSnapshot#shouldFilterApplication(PackageDataSnapshot, int, Object,
@@ -338,9 +344,11 @@
             } else if (Process.isSdkSandboxUid(callingAppId)) {
                 final int targetAppId = targetPkgSetting.getAppId();
                 final int targetUid = UserHandle.getUid(userId, targetAppId);
-                // we only allow sdk sandbox processes access to forcequeryable packages
+                // we only allow sdk sandbox processes access to forcequeryable packages or
+                // if the target app is the sandbox's client app
                 return !isForceQueryable(targetPkgSetting.getAppId())
-                      && !isImplicitlyQueryable(callingUid, targetUid);
+                        && !isImplicitlyQueryable(callingUid, targetUid)
+                        && !isQueryableBySdkSandbox(callingUid, targetUid);
             }
             // use cache
             if (mCacheReady && mCacheEnabled) {
diff --git a/services/core/java/com/android/server/pm/BACKGROUND_INSTALL_OWNERS b/services/core/java/com/android/server/pm/BACKGROUND_INSTALL_OWNERS
new file mode 100644
index 0000000..baa41a5
--- /dev/null
+++ b/services/core/java/com/android/server/pm/BACKGROUND_INSTALL_OWNERS
@@ -0,0 +1,2 @@
+georgechan@google.com
+wenhaowang@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index ada79ae..e70c5ea 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -1049,6 +1049,18 @@
                 } finally {
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
+                if (Flags.improveInstallFreeze()) {
+                    // Postpone freezer until after reconcile
+                    for (ReconciledPackage reconciledPkg : reconciledPackages) {
+                        InstallRequest installRequest = reconciledPkg.mInstallRequest;
+                        String packageName = installRequest.getParsedPackage().getPackageName();
+                        PackageFreezer freezer = freezePackageForInstall(packageName,
+                                UserHandle.USER_ALL, installRequest.getInstallFlags(),
+                                "installPackageLI", ApplicationExitInfo.REASON_PACKAGE_UPDATED,
+                                installRequest);
+                        installRequest.setFreezer(freezer);
+                    }
+                }
                 try {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                     commitPackagesLocked(reconciledPackages, mPm.mUserManager.getUserIds());
@@ -1613,9 +1625,12 @@
             parsedPackage.setBaseApkPath(request.getApexInfo().modulePath);
         }
 
-        final PackageFreezer freezer =
-                freezePackageForInstall(pkgName, UserHandle.USER_ALL, installFlags,
-                        "installPackageLI", ApplicationExitInfo.REASON_PACKAGE_UPDATED, request);
+        PackageFreezer freezer = null;
+        if (!Flags.improveInstallFreeze()) {
+            freezer = freezePackageForInstall(pkgName, UserHandle.USER_ALL, installFlags,
+                    "installPackageLI", ApplicationExitInfo.REASON_PACKAGE_UPDATED, request);
+        }
+
 
         boolean shouldCloseFreezerBeforeReturn = true;
         try {
@@ -1865,9 +1880,11 @@
                     oldPackageState, parsedPackage, archivedPackage,
                     replace /* clearCodeCache */, sysPkg, ps, disabledPs);
         } finally {
-            request.setFreezer(freezer);
-            if (shouldCloseFreezerBeforeReturn) {
-                freezer.close();
+            if (freezer != null) {
+                request.setFreezer(freezer);
+                if (shouldCloseFreezerBeforeReturn) {
+                    freezer.close();
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index b5346a3..bc0173a 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -18,6 +18,10 @@
 
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_ARCHIVE_ICON_OVERLAY;
+import static android.app.AppOpsManager.OP_UNARCHIVAL_CONFIRMATION;
 import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
 import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
@@ -43,6 +47,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
 import android.app.IApplicationThread;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyCache;
@@ -213,6 +218,7 @@
         private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
         private final ShortcutServiceInternal mShortcutServiceInternal;
         private final PackageManagerInternal mPackageManagerInternal;
+        private final AppOpsManager mAppOpsManager;
         private final PackageCallbackList<IOnAppsChangedListener> mListeners
                 = new PackageCallbackList<IOnAppsChangedListener>();
         private final DevicePolicyManager mDpm;
@@ -253,6 +259,7 @@
                     LocalServices.getService(ShortcutServiceInternal.class));
             mPackageManagerInternal = Objects.requireNonNull(
                     LocalServices.getService(PackageManagerInternal.class));
+            mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
             mShortcutServiceInternal.addListener(mPackageMonitor);
             mShortcutChangeHandler = new ShortcutChangeHandler(mUserManagerInternal);
             mShortcutServiceInternal.addShortcutChangeCallback(mShortcutChangeHandler);
@@ -1997,6 +2004,23 @@
             }
         }
 
+        @Override
+        public void setArchiveCompatibilityOptions(boolean enableIconOverlay,
+                boolean enableUnarchivalConfirmation) {
+            int callingUid = Binder.getCallingUid();
+            Binder.withCleanCallingIdentity(
+                    () -> {
+                        mAppOpsManager.setUidMode(
+                                OP_ARCHIVE_ICON_OVERLAY,
+                                callingUid,
+                                enableIconOverlay ? MODE_ALLOWED : MODE_IGNORED);
+                        mAppOpsManager.setUidMode(
+                                OP_UNARCHIVAL_CONFIRMATION,
+                                callingUid,
+                                enableUnarchivalConfirmation ? MODE_ALLOWED : MODE_IGNORED);
+                    });
+        }
+
         /** Checks if user is a profile of or same as listeningUser.
          * and the user is enabled. */
         private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user,
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 84324f2..c8bc56c 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -51,3 +51,5 @@
 per-file ShortcutService.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
 per-file ShortcutUser.java = omakoto@google.com, yamasani@google.com, sunnygoyal@google.com, mett@google.com, pinyaoting@google.com
 
+# background install control service
+per-file BackgroundInstall* = file:BACKGROUND_INSTALL_OWNERS
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index 32f5646..474b590 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
 import static android.app.ActivityManager.START_PERMISSION_DENIED;
 import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
 import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap;
@@ -275,11 +276,12 @@
         Slog.i(TAG, TextUtils.formatSimple("Unarchival is starting for: %s", packageName));
 
         try {
-            // TODO(b/311709794) Make showUnarchivalConfirmation dependent on the compat options.
             requestUnarchive(packageName, callerPackageName,
                     getOrCreateLauncherListener(userId, packageName),
                     UserHandle.of(userId),
-                    false /* showUnarchivalConfirmation= */);
+                    getAppOpsManager().checkOp(
+                            AppOpsManager.OP_UNARCHIVAL_CONFIRMATION, callingUid, callerPackageName)
+                            == MODE_ALLOWED);
         } catch (Throwable t) {
             Slog.e(TAG, TextUtils.formatSimple(
                     "Unexpected error occurred while unarchiving package %s: %s.", packageName,
@@ -796,7 +798,8 @@
      * <p> The icon is returned without any treatment/overlay. In the rare case the app had multiple
      * launcher activities, only one of the icons is returned arbitrarily.
      */
-    public Bitmap getArchivedAppIcon(@NonNull String packageName, @NonNull UserHandle user) {
+    public Bitmap getArchivedAppIcon(@NonNull String packageName, @NonNull UserHandle user,
+            String callingPackageName) {
         Objects.requireNonNull(packageName);
         Objects.requireNonNull(user);
 
@@ -819,7 +822,13 @@
         // TODO(b/298452477) Handle monochrome icons.
         // In the rare case the archived app defined more than two launcher activities, we choose
         // the first one arbitrarily.
-        return includeCloudOverlay(decodeIcon(archiveState.getActivityInfos().get(0)));
+        Bitmap icon = decodeIcon(archiveState.getActivityInfos().get(0));
+        if (getAppOpsManager().checkOp(
+                AppOpsManager.OP_ARCHIVE_ICON_OVERLAY, callingUid, callingPackageName)
+                == MODE_ALLOWED) {
+            icon = includeCloudOverlay(icon);
+        }
+        return icon;
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 135bd4f..dfe705a7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6414,8 +6414,10 @@
         }
 
         @Override
-        public Bitmap getArchivedAppIcon(@NonNull String packageName, @NonNull UserHandle user) {
-            return mInstallerService.mPackageArchiver.getArchivedAppIcon(packageName, user);
+        public Bitmap getArchivedAppIcon(@NonNull String packageName, @NonNull UserHandle user,
+                @NonNull String callingPackageName) {
+            return mInstallerService.mPackageArchiver.getArchivedAppIcon(packageName, user,
+                    callingPackageName);
         }
 
         @Override
@@ -7807,7 +7809,8 @@
             mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
                     | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS
-                    | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+                    | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES
+                    | ActivityInfo.FLAG_HARDWARE_ACCELERATED;
             mResolveActivity.theme = 0;
             mResolveActivity.exported = true;
             mResolveActivity.enabled = true;
@@ -7841,7 +7844,8 @@
                 mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
                 mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
                         | ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY
-                        | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+                        | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES
+                        | ActivityInfo.FLAG_HARDWARE_ACCELERATED;
                 mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
                 mResolveActivity.exported = true;
                 mResolveActivity.enabled = true;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a97652c..7cf1d33 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -517,15 +517,6 @@
     @Watched(manual = true)
     private final AppIdSettingMap mAppIds;
 
-    // For reading/writing settings file.
-    @Watched
-    private final WatchedArrayList<Signature> mPastSignatures;
-    private final SnapshotCache<WatchedArrayList<Signature>> mPastSignaturesSnapshot;
-
-    @Watched
-    private final WatchedArrayMap<Long, Integer> mKeySetRefs;
-    private final SnapshotCache<WatchedArrayMap<Long, Integer>> mKeySetRefsSnapshot;
-
     // Packages that have been renamed since they were first installed.
     // Keys are the new names of the packages, values are the original
     // names.  The packages appear everywhere else under their original
@@ -613,8 +604,6 @@
         mNextAppLinkGeneration.registerObserver(mObserver);
         mPendingDefaultBrowser.registerObserver(mObserver);
         mPendingPackages.registerObserver(mObserver);
-        mPastSignatures.registerObserver(mObserver);
-        mKeySetRefs.registerObserver(mObserver);
     }
 
     // CONSTRUCTOR
@@ -641,12 +630,6 @@
         mCrossProfileIntentResolversSnapshot = new SnapshotCache.Auto<>(
                 mCrossProfileIntentResolvers, mCrossProfileIntentResolvers,
                 "Settings.mCrossProfileIntentResolvers");
-        mPastSignatures = new WatchedArrayList<>();
-        mPastSignaturesSnapshot = new SnapshotCache.Auto<>(mPastSignatures, mPastSignatures,
-                "Settings.mPastSignatures");
-        mKeySetRefs = new WatchedArrayMap<>();
-        mKeySetRefsSnapshot = new SnapshotCache.Auto<>(mKeySetRefs, mKeySetRefs,
-                "Settings.mKeySetRefs");
         mPendingPackages = new WatchedArrayList<>();
         mPendingPackagesSnapshot = new SnapshotCache.Auto<>(mPendingPackages, mPendingPackages,
                 "Settings.mPendingPackages");
@@ -702,12 +685,6 @@
         mCrossProfileIntentResolversSnapshot = new SnapshotCache.Auto<>(
                 mCrossProfileIntentResolvers, mCrossProfileIntentResolvers,
                 "Settings.mCrossProfileIntentResolvers");
-        mPastSignatures = new WatchedArrayList<>();
-        mPastSignaturesSnapshot = new SnapshotCache.Auto<>(mPastSignatures, mPastSignatures,
-                "Settings.mPastSignatures");
-        mKeySetRefs = new WatchedArrayMap<>();
-        mKeySetRefsSnapshot = new SnapshotCache.Auto<>(mKeySetRefs, mKeySetRefs,
-                "Settings.mKeySetRefs");
         mPendingPackages = new WatchedArrayList<>();
         mPendingPackagesSnapshot = new SnapshotCache.Auto<>(mPendingPackages, mPendingPackages,
                 "Settings.mPendingPackages");
@@ -799,11 +776,6 @@
         mSharedUsers.snapshot(r.mSharedUsers);
         mAppIds = r.mAppIds.snapshot();
 
-        mPastSignatures = r.mPastSignaturesSnapshot.snapshot();
-        mPastSignaturesSnapshot = new SnapshotCache.Sealed<>();
-        mKeySetRefs = r.mKeySetRefsSnapshot.snapshot();
-        mKeySetRefsSnapshot = new SnapshotCache.Sealed<>();
-
         mRenamedPackages.snapshot(r.mRenamedPackages);
         mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration);
         mPendingDefaultBrowser.snapshot(r.mPendingDefaultBrowser);
@@ -2755,7 +2727,7 @@
         // right time.
         invalidatePackageCache();
 
-        mPastSignatures.clear();
+        ArrayList<Signature> writtenSignatures = new ArrayList<>();
 
         try (ResilientAtomicFile atomicFile = getSettingsFile()) {
             FileOutputStream str = null;
@@ -2803,7 +2775,7 @@
                         // load
                         continue;
                     }
-                    writePackageLPr(serializer, pkg);
+                    writePackageLPr(serializer, writtenSignatures, pkg);
                 }
 
                 for (final PackageSetting pkg : mDisabledSysPackages.values()) {
@@ -2819,7 +2791,7 @@
                     serializer.startTag(null, "shared-user");
                     serializer.attribute(null, ATTR_NAME, usr.name);
                     serializer.attributeInt(null, "userId", usr.mAppId);
-                    usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
+                    usr.signatures.writeXml(serializer, "sigs", writtenSignatures);
                     serializer.endTag(null, "shared-user");
                 }
 
@@ -2859,6 +2831,7 @@
                 }
             }
         }
+
         //Debug.stopMethodTracing();
     }
 
@@ -3159,7 +3132,8 @@
         serializer.endTag(null, "updated-package");
     }
 
-    void writePackageLPr(TypedXmlSerializer serializer, final PackageSetting pkg)
+    void writePackageLPr(TypedXmlSerializer serializer, ArrayList<Signature> writtenSignatures,
+            PackageSetting pkg)
             throws java.io.IOException {
         serializer.startTag(null, "package");
         serializer.attribute(null, ATTR_NAME, pkg.getPackageName());
@@ -3259,11 +3233,11 @@
         writeUsesStaticLibLPw(serializer, pkg.getUsesStaticLibraries(),
                 pkg.getUsesStaticLibrariesVersions());
 
-        pkg.getSignatures().writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
+        pkg.getSignatures().writeXml(serializer, "sigs", writtenSignatures);
 
         if (installSource.mInitiatingPackageSignatures != null) {
             installSource.mInitiatingPackageSignatures.writeXml(
-                    serializer, "install-initiator-sigs", mPastSignatures.untrackedStorage());
+                    serializer, "install-initiator-sigs", writtenSignatures);
         }
 
         writeSigningKeySetLPr(serializer, pkg.getKeySetData());
@@ -3305,11 +3279,12 @@
     boolean readSettingsLPw(@NonNull Computer computer, @NonNull List<UserInfo> users,
             ArrayMap<String, Long> originalFirstInstallTimes) {
         mPendingPackages.clear();
-        mPastSignatures.clear();
-        mKeySetRefs.clear();
         mInstallerPackages.clear();
         originalFirstInstallTimes.clear();
 
+        ArrayMap<Long, Integer> keySetRefs = new ArrayMap<>();
+        ArrayList<Signature> readSignatures = new ArrayList<>();
+
         try (ResilientAtomicFile atomicFile = getSettingsFile()) {
             FileInputStream str = null;
             try {
@@ -3346,13 +3321,14 @@
 
                     String tagName = parser.getName();
                     if (tagName.equals("package")) {
-                        readPackageLPw(parser, users, originalFirstInstallTimes);
+                        readPackageLPw(parser, readSignatures, keySetRefs, users,
+                                originalFirstInstallTimes);
                     } else if (tagName.equals("permissions")) {
                         mPermissions.readPermissions(parser);
                     } else if (tagName.equals("permission-trees")) {
                         mPermissions.readPermissionTrees(parser);
                     } else if (tagName.equals("shared-user")) {
-                        readSharedUserLPw(parser, users);
+                        readSharedUserLPw(parser, readSignatures, users);
                     } else if (tagName.equals("preferred-packages")) {
                         // no longer used.
                     } else if (tagName.equals("preferred-activities")) {
@@ -3412,8 +3388,7 @@
                     } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
                         // No longer used.
                     } else if (tagName.equals("keyset-settings")) {
-                        mKeySetManagerService.readKeySetsLPw(parser,
-                                mKeySetRefs.untrackedStorage());
+                        mKeySetManagerService.readKeySetsLPw(parser, keySetRefs);
                     } else if (TAG_VERSION.equals(tagName)) {
                         final String volumeUuid = XmlUtils.readStringAttribute(parser,
                                 ATTR_VOLUME_UUID);
@@ -3437,7 +3412,7 @@
                 }
 
                 str.close();
-            } catch (IOException | XmlPullParserException e) {
+            } catch (IOException | XmlPullParserException | ArrayIndexOutOfBoundsException e) {
                 // Remove corrupted file and retry.
                 atomicFile.failRead(str, e);
 
@@ -4007,7 +3982,8 @@
     private static final int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1 << 28;
     private static final int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1 << 30;
 
-    private void readPackageLPw(TypedXmlPullParser parser, List<UserInfo> users,
+    private void readPackageLPw(TypedXmlPullParser parser, ArrayList<Signature> readSignatures,
+            ArrayMap<Long, Integer> keySetRefs,  List<UserInfo> users,
             ArrayMap<String, Long> originalFirstInstallTimes)
             throws XmlPullParserException, IOException {
         String name = null;
@@ -4282,8 +4258,7 @@
                 } else if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
                     readEnabledComponentsLPw(packageSetting, parser, 0);
                 } else if (tagName.equals("sigs")) {
-                    packageSetting.getSignatures()
-                            .readXml(parser,mPastSignatures.untrackedStorage());
+                    packageSetting.getSignatures().readXml(parser, readSignatures);
                 } else if (tagName.equals(TAG_PERMISSIONS)) {
                     final LegacyPermissionState legacyState;
                     if (packageSetting.hasSharedUser()) {
@@ -4300,11 +4275,11 @@
                     }
                 } else if (tagName.equals("proper-signing-keyset")) {
                     long id = parser.getAttributeLong(null, "identifier");
-                    Integer refCt = mKeySetRefs.get(id);
+                    Integer refCt = keySetRefs.get(id);
                     if (refCt != null) {
-                        mKeySetRefs.put(id, refCt + 1);
+                        keySetRefs.put(id, refCt + 1);
                     } else {
-                        mKeySetRefs.put(id, 1);
+                        keySetRefs.put(id, 1);
                     }
                     packageSetting.getKeySetData().setProperSigningKeySet(id);
                 } else if (tagName.equals("signing-keyset")) {
@@ -4315,16 +4290,16 @@
                 } else if (tagName.equals("defined-keyset")) {
                     long id = parser.getAttributeLong(null, "identifier");
                     String alias = parser.getAttributeValue(null, "alias");
-                    Integer refCt = mKeySetRefs.get(id);
+                    Integer refCt = keySetRefs.get(id);
                     if (refCt != null) {
-                        mKeySetRefs.put(id, refCt + 1);
+                        keySetRefs.put(id, refCt + 1);
                     } else {
-                        mKeySetRefs.put(id, 1);
+                        keySetRefs.put(id, 1);
                     }
                     packageSetting.getKeySetData().addDefinedKeySet(id, alias);
                 } else if (tagName.equals("install-initiator-sigs")) {
                     final PackageSignatures signatures = new PackageSignatures();
-                    signatures.readXml(parser, mPastSignatures.untrackedStorage());
+                    signatures.readXml(parser, readSignatures);
                     packageSetting.setInstallSource(
                             packageSetting.getInstallSource()
                                     .setInitiatingPackageSignatures(signatures));
@@ -4497,7 +4472,8 @@
         }
     }
 
-    private void readSharedUserLPw(TypedXmlPullParser parser, List<UserInfo> users)
+    private void readSharedUserLPw(TypedXmlPullParser parser, ArrayList<Signature> readSignatures,
+            List<UserInfo> users)
             throws XmlPullParserException, IOException {
         String name = null;
         int pkgFlags = 0;
@@ -4539,7 +4515,7 @@
 
                 String tagName = parser.getName();
                 if (tagName.equals("sigs")) {
-                    su.signatures.readXml(parser, mPastSignatures.untrackedStorage());
+                    su.signatures.readXml(parser, readSignatures);
                 } else if (tagName.equals("perms")) {
                     readInstallPermissionsLPr(parser, su.getLegacyPermissionState(), users);
                 } else {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a6598d6..c0596bb 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -295,8 +295,6 @@
 
     private static final int USER_VERSION = 11;
 
-    private static final int MAX_USER_STRING_LENGTH = 500;
-
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
     static final int WRITE_USER_MSG = 1;
@@ -4692,16 +4690,18 @@
         if (userData.persistSeedData) {
             if (userData.seedAccountName != null) {
                 serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME,
-                        truncateString(userData.seedAccountName));
+                        truncateString(userData.seedAccountName,
+                                UserManager.MAX_ACCOUNT_STRING_LENGTH));
             }
             if (userData.seedAccountType != null) {
                 serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE,
-                        truncateString(userData.seedAccountType));
+                        truncateString(userData.seedAccountType,
+                                UserManager.MAX_ACCOUNT_STRING_LENGTH));
             }
         }
         if (userInfo.name != null) {
             serializer.startTag(null, TAG_NAME);
-            serializer.text(truncateString(userInfo.name));
+            serializer.text(truncateString(userInfo.name, UserManager.MAX_USER_NAME_LENGTH));
             serializer.endTag(null, TAG_NAME);
         }
         synchronized (mRestrictionsLock) {
@@ -4765,11 +4765,11 @@
         serializer.endDocument();
     }
 
-    private String truncateString(String original) {
-        if (original == null || original.length() <= MAX_USER_STRING_LENGTH) {
+    private String truncateString(String original, int limit) {
+        if (original == null || original.length() <= limit) {
             return original;
         }
-        return original.substring(0, MAX_USER_STRING_LENGTH);
+        return original.substring(0, limit);
     }
 
     /*
@@ -5236,7 +5236,7 @@
             @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,
             @NonNull TimingsTraceAndSlog t, @Nullable Object token)
             throws UserManager.CheckedUserOperationException {
-        String truncatedName = truncateString(name);
+        String truncatedName = truncateString(name, UserManager.MAX_USER_NAME_LENGTH);
         final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
         if (userTypeDetails == null) {
             throwCheckedUserOperationException(
@@ -6821,9 +6821,14 @@
                     Slog.e(LOG_TAG, "No such user for settings seed data u=" + userId);
                     return;
                 }
-                userData.seedAccountName = truncateString(accountName);
-                userData.seedAccountType = truncateString(accountType);
-                userData.seedAccountOptions = accountOptions;
+                userData.seedAccountName = truncateString(accountName,
+                        UserManager.MAX_ACCOUNT_STRING_LENGTH);
+                userData.seedAccountType = truncateString(accountType,
+                        UserManager.MAX_ACCOUNT_STRING_LENGTH);
+                if (accountOptions != null && accountOptions.isBundleContentsWithinLengthLimit(
+                        UserManager.MAX_ACCOUNT_OPTIONS_LENGTH)) {
+                    userData.seedAccountOptions = accountOptions;
+                }
                 userData.persistSeedData = persist;
             }
             if (persist) {
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 14db70e..23d0230 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -288,6 +288,28 @@
      * configuration.
      */
     private static UserTypeDetails.Builder getDefaultTypeProfilePrivate() {
+        UserProperties.Builder userPropertiesBuilder = new UserProperties.Builder()
+                .setStartWithParent(true)
+                .setCredentialShareableWithParent(true)
+                .setAuthAlwaysRequiredToDisableQuietMode(true)
+                .setAllowStoppingUserWithDelayedLocking(true)
+                .setMediaSharedWithParent(false)
+                .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
+                .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
+                .setShowInQuietMode(
+                        UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
+                .setShowInSharingSurfaces(
+                        UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
+                .setCrossProfileIntentFilterAccessControl(
+                        UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
+                .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
+                .setCrossProfileContentSharingStrategy(
+                        UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT);
+        if (android.multiuser.Flags.supportHidingProfiles()) {
+            userPropertiesBuilder.setProfileApiVisibility(
+                    UserProperties.PROFILE_API_VISIBILITY_HIDDEN);
+        }
+
         return new UserTypeDetails.Builder()
                 .setName(USER_TYPE_PROFILE_PRIVATE)
                 .setBaseType(FLAG_PROFILE)
@@ -306,23 +328,7 @@
                 .setDarkThemeBadgeColors(
                         R.color.white)
                 .setDefaultRestrictions(getDefaultProfileRestrictions())
-                .setDefaultUserProperties(new UserProperties.Builder()
-                        .setStartWithParent(true)
-                        .setCredentialShareableWithParent(true)
-                        .setAuthAlwaysRequiredToDisableQuietMode(true)
-                        .setAllowStoppingUserWithDelayedLocking(true)
-                        .setMediaSharedWithParent(false)
-                        .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
-                        .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
-                        .setShowInQuietMode(
-                                UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
-                        .setShowInSharingSurfaces(
-                                UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
-                        .setCrossProfileIntentFilterAccessControl(
-                                UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
-                        .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
-                        .setCrossProfileContentSharingStrategy(
-                                UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT));
+                .setDefaultUserProperties(userPropertiesBuilder);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index f0ff85d..dd2b409 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -357,7 +357,8 @@
             verifierUser = UserHandle.of(mPm.mUserManager.getCurrentUserId());
         }
         // TODO(b/300965895): Remove when inconsistencies loading classpaths from apex for
-        // user > 1 are fixed.
+        // user > 1 are fixed. Tests should cover verifiers from apex classpaths run on
+        // primary user, secondary user and work profile.
         if (pkgLite.isSdkLibrary) {
             verifierUser = UserHandle.SYSTEM;
         }
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index d0fe964..6ed2d31 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -421,6 +421,11 @@
         if (ai.isArchived) {
             ai.nonLocalizedLabel = state.getArchiveState().getActivityInfos().get(0).getTitle();
         }
+        if (!state.isInstalled() && !state.dataExists()
+                && android.content.pm.Flags.nullableDataDir()) {
+            // The data dir has been deleted
+            ai.dataDir = null;
+        }
     }
 
     @Nullable
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0abf304..1fdcc64 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2185,6 +2185,10 @@
         TalkbackShortcutController getTalkbackShortcutController() {
             return new TalkbackShortcutController(mContext);
         }
+
+        WindowWakeUpPolicy getWindowWakeUpPolicy() {
+            return new WindowWakeUpPolicy(mContext);
+        }
     }
 
     /** {@inheritDoc} */
@@ -2433,7 +2437,7 @@
                 com.android.internal.R.integer.config_keyguardDrawnTimeout);
         mKeyguardDelegate = injector.getKeyguardServiceDelegate();
         mTalkbackShortcutController = injector.getTalkbackShortcutController();
-        mWindowWakeUpPolicy = new WindowWakeUpPolicy(mContext);
+        mWindowWakeUpPolicy = injector.getWindowWakeUpPolicy();
         initKeyCombinationRules();
         initSingleKeyGestureRules(injector.getLooper());
         mButtonOverridePermissionChecker = injector.getButtonOverridePermissionChecker();
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 09b19e6..25e749f 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -138,6 +138,7 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.net.module.util.NetworkCapabilitiesUtils;
+import com.android.server.power.optimization.Flags;
 import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
 
 import libcore.util.EmptyArray;
@@ -185,7 +186,8 @@
     // TODO: remove "tcp" from network methods, since we measure total stats.
 
     // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
-    public static final int VERSION = 214;
+    public static final int VERSION =
+            !Flags.disableSystemServicePowerAttr() ? 214 : 215;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -1753,7 +1755,9 @@
         mCpuUidActiveTimeReader = new KernelCpuUidActiveTimeReader(true, mClock);
         mCpuUidClusterTimeReader = new KernelCpuUidClusterTimeReader(true, mClock);
         mKernelWakelockReader = new KernelWakelockReader();
-        mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+        if (!Flags.disableSystemServicePowerAttr()) {
+            mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+        }
         mKernelMemoryBandwidthStats = new KernelMemoryBandwidthStats();
         mTmpRailStats = new RailStats();
     }
@@ -11459,7 +11463,7 @@
     @Override
     public BatteryStatsHistoryIterator iterateBatteryStatsHistory(long startTimeMs,
             long endTimeMs) {
-        return mHistory.copy().iterate(startTimeMs, endTimeMs);
+        return mHistory.iterate(startTimeMs, endTimeMs);
     }
 
     @Override
@@ -11702,7 +11706,9 @@
 
         EnergyConsumerStats.resetIfNotNull(mGlobalEnergyConsumerStats);
 
-        resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
+        if (!Flags.disableSystemServicePowerAttr()) {
+            resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
+        }
 
         mNumAllUidCpuTimeReads = 0;
         mNumUidsRemoved = 0;
@@ -13676,7 +13682,9 @@
                     mKernelCpuSpeedReaders[i].readDelta();
                 }
             }
-            mSystemServerCpuThreadReader.readDelta();
+            if (!Flags.disableSystemServicePowerAttr()) {
+                mSystemServerCpuThreadReader.readDelta();
+            }
             return;
         }
 
@@ -15696,23 +15704,25 @@
             }
         }
 
-        updateSystemServiceCallStats();
-        if (mBinderThreadCpuTimesUs != null) {
-            pw.println("Per UID System server binder time in ms:");
-            long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
-            for (int i = 0; i < size; i++) {
-                int u = mUidStats.keyAt(i);
-                Uid uid = mUidStats.get(u);
-                double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
-                long timeUs = 0;
-                for (int j = systemServiceTimeAtCpuSpeeds.length - 1; j >= 0; j--) {
-                    timeUs += systemServiceTimeAtCpuSpeeds[j] * proportionalSystemServiceUsage;
-                }
+        if (!Flags.disableSystemServicePowerAttr()) {
+            updateSystemServiceCallStats();
+            if (mBinderThreadCpuTimesUs != null) {
+                pw.println("Per UID System server binder time in ms:");
+                long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
+                for (int i = 0; i < size; i++) {
+                    int u = mUidStats.keyAt(i);
+                    Uid uid = mUidStats.get(u);
+                    double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
+                    long timeUs = 0;
+                    for (int j = systemServiceTimeAtCpuSpeeds.length - 1; j >= 0; j--) {
+                        timeUs += systemServiceTimeAtCpuSpeeds[j] * proportionalSystemServiceUsage;
+                    }
 
-                pw.print("  ");
-                pw.print(u);
-                pw.print(": ");
-                pw.println(timeUs / 1000);
+                    pw.print("  ");
+                    pw.print(u);
+                    pw.print(": ");
+                    pw.println(timeUs / 1000);
+                }
             }
         }
     }
@@ -16428,8 +16438,10 @@
             }
         }
 
-        mBinderThreadCpuTimesUs =
-                LongSamplingCounterArray.readSummaryFromParcelLocked(in, mOnBatteryTimeBase);
+        if (!Flags.disableSystemServicePowerAttr()) {
+            mBinderThreadCpuTimesUs =
+                    LongSamplingCounterArray.readSummaryFromParcelLocked(in, mOnBatteryTimeBase);
+        }
     }
 
     /**
@@ -16973,7 +16985,9 @@
             }
         }
 
-        LongSamplingCounterArray.writeSummaryToParcelLocked(out, mBinderThreadCpuTimesUs);
+        if (!Flags.disableSystemServicePowerAttr()) {
+            LongSamplingCounterArray.writeSummaryToParcelLocked(out, mBinderThreadCpuTimesUs);
+        }
     }
 
     @GuardedBy("this")
@@ -16985,7 +16999,9 @@
         // if we had originally pulled a time before the RTC was set.
         getStartClockTime();
 
-        updateSystemServiceCallStats();
+        if (!Flags.disableSystemServicePowerAttr()) {
+            updateSystemServiceCallStats();
+        }
     }
 
     @GuardedBy("this")
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 c3221e4..30b80ae 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -96,11 +96,13 @@
                 mPowerCalculators.add(new CustomEnergyConsumerPowerCalculator(mPowerProfile));
                 mPowerCalculators.add(new UserPowerCalculator());
 
-                // It is important that SystemServicePowerCalculator be applied last,
-                // because it re-attributes some of the power estimated by the other
-                // calculators.
-                mPowerCalculators.add(
-                        new SystemServicePowerCalculator(mCpuScalingPolicies, mPowerProfile));
+                if (!com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+                    // It is important that SystemServicePowerCalculator be applied last,
+                    // because it re-attributes some of the power estimated by the other
+                    // calculators.
+                    mPowerCalculators.add(
+                            new SystemServicePowerCalculator(mCpuScalingPolicies, mPowerProfile));
+                }
             }
         }
         return mPowerCalculators;
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
index cd3db36..ba4c127 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
@@ -74,8 +74,7 @@
             boolean clockUpdateAdded = false;
             long baseTime = startTimeMs > 0 ? startTimeMs : UNINITIALIZED;
             long lastTime = 0;
-            try (BatteryStatsHistoryIterator iterator =
-                         mHistory.copy().iterate(startTimeMs, endTimeMs)) {
+            try (BatteryStatsHistoryIterator iterator = mHistory.iterate(startTimeMs, endTimeMs)) {
                 while (iterator.hasNext()) {
                     BatteryStats.HistoryItem item = iterator.next();
 
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index 0f13571..6546646 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -13,3 +13,11 @@
     description: "Feature flag for streamlined battery stats"
     bug: "285646152"
 }
+
+flag {
+    name: "disable_system_service_power_attr"
+    namespace: "backstage_power"
+    description: "Deprecation of system service power re-attribution"
+    bug: "311793616"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index a4dbce6..3c0547e 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -527,6 +527,7 @@
         if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
         synchronized (sRequestLock) {
             if (!setupOrClearBcb(true, command)) {
+                Slog.e(TAG, "rebootRecoveryWithCommand failed to setup BCB");
                 return;
             }
 
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
index 141d4dc..9ee9b14 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
@@ -48,6 +48,8 @@
                     return isLskfCaptured();
                 case "reboot-and-apply":
                     return rebootAndApply();
+                case "wipe":
+                    return wipe();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -58,6 +60,18 @@
         }
     }
 
+    private int wipe() throws RemoteException {
+        PrintWriter pw = getOutPrintWriter();
+        String newFsType = getNextArg();
+        String command = "--wipe_data";
+        if (newFsType != null && !newFsType.isEmpty()) {
+            command += "\n--reformat_data=" + newFsType;
+        }
+        pw.println("Rebooting into recovery with " + command.replaceAll("\n", " "));
+        mService.rebootRecoveryWithCommand(command);
+        return 0;
+    }
+
     private int requestLskf() throws RemoteException {
         String packageName = getNextArgRequired();
         boolean success = mService.requestLskf(packageName, null);
@@ -104,5 +118,6 @@
         pw.println("  clear-lskf");
         pw.println("  is-lskf-captured <package_name>");
         pw.println("  reboot-and-apply <package_name> <reason>");
+        pw.println("  wipe <new filesystem type ext4/f2fs>");
     }
 }
diff --git a/services/core/java/com/android/server/selinux/QuotaLimiter.java b/services/core/java/com/android/server/selinux/QuotaLimiter.java
new file mode 100644
index 0000000..e89ddfd
--- /dev/null
+++ b/services/core/java/com/android/server/selinux/QuotaLimiter.java
@@ -0,0 +1,78 @@
+/*
+ * 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.server.selinux;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.Clock;
+
+import java.time.Duration;
+import java.time.Instant;
+
+/**
+ * A QuotaLimiter allows to define a maximum number of Atom pushes within a specific time window.
+ *
+ * <p>The limiter divides the time line in windows of a fixed size. Every time a new permit is
+ * requested, the limiter checks whether the previous request was in the same time window as the
+ * current one. If the two windows are the same, it grants a permit only if the number of permits
+ * granted within the window does not exceed the quota. If the two windows are different, it resets
+ * the quota.
+ */
+public class QuotaLimiter {
+
+    private final Clock mClock;
+    private final Duration mWindowSize;
+    private final int mMaxPermits;
+
+    private long mCurrentWindow = 0;
+    private int mPermitsGranted = 0;
+
+    @VisibleForTesting
+    QuotaLimiter(Clock clock, Duration windowSize, int maxPermits) {
+        mClock = clock;
+        mWindowSize = windowSize;
+        mMaxPermits = maxPermits;
+    }
+
+    public QuotaLimiter(Duration windowSize, int maxPermits) {
+        this(Clock.SYSTEM_CLOCK, windowSize, maxPermits);
+    }
+
+    public QuotaLimiter(int maxPermitsPerDay) {
+        this(Clock.SYSTEM_CLOCK, Duration.ofDays(1), maxPermitsPerDay);
+    }
+
+    /**
+     * Acquires a permit if there is one available in the current time window.
+     *
+     * @return true if a permit was acquired.
+     */
+    boolean acquire() {
+        long nowWindow =
+                Duration.between(Instant.EPOCH, Instant.ofEpochMilli(mClock.currentTimeMillis()))
+                        .dividedBy(mWindowSize);
+        if (nowWindow > mCurrentWindow) {
+            mCurrentWindow = nowWindow;
+            mPermitsGranted = 0;
+        }
+
+        if (mPermitsGranted < mMaxPermits) {
+            mPermitsGranted++;
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/services/core/java/com/android/server/selinux/RateLimiter.java b/services/core/java/com/android/server/selinux/RateLimiter.java
new file mode 100644
index 0000000..599b840
--- /dev/null
+++ b/services/core/java/com/android/server/selinux/RateLimiter.java
@@ -0,0 +1,85 @@
+/*
+ * 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.server.selinux;
+
+import android.os.SystemClock;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.Clock;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+
+/**
+ * Rate limiter to ensure Atoms are pushed only within the allowed QPS window. This class is not
+ * thread-safe.
+ *
+ * <p>The rate limiter is smoothed, meaning that a rate limiter allowing X permits per second (or X
+ * QPS) will grant permits at a ratio of one every 1/X seconds.
+ */
+public final class RateLimiter {
+
+    private Instant mNextPermit = Instant.EPOCH;
+
+    private final Clock mClock;
+    private final Duration mWindow;
+
+    @VisibleForTesting
+    RateLimiter(Clock clock, Duration window) {
+        mClock = clock;
+        // Truncating because the system clock does not support units smaller than milliseconds.
+        mWindow = window;
+    }
+
+    /**
+     * Create a rate limiter generating one permit every {@code window} of time, using the {@link
+     * Clock.SYSTEM_CLOCK}.
+     */
+    public RateLimiter(Duration window) {
+        this(Clock.SYSTEM_CLOCK, window);
+    }
+
+    /**
+     * Acquire a permit if allowed by the rate limiter. If not, wait until a permit becomes
+     * available.
+     */
+    public void acquire() {
+        Instant now = Instant.ofEpochMilli(mClock.currentTimeMillis());
+
+        if (mNextPermit.isAfter(now)) { // Sleep until we can acquire.
+            SystemClock.sleep(ChronoUnit.MILLIS.between(now, mNextPermit));
+            mNextPermit = mNextPermit.plus(mWindow);
+        } else {
+            mNextPermit = now.plus(mWindow);
+        }
+    }
+
+    /**
+     * Try to acquire a permit if allowed by the rate limiter. Non-blocking.
+     *
+     * @return true if a permit was acquired. Otherwise, return false.
+     */
+    public boolean tryAcquire() {
+        final Instant now = Instant.ofEpochMilli(mClock.currentTimeMillis());
+
+        if (mNextPermit.isAfter(now)) {
+            return false;
+        }
+        mNextPermit = now.plus(mWindow);
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/selinux/SelinuxAuditLogBuilder.java b/services/core/java/com/android/server/selinux/SelinuxAuditLogBuilder.java
new file mode 100644
index 0000000..8d8d596
--- /dev/null
+++ b/services/core/java/com/android/server/selinux/SelinuxAuditLogBuilder.java
@@ -0,0 +1,155 @@
+/*
+ * 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.server.selinux;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+/** Builder for SelinuxAuditLogs. */
+class SelinuxAuditLogBuilder {
+
+    // Currently logs collection is hardcoded for the sdk_sandbox_audit.
+    private static final String SDK_SANDBOX_AUDIT = "sdk_sandbox_audit";
+    static final Matcher SCONTEXT_MATCHER =
+            Pattern.compile(
+                            "u:r:(?<stype>"
+                                    + SDK_SANDBOX_AUDIT
+                                    + "):s0(:c)?(?<scategories>((,c)?\\d+)+)*")
+                    .matcher("");
+
+    static final Matcher TCONTEXT_MATCHER =
+            Pattern.compile("u:object_r:(?<ttype>\\w+):s0(:c)?(?<tcategories>((,c)?\\d+)+)*")
+                    .matcher("");
+
+    static final Matcher PATH_MATCHER =
+            Pattern.compile("\"(?<path>/\\w+(/\\w+)?)(/\\w+)*\"").matcher("");
+
+    private Iterator<String> mTokens;
+    private final SelinuxAuditLog mAuditLog = new SelinuxAuditLog();
+
+    void reset(String denialString) {
+        mTokens =
+                Arrays.asList(
+                                Optional.ofNullable(denialString)
+                                        .map(s -> s.split("\\s+|="))
+                                        .orElse(new String[0]))
+                        .iterator();
+        mAuditLog.reset();
+    }
+
+    SelinuxAuditLog build() {
+        while (mTokens.hasNext()) {
+            final String token = mTokens.next();
+
+            switch (token) {
+                case "granted":
+                    mAuditLog.mGranted = true;
+                    break;
+                case "denied":
+                    mAuditLog.mGranted = false;
+                    break;
+                case "{":
+                    Stream.Builder<String> permissionsStream = Stream.builder();
+                    boolean closed = false;
+                    while (!closed && mTokens.hasNext()) {
+                        String permission = mTokens.next();
+                        if ("}".equals(permission)) {
+                            closed = true;
+                        } else {
+                            permissionsStream.add(permission);
+                        }
+                    }
+                    if (!closed) {
+                        return null;
+                    }
+                    mAuditLog.mPermissions = permissionsStream.build().toArray(String[]::new);
+                    break;
+                case "scontext":
+                    if (!nextTokenMatches(SCONTEXT_MATCHER)) {
+                        return null;
+                    }
+                    mAuditLog.mSType = SCONTEXT_MATCHER.group("stype");
+                    mAuditLog.mSCategories = toCategories(SCONTEXT_MATCHER.group("scategories"));
+                    break;
+                case "tcontext":
+                    if (!nextTokenMatches(TCONTEXT_MATCHER)) {
+                        return null;
+                    }
+                    mAuditLog.mTType = TCONTEXT_MATCHER.group("ttype");
+                    mAuditLog.mTCategories = toCategories(TCONTEXT_MATCHER.group("tcategories"));
+                    break;
+                case "tclass":
+                    if (!mTokens.hasNext()) {
+                        return null;
+                    }
+                    mAuditLog.mTClass = mTokens.next();
+                    break;
+                case "path":
+                    if (nextTokenMatches(PATH_MATCHER)) {
+                        mAuditLog.mPath = PATH_MATCHER.group("path");
+                    }
+                    break;
+                case "permissive":
+                    if (!mTokens.hasNext()) {
+                        return null;
+                    }
+                    mAuditLog.mPermissive = "1".equals(mTokens.next());
+                    break;
+                default:
+                    break;
+            }
+        }
+        return mAuditLog;
+    }
+
+    boolean nextTokenMatches(Matcher matcher) {
+        return mTokens.hasNext() && matcher.reset(mTokens.next()).matches();
+    }
+
+    static int[] toCategories(String categories) {
+        return categories == null
+                ? null
+                : Arrays.stream(categories.split(",c")).mapToInt(Integer::parseInt).toArray();
+    }
+
+    static class SelinuxAuditLog {
+        boolean mGranted = false;
+        String[] mPermissions = null;
+        String mSType = null;
+        int[] mSCategories = null;
+        String mTType = null;
+        int[] mTCategories = null;
+        String mTClass = null;
+        String mPath = null;
+        boolean mPermissive = false;
+
+        private void reset() {
+            mGranted = false;
+            mPermissions = null;
+            mSType = null;
+            mSCategories = null;
+            mTType = null;
+            mTCategories = null;
+            mTClass = null;
+            mPath = null;
+            mPermissive = false;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java b/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java
new file mode 100644
index 0000000..0219645
--- /dev/null
+++ b/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java
@@ -0,0 +1,144 @@
+/*
+ * 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.server.selinux;
+
+import android.util.EventLog;
+import android.util.EventLog.Event;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.selinux.SelinuxAuditLogBuilder.SelinuxAuditLog;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Class in charge of collecting SELinux audit logs and push the SELinux atoms. */
+class SelinuxAuditLogsCollector {
+
+    private static final String TAG = "SelinuxAuditLogs";
+
+    private static final String SELINUX_PATTERN = "^.*\\bavc:\\s+(?<denial>.*)$";
+
+    @VisibleForTesting
+    static final Matcher SELINUX_MATCHER = Pattern.compile(SELINUX_PATTERN).matcher("");
+
+    private final RateLimiter mRateLimiter;
+    private final QuotaLimiter mQuotaLimiter;
+
+    @VisibleForTesting Instant mLastWrite = Instant.MIN;
+
+    final AtomicBoolean mStopRequested = new AtomicBoolean(false);
+
+    SelinuxAuditLogsCollector(RateLimiter rateLimiter, QuotaLimiter quotaLimiter) {
+        mRateLimiter = rateLimiter;
+        mQuotaLimiter = quotaLimiter;
+    }
+
+    /**
+     * Collect and push SELinux audit logs for the provided {@code tagCode}.
+     *
+     * @return true if the job was completed. If the job was interrupted, return false.
+     */
+    boolean collect(int tagCode) {
+        Queue<Event> logLines = new ArrayDeque<>();
+        Instant latestTimestamp = collectLogLines(tagCode, logLines);
+
+        boolean quotaExceeded = writeAuditLogs(logLines);
+        if (quotaExceeded) {
+            Log.w(TAG, "Too many SELinux logs in the queue, I am giving up.");
+            mLastWrite = latestTimestamp; // next run we will ignore all these logs.
+            logLines.clear();
+        }
+
+        return logLines.isEmpty();
+    }
+
+    private Instant collectLogLines(int tagCode, Queue<Event> logLines) {
+        List<Event> events = new ArrayList<>();
+        try {
+            EventLog.readEvents(new int[] {tagCode}, events);
+        } catch (IOException e) {
+            Log.e(TAG, "Error reading event logs", e);
+        }
+
+        Instant latestTimestamp = mLastWrite;
+        for (Event event : events) {
+            Instant eventTime = Instant.ofEpochSecond(0, event.getTimeNanos());
+            if (eventTime.isAfter(latestTimestamp)) {
+                latestTimestamp = eventTime;
+            }
+            if (eventTime.isBefore(mLastWrite)) {
+                continue;
+            }
+            Object eventData = event.getData();
+            if (!(eventData instanceof String)) {
+                continue;
+            }
+            logLines.add(event);
+        }
+        return latestTimestamp;
+    }
+
+    private boolean writeAuditLogs(Queue<Event> logLines) {
+        final SelinuxAuditLogBuilder auditLogBuilder = new SelinuxAuditLogBuilder();
+
+        while (!mStopRequested.get() && !logLines.isEmpty()) {
+            Event event = logLines.poll();
+            String logLine = (String) event.getData();
+            Instant logTime = Instant.ofEpochSecond(0, event.getTimeNanos());
+            if (!SELINUX_MATCHER.reset(logLine).matches()) {
+                continue;
+            }
+
+            auditLogBuilder.reset(SELINUX_MATCHER.group("denial"));
+            final SelinuxAuditLog auditLog = auditLogBuilder.build();
+            if (auditLog == null) {
+                continue;
+            }
+
+            if (!mQuotaLimiter.acquire()) {
+                return true;
+            }
+            mRateLimiter.acquire();
+
+            FrameworkStatsLog.write(
+                    FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                    auditLog.mGranted,
+                    auditLog.mPermissions,
+                    auditLog.mSType,
+                    auditLog.mSCategories,
+                    auditLog.mTType,
+                    auditLog.mTCategories,
+                    auditLog.mTClass,
+                    auditLog.mPath,
+                    auditLog.mPermissive);
+
+            if (logTime.isAfter(mLastWrite)) {
+                mLastWrite = logTime;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/services/core/java/com/android/server/selinux/SelinuxAuditLogsService.java b/services/core/java/com/android/server/selinux/SelinuxAuditLogsService.java
new file mode 100644
index 0000000..8a661bc
--- /dev/null
+++ b/services/core/java/com/android/server/selinux/SelinuxAuditLogsService.java
@@ -0,0 +1,132 @@
+/*
+ * 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.server.selinux;
+
+import static com.android.sdksandbox.flags.Flags.selinuxSdkSandboxAudit;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.EventLog;
+import android.util.Log;
+
+import java.time.Duration;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Scheduled jobs related to logging of SELinux denials and audits. The job runs daily on idle
+ * devices.
+ */
+public class SelinuxAuditLogsService extends JobService {
+
+    private static final String TAG = "SelinuxAuditLogs";
+    private static final String SELINUX_AUDIT_NAMESPACE = "SelinuxAuditLogsNamespace";
+
+    static final int AUDITD_TAG_CODE = EventLog.getTagCode("auditd");
+
+    private static final int SELINUX_AUDIT_JOB_ID = 25327386;
+    private static final JobInfo SELINUX_AUDIT_JOB =
+            new JobInfo.Builder(
+                            SELINUX_AUDIT_JOB_ID,
+                            new ComponentName("android", SelinuxAuditLogsService.class.getName()))
+                    .setPeriodic(TimeUnit.DAYS.toMillis(1))
+                    .setRequiresDeviceIdle(true)
+                    .setRequiresCharging(true)
+                    .setRequiresBatteryNotLow(true)
+                    .build();
+
+    private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
+    private static final AtomicReference<Boolean> IS_RUNNING = new AtomicReference<>(false);
+
+    // Audit logging is subject to both rate and quota limiting. We can only push one atom every 10
+    // milliseconds, and no more than 50K atoms can be pushed each day.
+    private static final SelinuxAuditLogsCollector AUDIT_LOGS_COLLECTOR =
+            new SelinuxAuditLogsCollector(
+                    new RateLimiter(/* window= */ Duration.ofMillis(10)),
+                    new QuotaLimiter(/* maxPermitsPerDay= */ 50000));
+
+    /** Schedule jobs with the {@link JobScheduler}. */
+    public static void schedule(Context context) {
+        if (!selinuxSdkSandboxAudit()) {
+            Log.d(TAG, "SelinuxAuditLogsService not enabled");
+            return;
+        }
+
+        if (AUDITD_TAG_CODE == -1) {
+            Log.e(TAG, "auditd is not a registered tag on this system");
+            return;
+        }
+
+        if (context.getSystemService(JobScheduler.class)
+                        .forNamespace(SELINUX_AUDIT_NAMESPACE)
+                        .schedule(SELINUX_AUDIT_JOB)
+                == JobScheduler.RESULT_FAILURE) {
+            Log.e(TAG, "SelinuxAuditLogsService could not be started.");
+        }
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        if (params.getJobId() != SELINUX_AUDIT_JOB_ID) {
+            Log.e(TAG, "The job id does not match the expected selinux job id.");
+            return false;
+        }
+
+        AUDIT_LOGS_COLLECTOR.mStopRequested.set(false);
+        IS_RUNNING.set(true);
+        EXECUTOR_SERVICE.execute(new LogsCollectorJob(this, params));
+
+        return true; // the job is running
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        if (params.getJobId() != SELINUX_AUDIT_JOB_ID) {
+            return false;
+        }
+
+        AUDIT_LOGS_COLLECTOR.mStopRequested.set(true);
+        return IS_RUNNING.get();
+    }
+
+    private static class LogsCollectorJob implements Runnable {
+        private final JobService mAuditLogService;
+        private final JobParameters mParams;
+
+        LogsCollectorJob(JobService auditLogService, JobParameters params) {
+            mAuditLogService = auditLogService;
+            mParams = params;
+        }
+
+        @Override
+        public void run() {
+            IS_RUNNING.updateAndGet(
+                    isRunning -> {
+                        boolean done = AUDIT_LOGS_COLLECTOR.collect(AUDITD_TAG_CODE);
+                        if (done) {
+                            mAuditLogService.jobFinished(mParams, /* wantsReschedule= */ false);
+                        }
+                        return !done;
+                    });
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java b/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
index 6677e7e..1526230 100644
--- a/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
+++ b/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
@@ -36,10 +36,12 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
+import android.location.flags.Flags;
 import android.os.Bundle;
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.TypedValue;
 
 import com.android.internal.util.Preconditions;
 import com.android.server.FgThread;
@@ -70,6 +72,10 @@
     private static final String EXTRA_SERVICE_VERSION = "serviceVersion";
     private static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
 
+    // a package value that will never match against any package (we can't use null since this will
+    // match against any package).
+    private static final String NO_MATCH_PACKAGE = "";
+
     private static final Comparator<BoundServiceInfo> sBoundServiceInfoComparator = (o1, o2) -> {
         if (o1 == o2) {
             return 0;
@@ -196,7 +202,19 @@
         Resources resources = context.getResources();
         boolean enableOverlay = resources.getBoolean(enableOverlayResId);
         if (!enableOverlay) {
-            return resources.getString(nonOverlayPackageResId);
+            if (Flags.fixServiceWatcher()) {
+                // we don't use getText() or similar because it won't return null values
+                TypedValue out = new TypedValue();
+                resources.getValue(nonOverlayPackageResId, out, true);
+                CharSequence explicitPackage = out.coerceToString();
+                if (explicitPackage == null) {
+                    return NO_MATCH_PACKAGE;
+                } else {
+                    return explicitPackage.toString();
+                }
+            } else {
+                return resources.getString(nonOverlayPackageResId);
+            }
         } else {
             return null;
         }
@@ -233,6 +251,10 @@
 
     @Override
     public boolean hasMatchingService() {
+        if (Flags.fixServiceWatcher() && NO_MATCH_PACKAGE.equals(mIntent.getPackage())) {
+            return false;
+        }
+
         int intentQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
         if (mMatchSystemAppsOnly) {
             intentQueryFlags |= MATCH_SYSTEM_ONLY;
@@ -268,6 +290,10 @@
 
     @Override
     public BoundServiceInfo getServiceInfo() {
+        if (Flags.fixServiceWatcher() && NO_MATCH_PACKAGE.equals(mIntent.getPackage())) {
+            return null;
+        }
+
         BoundServiceInfo bestServiceInfo = null;
 
         // only allow services in the correct direct boot state to match
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 285bcc3..0ffd002 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2058,7 +2058,8 @@
     }
 
     private void registerCpuCyclesPerThreadGroupCluster() {
-        if (KernelCpuBpfTracking.isSupported()) {
+        if (KernelCpuBpfTracking.isSupported()
+                && !com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
             int tagId = FrameworkStatsLog.CPU_CYCLES_PER_THREAD_GROUP_CLUSTER;
             PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                     .setAdditiveFields(new int[]{3, 4})
@@ -2073,6 +2074,10 @@
     }
 
     int pullCpuCyclesPerThreadGroupCluster(int atomTag, List<StatsEvent> pulledData) {
+        if (com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+            return StatsManager.PULL_SKIP;
+        }
+
         SystemServiceCpuThreadTimes times = LocalServices.getService(BatteryStatsInternal.class)
                 .getSystemServiceCpuThreadTimes();
         if (times == null) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index e5a8a6d..dbf777f 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -83,7 +83,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.SystemService;
-import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -160,7 +159,6 @@
     private final ActivityManager mActivityManager;
     private FingerprintManager mFingerprintManager;
     private FaceManager mFaceManager;
-    private VirtualDeviceManagerInternal mVirtualDeviceManager;
 
     private enum TrustState {
         // UNTRUSTED means that TrustManagerService is currently *not* giving permission for the
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index d7b8495..eacd3f8 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -2390,6 +2390,33 @@
         }
 
         @Override
+        public void sendCertificate(IBinder sessionToken, String host, int port,
+                Bundle certBundle, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "sendCertificate(host=%s port=%d cert=%s)", host, port,
+                        certBundle);
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "sendCertificate");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).sendCertificate(host, port, certBundle);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in sendCertificate", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void notifyError(IBinder sessionToken, String errMsg, Bundle params, int userId) {
             if (DEBUG) {
                 Slogf.d(TAG, "notifyError(errMsg=%s)", errMsg);
@@ -4125,6 +4152,43 @@
         }
 
         @Override
+        public void onRequestSigning2(String id, String algorithm, String host,
+                int port, byte[] data) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRequestSigning");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRequestSigning2(
+                            id, algorithm, host, port, data, mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRequestSigning", e);
+                }
+            }
+        }
+
+        @Override
+        public void onRequestCertificate(String host, int port) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRequestCertificate");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRequestCertificate(host, port, mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRequestCertificate", e);
+                }
+            }
+        }
+
+
+        @Override
         public void onAdRequest(AdRequest request) {
             synchronized (mLock) {
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
index 19fd9a9..9e1b5d2 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
@@ -96,7 +96,8 @@
             }
             if (populateOrientationPairs) {
                 int orientation = WallpaperManager.getOrientation(displaySize);
-                float newSurface = displaySize.x * displaySize.y * metric.getDensity();
+                float newSurface = displaySize.x * displaySize.y
+                        / (metric.getDensity() * metric.getDensity());
                 if (surface <= 0) {
                     surface = newSurface;
                     firstOrientation = orientation;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 2d584c4..fa8c35a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -462,17 +462,16 @@
         }
     }
 
-    // TODO(b/318327737): Remove parameter 't' when removing flag DRAW_IN_WM_LOCK.
-    void drawMagnifiedRegionBorderIfNeeded(int displayId, SurfaceControl.Transaction t) {
+    void drawMagnifiedRegionBorderIfNeeded(int displayId) {
         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
             mAccessibilityTracing.logTrace(
                     TAG + ".drawMagnifiedRegionBorderIfNeeded",
                     FLAGS_MAGNIFICATION_CALLBACK,
-                    "displayId=" + displayId + "; transaction={" + t + "}");
+                    "displayId=" + displayId);
         }
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
         if (displayMagnifier != null) {
-            displayMagnifier.drawMagnifiedRegionBorderIfNeeded(t);
+            displayMagnifier.drawMagnifiedRegionBorderIfNeeded();
         }
         // Not relevant for the window observer.
     }
@@ -870,12 +869,12 @@
                     .sendToTarget();
         }
 
-        void drawMagnifiedRegionBorderIfNeeded(SurfaceControl.Transaction t) {
+        void drawMagnifiedRegionBorderIfNeeded() {
             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                 mAccessibilityTracing.logTrace(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded",
-                        FLAGS_MAGNIFICATION_CALLBACK, "transition={" + t + "}");
+                        FLAGS_MAGNIFICATION_CALLBACK);
             }
-            mMagnifedViewport.drawWindowIfNeeded(t);
+            mMagnifedViewport.drawWindowIfNeeded();
         }
 
         void dump(PrintWriter pw, String prefix) {
@@ -1121,14 +1120,6 @@
             }
 
             void setMagnifiedRegionBorderShown(boolean shown, boolean animate) {
-                if (ViewportWindow.DRAW_IN_WM_LOCK) {
-                    if (shown) {
-                        mFullRedrawNeeded = true;
-                        mOldMagnificationRegion.set(0, 0, 0, 0);
-                    }
-                    mWindow.setShown(shown, animate);
-                    return;
-                }
                 if (mWindow.setShown(shown, animate)) {
                     mFullRedrawNeeded = true;
                     // Clear the old region, so recomputeBounds will refresh the current region.
@@ -1151,12 +1142,8 @@
                 return mMagnificationSpec;
             }
 
-            void drawWindowIfNeeded(SurfaceControl.Transaction t) {
+            void drawWindowIfNeeded() {
                 recomputeBounds();
-                if (ViewportWindow.DRAW_IN_WM_LOCK) {
-                    mWindow.drawOrRemoveIfNeeded(t);
-                    return;
-                }
                 mWindow.postDrawIfNeeded();
             }
 
@@ -1187,8 +1174,6 @@
 
             private final class ViewportWindow implements Runnable {
                 private static final String SURFACE_TITLE = "Magnification Overlay";
-                // TODO(b/318327737): Remove if it is stable.
-                static final boolean DRAW_IN_WM_LOCK = !Flags.drawMagnifierBorderOutsideWmlock();
 
                 private final Region mBounds = new Region();
                 private final Rect mDirtyRect = new Rect();
@@ -1328,14 +1313,14 @@
 
                 @Override
                 public void run() {
-                    drawOrRemoveIfNeeded(mTransaction);
+                    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(SurfaceControl.Transaction t) {
+                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.
@@ -1343,7 +1328,7 @@
                     Rect drawingRect = null;
                     Region drawingBounds = null;
                     synchronized (mService.mGlobalLock) {
-                        if (!DRAW_IN_WM_LOCK && mBlastBufferQueue.mNativeObject == 0) {
+                        if (mBlastBufferQueue.mNativeObject == 0) {
                             // Complete removal since releaseSurface has been called.
                             if (mSurface.isValid()) {
                                 mTransaction.remove(mSurfaceControl).apply();
@@ -1388,16 +1373,8 @@
                         mPaint.setAlpha(alpha);
                         canvas.drawPath(drawingBounds.getBoundaryPath(), mPaint);
                         mSurface.unlockCanvasAndPost(canvas);
-                        if (DRAW_IN_WM_LOCK) {
-                            t.show(mSurfaceControl);
-                            return;
-                        }
                         showSurface = true;
                     } else {
-                        if (DRAW_IN_WM_LOCK) {
-                            t.hide(mSurfaceControl);
-                            return;
-                        }
                         showSurface = false;
                     }
 
@@ -1413,11 +1390,6 @@
                 @GuardedBy("mService.mGlobalLock")
                 void releaseSurface() {
                     mBlastBufferQueue.destroy();
-                    if (DRAW_IN_WM_LOCK) {
-                        mService.mTransactionFactory.get().remove(mSurfaceControl).apply();
-                        mSurface.release();
-                        return;
-                    }
                     // Post to perform cleanup on the thread which handles mSurface.
                     mService.mAnimationHandler.post(this);
                 }
@@ -1568,16 +1540,12 @@
 
         private static final boolean DEBUG = false;
 
-        private final List<AccessibilityWindow> mTempA11yWindows = new ArrayList<>();
-
         private final Set<IBinder> mTempBinderSet = new ArraySet<>();
 
         private final Point mTempPoint = new Point();
 
         private final Region mTempRegion = new Region();
 
-        private final Region mTempRegion1 = new Region();
-
         private final Region mTempRegion2 = new Region();
 
         private final WindowManagerService mService;
@@ -1645,7 +1613,8 @@
                 Slog.i(LOG_TAG, "computeChangedWindows()");
             }
 
-            List<WindowInfo> windows = new ArrayList<>();
+            final List<WindowInfo> windows = new ArrayList<>();
+            final List<AccessibilityWindow> visibleWindows = new ArrayList<>();
             final int topFocusedDisplayId;
             IBinder topFocusedWindowToken = null;
 
@@ -1680,7 +1649,6 @@
                 Region unaccountedSpace = mTempRegion;
                 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
 
-                final List<AccessibilityWindow> visibleWindows = mTempA11yWindows;
                 mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
                         mDisplayId, visibleWindows);
                 Set<IBinder> addedWindows = mTempBinderSet;
@@ -1737,7 +1705,6 @@
                     }
                 }
 
-                visibleWindows.clear();
                 addedWindows.clear();
 
                 // Gets the top focused display Id and window token for supporting multi-display.
@@ -1748,7 +1715,9 @@
                     topFocusedWindowToken, windows);
 
             // Recycle the windows as we do not need them.
-            clearAndRecycleWindows(windows);
+            for (final AccessibilityWindowsPopulator.AccessibilityWindow window : visibleWindows) {
+                window.getWindowInfo().recycle();
+            }
             mInitialized = true;
         }
 
@@ -1830,13 +1799,6 @@
             tokenOut.add(window.token);
         }
 
-        private static void clearAndRecycleWindows(List<WindowInfo> windows) {
-            final int windowCount = windows.size();
-            for (int i = windowCount - 1; i >= 0; i--) {
-                windows.remove(i).recycle();
-            }
-        }
-
         private static boolean isReportedWindowType(int windowType) {
             return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
                     && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3d492bb..b1d04c9 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -53,6 +53,7 @@
 import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
 import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
 import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
+import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.content.Intent.ACTION_MAIN;
 import static android.content.Intent.CATEGORY_HOME;
 import static android.content.Intent.CATEGORY_LAUNCHER;
@@ -544,9 +545,6 @@
     boolean launchFailed;   // set if a launched failed, to abort on 2nd try
     boolean delayedResume;  // not yet resumed because of stopped app switches?
     boolean finishing;      // activity in pending finish list?
-    boolean deferRelaunchUntilPaused;   // relaunch of activity is being deferred until pause is
-                                        // completed
-    boolean preserveWindowOnDeferredRelaunch; // activity windows are preserved on deferred relaunch
     int configChangeFlags;  // which config values have changed
     private boolean keysPaused;     // has key dispatching been paused for it?
     int launchMode;         // the launch mode activity attribute.
@@ -1276,10 +1274,8 @@
         if (mDeferHidingClient) {
             pw.println(prefix + "mDeferHidingClient=" + mDeferHidingClient);
         }
-        if (deferRelaunchUntilPaused || configChangeFlags != 0) {
-            pw.print(prefix); pw.print("deferRelaunchUntilPaused=");
-                    pw.print(deferRelaunchUntilPaused);
-                    pw.print(" configChangeFlags=");
+        if (configChangeFlags != 0) {
+            pw.print(prefix); pw.print(" configChangeFlags=");
                     pw.println(Integer.toHexString(configChangeFlags));
         }
         if (mServiceConnectionsHolder != null) {
@@ -2136,7 +2132,6 @@
         launchFailed = false;
         delayedResume = false;
         finishing = false;
-        deferRelaunchUntilPaused = false;
         keysPaused = false;
         inHistory = false;
         nowVisible = false;
@@ -2231,7 +2226,17 @@
 
         mOptInOnBackInvoked = WindowOnBackInvokedDispatcher
                 .isOnBackInvokedCallbackEnabled(info, info.applicationInfo,
-                        () -> ent != null ? ent.array : null, false);
+                        () -> {
+                            Context appContext = null;
+                            try {
+                                appContext = mAtmService.mContext.createPackageContextAsUser(
+                                        info.packageName, CONTEXT_RESTRICTED,
+                                        UserHandle.of(mUserId));
+                                appContext.setTheme(theme);
+                            } catch (PackageManager.NameNotFoundException ignore) {
+                            }
+                            return appContext;
+                        });
     }
 
     /**
@@ -2635,10 +2640,20 @@
         if (snapshot == null) {
             return false;
         }
-        if (!snapshot.getTopActivityComponent().equals(mActivityComponent)) {
-            // Obsoleted snapshot.
-            return false;
-        }
+        return isSnapshotComponentCompatible(snapshot) && isSnapshotOrientationCompatible(snapshot);
+    }
+
+    /**
+     * Returns {@code true} if the top activity component of task snapshot equals to this activity.
+     */
+    boolean isSnapshotComponentCompatible(@NonNull TaskSnapshot snapshot) {
+        return snapshot.getTopActivityComponent().equals(mActivityComponent);
+    }
+
+    /**
+     * Returns {@code true} if the orientation of task snapshot is compatible with this activity.
+     */
+    boolean isSnapshotOrientationCompatible(@NonNull TaskSnapshot snapshot) {
         final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(this);
         final int currentRotation = task.getWindowConfiguration().getRotation();
         final int targetRotation = rotation != ROTATION_UNDEFINED
@@ -4075,8 +4090,6 @@
         // Clean up the splash screen if it was still displayed.
         cleanUpSplashScreen();
 
-        deferRelaunchUntilPaused = false;
-
         if (setState) {
             setState(DESTROYED, "cleanUp");
             if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + this);
@@ -6460,9 +6473,6 @@
             mAppStopped = true;
             ProtoLog.v(WM_DEBUG_STATES, "Stop failed; moving to STOPPED: %s", this);
             setState(STOPPED, "stopIfPossible");
-            if (deferRelaunchUntilPaused) {
-                destroyImmediately("stop-except");
-            }
         }
     }
 
@@ -6518,12 +6528,7 @@
         if (finishing) {
             abortAndClearOptionsAnimation();
         } else {
-            if (deferRelaunchUntilPaused) {
-                destroyImmediately("stop-config");
-                mRootWindowContainer.resumeFocusedTasksTopActivities();
-            } else {
-                mAtmService.updatePreviousProcess(this);
-            }
+            mAtmService.updatePreviousProcess(this);
         }
         mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
     }
@@ -9703,23 +9708,12 @@
             } else {
                 mRelaunchReason = RELAUNCH_REASON_NONE;
             }
-            if (mState == PAUSING) {
-                // A little annoying: we are waiting for this activity to finish pausing. Let's not
-                // do anything now, but just flag that it needs to be restarted when done pausing.
-                ProtoLog.v(WM_DEBUG_CONFIGURATION,
-                        "Config is skipping already pausing %s", this);
-                deferRelaunchUntilPaused = true;
-                preserveWindowOnDeferredRelaunch = preserveWindow;
-                return true;
-            } else {
-                ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s",
-                        this);
-                if (!mVisibleRequested) {
-                    ProtoLog.v(WM_DEBUG_STATES, "Config is relaunching invisible "
-                            + "activity %s called by %s", this, Debug.getCallers(4));
-                }
-                relaunchActivityLocked(preserveWindow);
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s", this);
+            if (!mVisibleRequested) {
+                ProtoLog.v(WM_DEBUG_STATES, "Config is relaunching invisible "
+                        + "activity %s called by %s", this, Debug.getCallers(4));
             }
+            relaunchActivityLocked(preserveWindow);
 
             // All done...  tell the caller we weren't able to keep this activity around.
             return false;
@@ -9937,8 +9931,6 @@
         mTaskSupervisor.mStoppingActivities.remove(this);
 
         configChangeFlags = 0;
-        deferRelaunchUntilPaused = false;
-        preserveWindowOnDeferredRelaunch = false;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
index a692167..1f013b9 100644
--- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java
+++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
@@ -31,8 +31,6 @@
 import android.window.TaskSnapshot;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
 import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider;
 import com.android.window.flags.Flags;
 
@@ -163,18 +161,12 @@
     private void cleanUpUserFiles(int userId) {
         synchronized (mSnapshotPersistQueue.getLock()) {
             mSnapshotPersistQueue.sendToQueueLocked(
-                    new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) {
-                        @Override
-                        boolean isReady() {
-                            final UserManagerInternal mUserManagerInternal =
-                                    LocalServices.getService(UserManagerInternal.class);
-                            return mUserManagerInternal.isUserUnlocked(userId);
-                        }
+                    new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider, userId) {
 
                         @Override
                         void write() {
                             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "cleanUpUserFiles");
-                            final File file = mPersistInfoProvider.getDirectory(userId);
+                            final File file = mPersistInfoProvider.getDirectory(mUserId);
                             if (file.exists()) {
                                 final File[] contents = file.listFiles();
                                 if (contents != null) {
@@ -263,15 +255,13 @@
 
     class LoadActivitySnapshotItem extends SnapshotPersistQueue.WriteQueueItem {
         private final int mCode;
-        private final int mUserId;
         private final ActivityRecord[] mActivities;
 
         LoadActivitySnapshotItem(@NonNull ActivityRecord[] activities, int code, int userId,
                 @NonNull PersistInfoProvider persistInfoProvider) {
-            super(persistInfoProvider);
+            super(persistInfoProvider, userId);
             mActivities = activities;
             mCode = code;
-            mUserId = userId;
         }
 
         @Override
@@ -305,6 +295,11 @@
             return mCode == other.mCode && mUserId == other.mUserId
                     && mPersistInfoProvider == other.mPersistInfoProvider;
         }
+
+        @Override
+        public String toString() {
+            return "LoadActivitySnapshotItem{code=" + mCode + ", UserId=" + mUserId + "}";
+        }
     }
 
     void loadActivitySnapshot() {
@@ -714,24 +709,9 @@
             }
             removeTargets.add(usf);
         }
-        removeSnapshotFiles(removeTargets);
-    }
-
-    private void removeSnapshotFiles(@NonNull ArrayList<UserSavedFile> files) {
-        synchronized (mSnapshotPersistQueue.getLock()) {
-            mSnapshotPersistQueue.sendToQueueLocked(
-                    new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) {
-                        @Override
-                        void write() {
-                            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activity_remove_files");
-                            for (int i = files.size() - 1; i >= 0; --i) {
-                                final UserSavedFile usf = files.get(i);
-                                mSnapshotPersistQueue.deleteSnapshot(
-                                        usf.mFileId, usf.mUserId, mPersistInfoProvider);
-                            }
-                            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-                        }
-                    });
+        for (int i = removeTargets.size() - 1; i >= 0; --i) {
+            final UserSavedFile usf = removeTargets.get(i);
+            mPersister.removeSnapshot(usf.mFileId, usf.mUserId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index a4d15e0..13f6a5f 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -103,10 +103,6 @@
     static final boolean sPredictBackEnable =
             SystemProperties.getBoolean("persist.wm.debug.predictive_back", true);
 
-    static boolean isScreenshotEnabled() {
-        return SystemProperties.getInt("persist.wm.debug.predictive_back_screenshot", 0) != 0;
-    }
-
     // Notify focus window changed
     void onFocusChanged(WindowState newFocus) {
         mNavigationMonitor.onFocusWindowChanged(newFocus);
@@ -310,9 +306,11 @@
                     // keyguard locked and activities are unable to show when locked.
                     backType = BackNavigationInfo.TYPE_CALLBACK;
                 }
+            } else if (currentTask.mAtmService.getLockTaskController().isTaskLocked(currentTask)) {
+                // Do not predict if current task is in task locked.
+                backType = BackNavigationInfo.TYPE_CALLBACK;
             } else {
-                // TODO(208789724): Create single source of truth for this, maybe in
-                //  RootWindowContainer
+                // Check back-to-home or cross-task
                 prevTask = currentTask.mRootWindowContainer.getTask(t -> {
                     if (t.showToCurrentUser() && !t.mChildren.isEmpty()) {
                         final ActivityRecord ar = t.getTopNonFinishingActivity();
@@ -958,6 +956,18 @@
                 return;
             }
 
+            // Start fixed rotation for previous activity before create animation.
+            if (openingActivities.length == 1) {
+                final ActivityRecord next = openingActivities[0];
+                final DisplayContent dc = next.mDisplayContent;
+                dc.rotateInDifferentOrientationIfNeeded(next);
+                if (next.hasFixedRotationTransform()) {
+                    // Set the record so we can recognize it to continue to update display
+                    // orientation if the previous activity becomes the top later.
+                    dc.setFixedRotationLaunchingApp(next,
+                            next.getWindowConfiguration().getRotation());
+                }
+            }
             mOpenAnimAdaptor = new BackWindowAnimationAdaptorWrapper(true, mSwitchType, open);
             if (!mOpenAnimAdaptor.isValid()) {
                 Slog.w(TAG, "compose animations fail, skip");
@@ -1517,6 +1527,12 @@
                         setLaunchBehind(visibleOpenActivities[i]);
                     }
                 }
+                // Force update mLastSurfaceShowing for opening activity and its task.
+                if (mWindowManagerService.mRoot.mTransitionController.isShellTransitionsEnabled()) {
+                    for (int i = visibleOpenActivities.length - 1; i >= 0; --i) {
+                        WindowContainer.enforceSurfaceVisible(visibleOpenActivities[i]);
+                    }
+                }
             }
 
             @Nullable Runnable build() {
@@ -1623,16 +1639,6 @@
         }
         activity.mLaunchTaskBehind = true;
 
-        // Handle fixed rotation launching app.
-        final DisplayContent dc = activity.mDisplayContent;
-        dc.rotateInDifferentOrientationIfNeeded(activity);
-        if (activity.hasFixedRotationTransform()) {
-            // Set the record so we can recognize it to continue to update display
-            // orientation if the previous activity becomes the top later.
-            dc.setFixedRotationLaunchingApp(activity,
-                    activity.getWindowConfiguration().getRotation());
-        }
-
         ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
                 "Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity);
         activity.mTaskSupervisor.mStoppingActivities.remove(activity);
@@ -1700,21 +1706,38 @@
 
     static TaskSnapshot getSnapshot(@NonNull WindowContainer w,
             ActivityRecord[] visibleOpenActivities) {
+        TaskSnapshot snapshot = null;
         if (w.asTask() != null) {
             final Task task = w.asTask();
-            return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot(
+            snapshot = task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot(
                     task.mTaskId, task.mUserId, false /* restoreFromDisk */,
                     false /* isLowResolution */);
-        }
-
-        if (w.asActivityRecord() != null) {
+        } else if (w.asActivityRecord() != null) {
             final ActivityRecord ar = w.asActivityRecord();
-            return ar.mWmService.mSnapshotController.mActivitySnapshotController
+            snapshot = ar.mWmService.mSnapshotController.mActivitySnapshotController
                     .getSnapshot(visibleOpenActivities);
         }
-        return null;
+
+        return isSnapshotCompatible(snapshot, visibleOpenActivities) ? snapshot : null;
     }
 
+    static boolean isSnapshotCompatible(@NonNull TaskSnapshot snapshot,
+            @NonNull ActivityRecord[] visibleOpenActivities) {
+        if (snapshot == null) {
+            return false;
+        }
+        boolean oneComponentMatch = false;
+        for (int i = visibleOpenActivities.length - 1; i >= 0; --i) {
+            final ActivityRecord ar = visibleOpenActivities[i];
+            if (!ar.isSnapshotOrientationCompatible(snapshot)) {
+                return false;
+            }
+            oneComponentMatch |= ar.isSnapshotComponentCompatible(snapshot);
+        }
+        return oneComponentMatch;
+    }
+
+
     void setWindowManager(WindowManagerService wm) {
         mWindowManagerService = wm;
         mAnimationHandler = new AnimationHandler(wm);
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 9ac4a5c..688a3b5 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -717,71 +717,32 @@
         boolean callerCanAllow = resultForCaller.allows() && !state.callerExplicitOptOut();
         boolean realCallerCanAllow = resultForRealCaller.allows()
                 && !state.realCallerExplicitOptOut();
-        if (callerCanAllow && realCallerCanAllow) {
-            // Both caller and real caller allow with system defined behavior
-            if (state.mBalAllowedByPiCreatorWithHardening.allowsBackgroundActivityStarts()) {
-                // Will be allowed even with BAL hardening.
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed by caller. "
-                            + state.dump());
-                }
-                return allowBasedOnCaller(state);
-            }
-            if (state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts()) {
-                Slog.wtf(TAG,
-                        "With Android 15 BAL hardening this activity start may be blocked"
-                                + " if the PI creator upgrades target_sdk to 35+"
-                                + " AND the PI sender upgrades target_sdk to 34+! "
-                                + state.dump());
-                showBalRiskToast();
-                return allowBasedOnCaller(state);
-            }
-            Slog.wtf(TAG,
-                    "Without Android 15 BAL hardening this activity start would be allowed"
-                            + " (missing opt in by PI creator or sender)! "
-                            + state.dump());
-            return abortLaunch(state);
-        }
         if (callerCanAllow) {
             // Allowed before V by creator
-            if (state.mBalAllowedByPiCreatorWithHardening.allowsBackgroundActivityStarts()) {
-                // Will be allowed even with BAL hardening.
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed by caller. "
-                            + state.dump());
-                }
-                return allowBasedOnCaller(state);
-            }
             if (state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts()) {
-                Slog.wtf(TAG,
-                        "With Android 15 BAL hardening this activity start may be blocked"
+                Slog.wtf(TAG, "With Android 15 BAL hardening this activity start may be blocked"
                                 + " if the PI creator upgrades target_sdk to 35+! "
                                 + " (missing opt in by PI creator)! "
                                 + state.dump());
                 showBalRiskToast();
                 return allowBasedOnCaller(state);
             }
-            Slog.wtf(TAG,
-                    "Without Android 15 BAL hardening this activity start would be allowed"
-                            + " (missing opt in by PI creator)! "
-                            + state.dump());
-            return abortLaunch(state);
         }
         if (realCallerCanAllow) {
             // Allowed before U by sender
             if (state.mBalAllowedByPiSender.allowsBackgroundActivityStarts()) {
-                Slog.wtf(TAG,
-                        "With Android 14 BAL hardening this activity start will be blocked"
+                Slog.wtf(TAG, "With Android 14 BAL hardening this activity start will be blocked"
                                 + " if the PI sender upgrades target_sdk to 34+! "
                                 + " (missing opt in by PI sender)! "
                                 + state.dump());
                 showBalRiskToast();
                 return allowBasedOnRealCaller(state);
             }
-            Slog.wtf(TAG, "Without Android 14 BAL hardening this activity start would be allowed"
-                    + " (missing opt in by PI sender)! "
-                    + state.dump());
-            return abortLaunch(state);
+        }
+        // caller or real caller could start the activity, but would need to explicitly opt in
+        if (callerCanAllow || realCallerCanAllow) {
+            Slog.wtf(TAG, "Without BAL hardening this activity start would be allowed "
+                            + state.dump());
         }
         // neither the caller not the realCaller can allow or have explicitly opted out
         return abortLaunch(state);
@@ -1028,7 +989,7 @@
                         BalVerdict balAllowedForUid = proc.areBackgroundActivityStartsAllowed(
                                 state.mAppSwitchState);
                         if (balAllowedForUid.allows()) {
-                            return balAllowedForCaller.withProcessInfo("process", proc);
+                            return balAllowedForUid.withProcessInfo("process", proc);
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index 0f9e5b0..7052982 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -183,9 +183,6 @@
                         getCurrentDisplayChange(fromRotation, startBounds);
                 mDisplayContent.mTransitionController.requestStartTransition(transition,
                         /* startTask= */ null, /* remoteTransition= */ null, displayChange);
-                mDisplayContent.mTransitionController.setDisplaySyncMethod(displayChange,
-                        mDisplayContent);
-                transition.setAllReady();
             }
         });
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e7ecf52..82dbf8d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -160,6 +160,7 @@
 import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields;
 import static com.android.server.wm.utils.RegionUtils.forEachRectReverse;
 import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
+import static com.android.window.flags.Flags.deferDisplayUpdates;
 import static com.android.window.flags.Flags.explicitRefreshRateHints;
 
 import android.annotation.IntDef;
@@ -174,7 +175,6 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
 import android.graphics.ColorSpace;
 import android.graphics.Insets;
 import android.graphics.Matrix;
@@ -246,7 +246,6 @@
 import android.window.DisplayWindowPolicyController;
 import android.window.IDisplayAreaOrganizer;
 import android.window.ScreenCapture;
-import android.window.ScreenCapture.SynchronousScreenCaptureListener;
 import android.window.SystemPerformanceHinter;
 import android.window.TransitionRequestInfo;
 
@@ -276,7 +275,6 @@
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
-import static com.android.window.flags.Flags.deferDisplayUpdates;
 
 /**
  * Utility class for keeping track of the WindowStates and other pertinent contents of a
@@ -1636,12 +1634,19 @@
         if (configChanged) {
             mWaitingForConfig = true;
             if (mTransitionController.isShellTransitionsEnabled()) {
-                final TransitionRequestInfo.DisplayChange change =
-                        mTransitionController.isCollecting()
+                final Rect startBounds = currentDisplayConfig.windowConfiguration.getBounds();
+                final Rect endBounds = mTmpConfiguration.windowConfiguration.getBounds();
+                final Transition transition = mTransitionController.getCollectingTransition();
+                final TransitionRequestInfo.DisplayChange change = transition != null
                                 ? null : new TransitionRequestInfo.DisplayChange(mDisplayId);
                 if (change != null) {
-                    change.setStartAbsBounds(currentDisplayConfig.windowConfiguration.getBounds());
-                    change.setEndAbsBounds(mTmpConfiguration.windowConfiguration.getBounds());
+                    change.setStartAbsBounds(startBounds);
+                    change.setEndAbsBounds(endBounds);
+                } else {
+                    transition.setKnownConfigChanges(this, changes);
+                    // A collecting transition is existed. The sync method must be set before
+                    // collecting this display, so WindowState#prepareSync can use the sync method.
+                    mTransitionController.setDisplaySyncMethod(startBounds, endBounds, this);
                 }
                 requestChangeTransitionIfNeeded(changes, change);
             } else if (mLastHasContent) {
@@ -5207,10 +5212,9 @@
     }
 
     /**
-     * Takes a snapshot of the display.  In landscape mode this grabs the whole screen.
-     * In portrait mode, it grabs the full screenshot.
+     * Creates a LayerCaptureArgs object to represent the entire DisplayContent
      */
-    Bitmap screenshotDisplayLocked() {
+    ScreenCapture.LayerCaptureArgs getLayerCaptureArgs() {
         if (!mWmService.mPolicy.isScreenOn()) {
             if (DEBUG_SCREENSHOT) {
                 Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
@@ -5218,24 +5222,10 @@
             return null;
         }
 
-        SynchronousScreenCaptureListener syncScreenCapture =
-                ScreenCapture.createSyncCaptureListener();
-
         getBounds(mTmpRect);
         mTmpRect.offsetTo(0, 0);
-        ScreenCapture.LayerCaptureArgs args =
-                new ScreenCapture.LayerCaptureArgs.Builder(getSurfaceControl())
-                        .setSourceCrop(mTmpRect).build();
-
-        ScreenCapture.captureLayers(args, syncScreenCapture);
-
-        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
-                syncScreenCapture.getBuffer();
-        final Bitmap bitmap = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
-        if (bitmap == null) {
-            Slog.w(TAG_WM, "Failed to take screenshot");
-        }
-        return bitmap;
+        return new ScreenCapture.LayerCaptureArgs.Builder(getSurfaceControl())
+                .setSourceCrop(mTmpRect).build();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e2bc59b..a7bbc25 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1913,12 +1913,9 @@
              */
             final Rect mConfigFrame = new Rect();
 
-            /** The count of insets sources when calculating this info. */
-            int mLastInsetsSourceCount;
-
             private boolean mNeedUpdate = true;
 
-            void update(DisplayContent dc, int rotation, int w, int h) {
+            InsetsState update(DisplayContent dc, int rotation, int w, int h) {
                 final DisplayFrames df = new DisplayFrames();
                 dc.updateDisplayFrames(df, rotation, w, h);
                 dc.getDisplayPolicy().simulateLayoutDisplay(df);
@@ -1935,8 +1932,8 @@
                 mNonDecorFrame.inset(mNonDecorInsets);
                 mConfigFrame.set(displayFrame);
                 mConfigFrame.inset(mConfigInsets);
-                mLastInsetsSourceCount = dc.getDisplayPolicy().mInsetsSourceWindowsExceptIme.size();
                 mNeedUpdate = false;
+                return insetsState;
             }
 
             void set(Info other) {
@@ -1944,7 +1941,6 @@
                 mConfigInsets.set(other.mConfigInsets);
                 mNonDecorFrame.set(other.mNonDecorFrame);
                 mConfigFrame.set(other.mConfigFrame);
-                mLastInsetsSourceCount = other.mLastInsetsSourceCount;
                 mNeedUpdate = false;
             }
 
@@ -1997,6 +1993,29 @@
             }
         }
 
+        static boolean hasInsetsFrameDiff(InsetsState s1, InsetsState s2, int insetsTypes) {
+            int insetsCount1 = 0;
+            for (int i = s1.sourceSize() - 1; i >= 0; i--) {
+                final InsetsSource source1 = s1.sourceAt(i);
+                if ((source1.getType() & insetsTypes) == 0) {
+                    continue;
+                }
+                insetsCount1++;
+                final InsetsSource source2 = s2.peekSource(source1.getId());
+                if (source2 == null || !source2.getFrame().equals(source1.getFrame())) {
+                    return true;
+                }
+            }
+            int insetsCount2 = 0;
+            for (int i = s2.sourceSize() - 1; i >= 0; i--) {
+                final InsetsSource source2 = s2.sourceAt(i);
+                if ((source2.getType() & insetsTypes) != 0) {
+                    insetsCount2++;
+                }
+            }
+            return insetsCount1 != insetsCount2;
+        }
+
         private static class Cache {
             /**
              * If {@link #mPreserveId} is this value, it is in the middle of updating display
@@ -2031,12 +2050,14 @@
         final int dw = displayFrames.mWidth;
         final int dh = displayFrames.mHeight;
         final DecorInsets.Info newInfo = mDecorInsets.mTmpInfo;
-        newInfo.update(mDisplayContent, rotation, dw, dh);
+        final InsetsState newInsetsState = newInfo.update(mDisplayContent, rotation, dw, dh);
         final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh);
         if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)) {
             // Even if the config frame is not changed in current rotation, it may change the
-            // insets in other rotations if the source count is changed.
-            if (newInfo.mLastInsetsSourceCount != currentInfo.mLastInsetsSourceCount) {
+            // insets in other rotations if the frame of insets source is changed.
+            final InsetsState currentInsetsState = mDisplayContent.mDisplayFrames.mInsetsState;
+            if (DecorInsets.hasInsetsFrameDiff(
+                    newInsetsState, currentInsetsState, mService.mConfigTypes)) {
                 for (int i = mDecorInsets.mInfoForRotation.length - 1; i >= 0; i--) {
                     if (i != rotation) {
                         final boolean flipSize = (i + rotation) % 2 == 1;
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index f279689..0e2d3d1 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1424,7 +1424,7 @@
 
     @VisibleForTesting
     boolean shouldShowLetterboxUi(WindowState mainWindow) {
-        if (mIsRelaunchingAfterRequestedOrientationChanged || !isSurfaceReadyToShow(mainWindow)) {
+        if (mIsRelaunchingAfterRequestedOrientationChanged) {
             return mLastShouldShowLetterboxUi;
         }
 
@@ -1442,13 +1442,6 @@
     }
 
     @VisibleForTesting
-    boolean isSurfaceReadyToShow(WindowState mainWindow) {
-        return mainWindow.isDrawn() // Regular case
-                // Waiting for relayoutWindow to call preserveSurface
-                || mainWindow.isDragResizeChanged();
-    }
-
-    @VisibleForTesting
     boolean isSurfaceVisible(WindowState mainWindow) {
         return mainWindow.isOnScreen() && (mActivityRecord.isVisible()
                 || mActivityRecord.isVisibleRequested());
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 10405ec..e027eb6 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1135,16 +1135,17 @@
                     if (!mFreezeTaskListReordering) {
                         // Simple case: this is not an affiliated task, so we just move it to the
                         // front unless overridden by the provided activity options
+                        int indexToAdd = findIndexToAdd(task);
                         mTasks.remove(taskIndex);
-                        mTasks.add(0, task);
+                        mTasks.add(indexToAdd, task);
                         if (taskIndex != 0) {
                             // Only notify when position changes
                             mTaskNotificationController.notifyTaskListUpdated();
                         }
 
                         if (DEBUG_RECENTS) {
-                            Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
-                                    + " from " + taskIndex);
+                            Slog.d(TAG_RECENTS, "addRecent: moving " + task + " to index "
+                                    + indexToAdd + " from " + taskIndex);
                         }
                     }
                     notifyTaskPersisterLocked(task, false);
@@ -1231,6 +1232,37 @@
         notifyTaskPersisterLocked(task, false /* flush */);
     }
 
+    // Looks for a new index to move the recent Task. Note that the recent Task should not be
+    // placed higher than another recent Task that has higher hierarchical z-ordering.
+    private int findIndexToAdd(Task task) {
+        int indexToAdd = 0;
+        for (int i = 0; i < mTasks.size(); i++) {
+            final Task otherTask = mTasks.get(i);
+            if (task == otherTask) {
+                break;
+            }
+
+            if (!otherTask.isAttached()) {
+                // Stop searching if not attached.
+                break;
+            }
+
+            if (otherTask.inPinnedWindowingMode()) {
+                // Skip pip task without increasing index since pip is always on screen.
+                continue;
+            }
+
+            // Stop searching if the task has higher z-ordering, or increase the index and
+            // continue the search.
+            if (task.compareTo(otherTask) > 0) {
+                break;
+            }
+
+            indexToAdd = i + 1;
+        }
+        return indexToAdd;
+    }
+
     /**
      * Add the task to the bottom if possible.
      */
diff --git a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
index 5f488b7..bdb4588 100644
--- a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
+++ b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
@@ -97,7 +97,7 @@
             mRecordedWC = (WindowContainer) mWms.mRoot.getDefaultDisplay();
         } else {
             mRecordedWC = mWms.mRoot.getActivity(activity -> activity.mLaunchCookie
-                    == mediaProjectionInfo.getLaunchCookie()).getTask();
+                    == mediaProjectionInfo.getLaunchCookie().binder).getTask();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index f10a733..083872a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -669,7 +669,7 @@
     }
 
     @Override
-    public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
+    public void sendWallpaperCommand(IBinder window, String action, int x, int y,
             int z, Bundle extras, boolean sync) {
         synchronized (mService.mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
@@ -680,10 +680,9 @@
                 if (mCanAlwaysUpdateWallpaper
                         || windowState == wallpaperController.getWallpaperTarget()
                         || windowState == wallpaperController.getPrevWallpaperTarget()) {
-                    return wallpaperController.sendWindowWallpaperCommandUnchecked(
+                    wallpaperController.sendWindowWallpaperCommandUnchecked(
                             windowState, action, x, y, z, extras, sync);
                 }
-                return null;
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/wm/SnapshotController.java b/services/core/java/com/android/server/wm/SnapshotController.java
index 3014f97..cb388ef 100644
--- a/services/core/java/com/android/server/wm/SnapshotController.java
+++ b/services/core/java/com/android/server/wm/SnapshotController.java
@@ -211,5 +211,6 @@
     void dump(PrintWriter pw, String prefix) {
         mTaskSnapshotController.dump(pw, prefix);
         mActivitySnapshotController.dump(pw, prefix);
+        mSnapshotPersistQueue.dump(pw, prefix);
     }
 }
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index e4379b5..3578971 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -41,6 +41,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.ArrayDeque;
 
 /**
@@ -155,7 +156,9 @@
     void deleteSnapshot(int index, int userId, PersistInfoProvider provider) {
         final File protoFile = provider.getProtoFile(index, userId);
         final File bitmapLowResFile = provider.getLowResolutionBitmapFile(index, userId);
-        protoFile.delete();
+        if (protoFile.exists()) {
+            protoFile.delete();
+        }
         if (bitmapLowResFile.exists()) {
             bitmapLowResFile.delete();
         }
@@ -177,7 +180,7 @@
                     } else {
                         next = mWriteQueue.poll();
                         if (next != null) {
-                            if (next.isReady()) {
+                            if (next.isReady(mUserManagerInternal)) {
                                 isReadyToWrite = true;
                                 next.onDequeuedLocked();
                             } else {
@@ -210,14 +213,16 @@
 
     abstract static class WriteQueueItem {
         protected final PersistInfoProvider mPersistInfoProvider;
-        WriteQueueItem(@NonNull PersistInfoProvider persistInfoProvider) {
+        protected final int mUserId;
+        WriteQueueItem(@NonNull PersistInfoProvider persistInfoProvider, int userId) {
             mPersistInfoProvider = persistInfoProvider;
+            mUserId = userId;
         }
         /**
          * @return {@code true} if item is ready to have {@link WriteQueueItem#write} called
          */
-        boolean isReady() {
-            return true;
+        boolean isReady(UserManagerInternal userManager) {
+            return userManager.isUserUnlocked(mUserId);
         }
 
         abstract void write();
@@ -242,14 +247,12 @@
 
     class StoreWriteQueueItem extends WriteQueueItem {
         private final int mId;
-        private final int mUserId;
         private final TaskSnapshot mSnapshot;
 
         StoreWriteQueueItem(int id, int userId, TaskSnapshot snapshot,
                 PersistInfoProvider provider) {
-            super(provider);
+            super(provider, userId);
             mId = id;
-            mUserId = userId;
             mSnapshot = snapshot;
         }
 
@@ -268,11 +271,6 @@
         }
 
         @Override
-        boolean isReady() {
-            return mUserManagerInternal.isUserUnlocked(mUserId);
-        }
-
-        @Override
         void write() {
             if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "StoreWriteQueueItem#" + mId);
@@ -391,6 +389,11 @@
             return mId == other.mId && mUserId == other.mUserId
                     && mPersistInfoProvider == other.mPersistInfoProvider;
         }
+
+        @Override
+        public String toString() {
+            return "StoreWriteQueueItem{ID=" + mId + ", UserId=" + mUserId + "}";
+        }
     }
 
     DeleteWriteQueueItem createDeleteWriteQueueItem(int id, int userId,
@@ -400,12 +403,10 @@
 
     private class DeleteWriteQueueItem extends WriteQueueItem {
         private final int mId;
-        private final int mUserId;
 
         DeleteWriteQueueItem(int id, int userId, PersistInfoProvider provider) {
-            super(provider);
+            super(provider, userId);
             mId = id;
-            mUserId = userId;
         }
 
         @Override
@@ -414,5 +415,24 @@
             deleteSnapshot(mId, mUserId, mPersistInfoProvider);
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
+
+        @Override
+        public String toString() {
+            return "DeleteWriteQueueItem{ID=" + mId + ", UserId=" + mUserId + "}";
+        }
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        final WriteQueueItem[] items;
+        synchronized (mLock) {
+            items = mWriteQueue.toArray(new WriteQueueItem[0]);
+        }
+        if (items.length == 0) {
+            return;
+        }
+        pw.println(prefix + "PersistQueue contains:");
+        for (int i = items.length - 1; i >= 0; --i) {
+            pw.println(prefix + "  " + items[i] + "");
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 0c6b174..838ce86 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE;
 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
@@ -45,7 +46,6 @@
 import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
 import static com.android.server.wm.ActivityRecord.State.PAUSED;
 import static com.android.server.wm.ActivityRecord.State.PAUSING;
@@ -89,7 +89,6 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.util.DisplayMetrics;
@@ -99,7 +98,6 @@
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.window.ITaskFragmentOrganizer;
-import android.window.ScreenCapture;
 import android.window.TaskFragmentAnimationParams;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOrganizerToken;
@@ -113,7 +111,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -403,10 +400,6 @@
     /** For calculating app bounds, i.e. the area without the nav bar and display cutout. */
     private final Rect mTmpNonDecorBounds = new Rect();
 
-    //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
-    // implemented
-    HashMap<String, ScreenCapture.ScreenshotHardwareBuffer> mBackScreenshots = new HashMap<>();
-
     private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
             new EnsureActivitiesVisibleHelper(this);
 
@@ -733,6 +726,9 @@
             // TaskFragment to have bounds outside of the parent bounds.
             return false;
         }
+        if (hasEmbedAnyAppInUntrustedModePermission(mTaskFragmentOrganizerUid)) {
+            return true;
+        }
         return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
                 == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
     }
@@ -804,6 +800,15 @@
     }
 
     /**
+     * Checks if a particular app uid has the {@link EMBED_ANY_APP_IN_UNTRUSTED_MODE} permission.
+     */
+    private static boolean hasEmbedAnyAppInUntrustedModePermission(int uid) {
+        return Flags.untrustedEmbeddingAnyAppPermission()
+                && checkPermission(EMBED_ANY_APP_IN_UNTRUSTED_MODE,
+                PermissionChecker.PID_UNKNOWN, uid) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
      * Checks if all activities in the task fragment are embedded as fully trusted.
      * @see #isFullyTrustedEmbedding(ActivityRecord, int)
      * @param uid   uid of the TaskFragment organizer.
@@ -1910,11 +1915,7 @@
                 ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
                                 + "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,
                         prev.isVisibleRequested());
-                if (prev.deferRelaunchUntilPaused) {
-                    // Complete the deferred relaunch that was waiting for pause to complete.
-                    ProtoLog.v(WM_DEBUG_STATES, "Re-launching after pause: %s", prev);
-                    prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
-                } else if (wasStopping) {
+                if (wasStopping) {
                     // We are also stopping, the stop request must have gone soon after the pause.
                     // We can't clobber it, because the stop confirmation will not be handled.
                     // We don't need to schedule another stop, we only need to let it happen.
@@ -2092,17 +2093,6 @@
         super.addChild(child, index);
 
         if (isAddingActivity && task != null) {
-            // TODO(b/207481538): temporary per-activity screenshoting
-            if (r != null && BackNavigationController.isScreenshotEnabled()) {
-                ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
-                        r.mActivityComponent.flattenToString());
-                Rect outBounds = r.getBounds();
-                ScreenCapture.ScreenshotHardwareBuffer backBuffer = ScreenCapture.captureLayers(
-                        r.mSurfaceControl,
-                        new Rect(0, 0, outBounds.width(), outBounds.height()),
-                        1f);
-                mBackScreenshots.put(r.mActivityComponent.flattenToString(), backBuffer);
-            }
             addingActivity.inHistory = true;
             task.onDescendantActivityAdded(taskHadActivity, activityType, addingActivity);
         }
@@ -2905,19 +2895,6 @@
         return !mCreatedByOrganizer || mIsRemovalRequested;
     }
 
-    @Nullable
-    HardwareBuffer getSnapshotForActivityRecord(@Nullable ActivityRecord r) {
-        if (!BackNavigationController.isScreenshotEnabled()) {
-            return null;
-        }
-        if (r != null && r.mActivityComponent != null) {
-            ScreenCapture.ScreenshotHardwareBuffer backBuffer =
-                    mBackScreenshots.get(r.mActivityComponent.flattenToString());
-            return backBuffer != null ? backBuffer.getHardwareBuffer() : null;
-        }
-        return null;
-    }
-
     @Override
     void removeChild(WindowContainer child) {
         removeChild(child, true /* removeSelfIfPossible */);
@@ -2926,13 +2903,6 @@
     void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
         super.removeChild(child);
         final ActivityRecord r = child.asActivityRecord();
-        if (BackNavigationController.isScreenshotEnabled()) {
-            //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
-            // implemented
-            if (r != null) {
-                mBackScreenshots.remove(r.mActivityComponent.flattenToString());
-            }
-        }
         final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(r);
         if (hostProcess != null) {
             hostProcess.removeEmbeddedActivity(r);
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 4e7a9bd..f4e9957 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -303,8 +303,15 @@
         } else {
             if (DEBUG) appendLog("non-freeform-task-display-area");
         }
+        final boolean isUpdatingExistingTaskWindowingMode = task != null
+                && task.getRequestedOverrideWindowingMode() != WINDOWING_MODE_UNDEFINED
+                && launchMode != task.getRequestedOverrideWindowingMode();
+        if (DEBUG && isUpdatingExistingTaskWindowingMode) {
+            appendLog("updating-existing-task-windowing-mode");
+        }
         // If launch mode matches display windowing mode, let it inherit from display.
         outParams.mWindowingMode = launchMode == suggestedDisplayArea.getWindowingMode()
+                && !isUpdatingExistingTaskWindowingMode
                 ? WINDOWING_MODE_UNDEFINED : launchMode;
 
         if (phase == PHASE_WINDOWING_MODE) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 233daad..87be74a 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -19,11 +19,13 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 
 import android.os.Trace;
+import android.os.UserHandle;
 import android.util.ArraySet;
 import android.window.TaskSnapshot;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.UserManagerInternal;
 
 import java.io.File;
 import java.util.Arrays;
@@ -84,6 +86,9 @@
      *                       model.
      */
     void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) {
+        if (runningUserIds.length == 0) {
+            return;
+        }
         synchronized (mLock) {
             mPersistedTaskIdsSinceLastRemoveObsolete.clear();
             mSnapshotPersistQueue.sendToQueueLocked(new RemoveObsoleteFilesQueueItem(
@@ -99,12 +104,22 @@
         @VisibleForTesting
         RemoveObsoleteFilesQueueItem(ArraySet<Integer> persistentTaskIds,
                 int[] runningUserIds, PersistInfoProvider provider) {
-            super(provider);
+            super(provider, runningUserIds.length > 0 ? runningUserIds[0] : UserHandle.USER_SYSTEM);
             mPersistentTaskIds = new ArraySet<>(persistentTaskIds);
             mRunningUserIds = Arrays.copyOf(runningUserIds, runningUserIds.length);
         }
 
         @Override
+        boolean isReady(UserManagerInternal userManagerInternal) {
+            for (int i = mRunningUserIds.length - 1; i >= 0; --i) {
+                if (!userManagerInternal.isUserUnlocked(mRunningUserIds[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
         void write() {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RemoveObsoleteFilesQueueItem");
             final ArraySet<Integer> newPersistedTaskIds;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 59e3350..7077553 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -496,6 +496,9 @@
         if (mCollectingTransition != null && mCollectingTransition.isInTransientHide(task)) {
             return true;
         }
+        for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
+            if (mWaitingTransitions.get(i).isInTransientHide(task)) return true;
+        }
         for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
             if (mPlayingTransitions.get(i).isInTransientHide(task)) return true;
         }
@@ -506,6 +509,9 @@
         if (mCollectingTransition != null && mCollectingTransition.isTransientVisible(task)) {
             return true;
         }
+        for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
+            if (mWaitingTransitions.get(i).isTransientVisible(task)) return true;
+        }
         for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
             if (mPlayingTransitions.get(i).isTransientVisible(task)) return true;
         }
@@ -634,11 +640,16 @@
     }
 
     /** Sets the sync method for the display change. */
-    void setDisplaySyncMethod(@NonNull TransitionRequestInfo.DisplayChange displayChange,
+    private void setDisplaySyncMethod(@NonNull TransitionRequestInfo.DisplayChange displayChange,
             @NonNull DisplayContent displayContent) {
         final Rect startBounds = displayChange.getStartAbsBounds();
         final Rect endBounds = displayChange.getEndAbsBounds();
         if (startBounds == null || endBounds == null) return;
+        setDisplaySyncMethod(startBounds, endBounds, displayContent);
+    }
+
+    void setDisplaySyncMethod(@NonNull Rect startBounds, @NonNull Rect endBounds,
+            @NonNull DisplayContent displayContent) {
         final int startWidth = startBounds.width();
         final int startHeight = startBounds.height();
         final int endWidth = endBounds.width();
@@ -983,39 +994,18 @@
         Slog.e(TAG, "Set visible without transition " + wc + " playing=" + isPlaying
                 + " caller=" + caller);
         if (!isPlaying) {
-            enforceSurfaceVisible(wc);
+            WindowContainer.enforceSurfaceVisible(wc);
             return;
         }
         // Update surface visibility after the playing transitions are finished, so the last
         // visibility won't be replaced by the finish transaction of transition.
         mStateValidators.add(() -> {
             if (wc.isVisibleRequested()) {
-                enforceSurfaceVisible(wc);
+                WindowContainer.enforceSurfaceVisible(wc);
             }
         });
     }
 
-    private void enforceSurfaceVisible(WindowContainer<?> wc) {
-        if (wc.mSurfaceControl == null) return;
-        wc.getSyncTransaction().show(wc.mSurfaceControl);
-        final ActivityRecord ar = wc.asActivityRecord();
-        if (ar != null) {
-            ar.mLastSurfaceShowing = true;
-        }
-        // Force showing the parents because they may be hidden by previous transition.
-        for (WindowContainer<?> p = wc.getParent(); p != null && p != wc.mDisplayContent;
-                p = p.getParent()) {
-            if (p.mSurfaceControl != null) {
-                p.getSyncTransaction().show(p.mSurfaceControl);
-                final Task task = p.asTask();
-                if (task != null) {
-                    task.mLastSurfaceShowing = true;
-                }
-            }
-        }
-        wc.scheduleAnimation();
-    }
-
     /**
      * Called when the transition has a complete set of participants for its operation. In other
      * words, it is when the transition is "ready" but is still waiting for participants to draw.
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 0fc62a7..6949a87 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -279,13 +279,14 @@
             return null;
         }
         Point largestDisplaySize = new Point();
+        float largestWidth = 0;
         List<DisplayInfo> possibleDisplayInfo =
                 mService.getPossibleDisplayInfoLocked(DEFAULT_DISPLAY);
         for (int i = 0; i < possibleDisplayInfo.size(); i++) {
             DisplayInfo displayInfo = possibleDisplayInfo.get(i);
-            if (displayInfo.type == Display.TYPE_INTERNAL
-                    && Math.max(displayInfo.logicalWidth, displayInfo.logicalHeight)
-                    > Math.max(largestDisplaySize.x, largestDisplaySize.y)) {
+            float width = (float) displayInfo.logicalWidth / displayInfo.physicalXDpi;
+            if (displayInfo.type == Display.TYPE_INTERNAL && width > largestWidth) {
+                largestWidth = width;
                 largestDisplaySize.set(displayInfo.logicalWidth,
                         displayInfo.logicalHeight);
             }
@@ -641,11 +642,10 @@
         }
     }
 
-    Bundle sendWindowWallpaperCommandUnchecked(
+    void sendWindowWallpaperCommandUnchecked(
             WindowState window, String action, int x, int y, int z,
             Bundle extras, boolean sync) {
         sendWindowWallpaperCommand(action, x, y, z, extras, sync);
-        return null;
     }
 
     private void sendWindowWallpaperCommand(
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 750fd50..b43a454 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -146,10 +146,11 @@
             for (int i = 0; i < numDisplays; i++) {
                 final DisplayContent dc = root.getChildAt(i);
 
-                dc.checkAppWindowsReadyToShow();
+                if (!useShellTransition) {
+                    dc.checkAppWindowsReadyToShow();
+                }
                 if (accessibilityController.hasCallbacks()) {
-                    accessibilityController.drawMagnifiedRegionBorderIfNeeded(dc.mDisplayId,
-                            mTransaction);
+                    accessibilityController.drawMagnifiedRegionBorderIfNeeded(dc.mDisplayId);
                 }
 
                 if (dc.isAnimating(animationFlags, ANIMATION_TYPE_ALL)) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 286182e..2d2857a 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3625,6 +3625,29 @@
         return mSurfaceControl.getHeight();
     }
 
+    static void enforceSurfaceVisible(@NonNull WindowContainer<?> wc) {
+        if (wc.mSurfaceControl == null) {
+            return;
+        }
+        wc.getSyncTransaction().show(wc.mSurfaceControl);
+        final ActivityRecord ar = wc.asActivityRecord();
+        if (ar != null) {
+            ar.mLastSurfaceShowing = true;
+        }
+        // Force showing the parents because they may be hidden by previous transition.
+        for (WindowContainer<?> p = wc.getParent(); p != null && p != wc.mDisplayContent;
+                p = p.getParent()) {
+            if (p.mSurfaceControl != null) {
+                p.getSyncTransaction().show(p.mSurfaceControl);
+                final Task task = p.asTask();
+                if (task != null) {
+                    task.mLastSurfaceShowing = true;
+                }
+            }
+        }
+        wc.scheduleAnimation();
+    }
+
     @CallSuper
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         if (mSurfaceAnimator.isAnimating()) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9650b8bc..426694d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4087,7 +4087,7 @@
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
 
-        final Bitmap bm;
+        ScreenCapture.LayerCaptureArgs captureArgs;
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(DEFAULT_DISPLAY);
             if (displayContent == null) {
@@ -4095,12 +4095,30 @@
                     Slog.i(TAG_WM, "Screenshot returning null. No Display for displayId="
                             + DEFAULT_DISPLAY);
                 }
-                bm = null;
+                captureArgs = null;
             } else {
-                bm = displayContent.screenshotDisplayLocked();
+                captureArgs = displayContent.getLayerCaptureArgs();
             }
         }
 
+        final Bitmap bm;
+        if (captureArgs != null) {
+            ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture =
+                    ScreenCapture.createSyncCaptureListener();
+
+            ScreenCapture.captureLayers(captureArgs, syncScreenCapture);
+
+            final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                    syncScreenCapture.getBuffer();
+            bm = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
+        } else {
+            bm = null;
+        }
+
+        if (bm == null) {
+            Slog.w(TAG_WM, "Failed to take screenshot");
+        }
+
         FgThread.getHandler().post(() -> {
             try {
                 receiver.onHandleAssistScreenshot(bm);
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4ba52e4..3f889c0 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1471,7 +1471,12 @@
                         final int index = task.mChildren.indexOf(topTaskFragment);
                         task.mChildren.remove(taskFragment);
                         task.mChildren.add(index, taskFragment);
-                        effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                        if (taskFragment.hasChild()) {
+                            effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                        } else {
+                            // Ensure that the child layers are updated if the TaskFragment is empty
+                            task.assignChildLayers();
+                        }
                     }
                 }
                 break;
@@ -1486,7 +1491,12 @@
                 if (task != null) {
                     task.mChildren.remove(taskFragment);
                     task.mChildren.add(0, taskFragment);
-                    effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                    if (taskFragment.hasChild()) {
+                        effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                    } else {
+                        // Ensure that the child layers are updated if the TaskFragment is empty.
+                        task.assignChildLayers();
+                    }
                 }
                 break;
             }
@@ -1495,7 +1505,12 @@
                 if (task != null) {
                     task.mChildren.remove(taskFragment);
                     task.mChildren.add(taskFragment);
-                    effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                    if (taskFragment.hasChild()) {
+                        effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                    } else {
+                        // Ensure that the child layers are updated if the TaskFragment is empty.
+                        task.assignChildLayers();
+                    }
                 }
                 break;
             }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7ad87ed..24e50c5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -169,6 +169,7 @@
 import static com.android.server.wm.WindowStateProto.REMOVED;
 import static com.android.server.wm.WindowStateProto.REMOVE_ON_EXIT;
 import static com.android.server.wm.WindowStateProto.REQUESTED_HEIGHT;
+import static com.android.server.wm.WindowStateProto.REQUESTED_VISIBLE_TYPES;
 import static com.android.server.wm.WindowStateProto.REQUESTED_WIDTH;
 import static com.android.server.wm.WindowStateProto.STACK_ID;
 import static com.android.server.wm.WindowStateProto.SURFACE_INSETS;
@@ -3988,6 +3989,7 @@
         proto.write(FORCE_SEAMLESS_ROTATION, mForceSeamlesslyRotate);
         proto.write(HAS_COMPAT_SCALE, hasCompatScale());
         proto.write(GLOBAL_SCALE, mGlobalScale);
+        proto.write(REQUESTED_VISIBLE_TYPES, mRequestedVisibleTypes);
         for (Rect r : mKeepClearAreas) {
             r.dumpDebug(proto, KEEP_CLEAR_AREAS);
         }
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 7b08413..4403bce 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -571,8 +571,8 @@
 }
 
 static jboolean com_android_server_am_CachedAppOptimizer_isFreezerProfileValid(JNIEnv* env) {
-    int uid = getuid();
-    int pid = getpid();
+    uid_t uid = getuid();
+    pid_t pid = getpid();
 
     return isProfileValidForProcess("Frozen", uid, pid) &&
             isProfileValidForProcess("Unfrozen", uid, pid);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8bc41af..cbc301b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -306,7 +306,7 @@
     void setMotionClassifierEnabled(bool enabled);
     std::optional<std::string> getBluetoothAddress(int32_t deviceId);
     void setStylusButtonMotionEventsEnabled(bool enabled);
-    FloatPoint getMouseCursorPosition();
+    FloatPoint getMouseCursorPosition(int32_t displayId);
     void setStylusPointerIconEnabled(bool enabled);
 
     /* --- InputReaderPolicyInterface implementation --- */
@@ -1784,10 +1784,12 @@
             InputReaderConfiguration::Change::STYLUS_BUTTON_REPORTING);
 }
 
-FloatPoint NativeInputManager::getMouseCursorPosition() {
+FloatPoint NativeInputManager::getMouseCursorPosition(int32_t displayId) {
     if (ENABLE_POINTER_CHOREOGRAPHER) {
-        return mInputManager->getChoreographer().getMouseCursorPosition(ADISPLAY_ID_NONE);
+        return mInputManager->getChoreographer().getMouseCursorPosition(displayId);
     }
+    // To maintain the status-quo, the displayId parameter (used when PointerChoreographer is
+    // enabled) is ignored in the old pipeline.
     std::scoped_lock _l(mLock);
     const auto pc = mLocked.legacyPointerController.lock();
     if (!pc) return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
@@ -2751,9 +2753,10 @@
     im->setStylusButtonMotionEventsEnabled(enabled);
 }
 
-static jfloatArray nativeGetMouseCursorPosition(JNIEnv* env, jobject nativeImplObj) {
+static jfloatArray nativeGetMouseCursorPosition(JNIEnv* env, jobject nativeImplObj,
+                                                jint displayId) {
     NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
-    const auto p = im->getMouseCursorPosition();
+    const auto p = im->getMouseCursorPosition(displayId);
     const std::array<float, 2> arr = {{p.x, p.y}};
     jfloatArray outArr = env->NewFloatArray(2);
     env->SetFloatArrayRegion(outArr, 0, arr.size(), arr.data());
@@ -2775,6 +2778,15 @@
     }
 }
 
+static void nativeSetAccessibilitySlowKeysThreshold(JNIEnv* env, jobject nativeImplObj,
+                                                    jint thresholdTimeMs) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+    if (ENABLE_INPUT_FILTER_RUST) {
+        im->getInputManager()->getInputFilter().setAccessibilitySlowKeysThreshold(
+                static_cast<nsecs_t>(thresholdTimeMs) * 1000000);
+    }
+}
+
 static void nativeSetAccessibilityStickyKeysEnabled(JNIEnv* env, jobject nativeImplObj,
                                                     jboolean enabled) {
     NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
@@ -2883,10 +2895,12 @@
         {"getBluetoothAddress", "(I)Ljava/lang/String;", (void*)nativeGetBluetoothAddress},
         {"setStylusButtonMotionEventsEnabled", "(Z)V",
          (void*)nativeSetStylusButtonMotionEventsEnabled},
-        {"getMouseCursorPosition", "()[F", (void*)nativeGetMouseCursorPosition},
+        {"getMouseCursorPosition", "(I)[F", (void*)nativeGetMouseCursorPosition},
         {"setStylusPointerIconEnabled", "(Z)V", (void*)nativeSetStylusPointerIconEnabled},
         {"setAccessibilityBounceKeysThreshold", "(I)V",
          (void*)nativeSetAccessibilityBounceKeysThreshold},
+        {"setAccessibilitySlowKeysThreshold", "(I)V",
+         (void*)nativeSetAccessibilitySlowKeysThreshold},
         {"setAccessibilityStickyKeysEnabled", "(Z)V",
          (void*)nativeSetAccessibilityStickyKeysEnabled},
 };
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index db985fd..b1349ea 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -23,8 +23,8 @@
 import android.credentials.ClearCredentialStateRequest;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.IClearCredentialStateCallback;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
 import android.os.CancellationSignal;
 import android.os.RemoteException;
 import android.service.credentials.CallingAppInfo;
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index b24accb..3dcf42d 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -27,8 +27,8 @@
 import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.ICreateCredentialCallback;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
 import android.os.CancellationSignal;
 import android.os.RemoteException;
 import android.service.credentials.CallingAppInfo;
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 667e086..281fb1c 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -27,6 +27,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -201,7 +202,7 @@
     @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
     // this.mLock
     protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) {
-        updateProvidersWhenPackageRemoved(mContext, packageName);
+        updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName);
 
         List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId);
         if (services == null) {
@@ -1134,13 +1135,14 @@
     }
 
     /** Updates the list of providers when an app is uninstalled. */
-    public static void updateProvidersWhenPackageRemoved(Context context, String packageName) {
+    public static void updateProvidersWhenPackageRemoved(
+            SettingsWrapper settingsWrapper, String packageName) {
+        Slog.i(TAG, "updateProvidersWhenPackageRemoved");
+
         // Get the current providers.
         String rawProviders =
-                Settings.Secure.getStringForUser(
-                    context.getContentResolver(),
-                    Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
-                    UserHandle.myUserId());
+                settingsWrapper.getStringForUser(
+                        Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, UserHandle.myUserId());
         if (rawProviders == null) {
             Slog.w(TAG, "settings key is null");
             return;
@@ -1148,44 +1150,44 @@
 
         // Remove any providers from the primary setting that contain the package name
         // being removed.
-        Set<String> primaryProviders =
-                getStoredProviders(rawProviders, packageName);
-        if (!Settings.Secure.putString(
-                context.getContentResolver(),
+        Set<String> primaryProviders = getStoredProviders(rawProviders, packageName);
+        if (!settingsWrapper.putStringForUser(
                 Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
-                String.join(":", primaryProviders))) {
-            Slog.w(TAG, "Failed to remove primary package: " + packageName);
+                String.join(":", primaryProviders),
+                UserHandle.myUserId(),
+                /* overrideableByRestore= */ true)) {
+            Slog.e(TAG, "Failed to remove primary package: " + packageName);
             return;
         }
 
         // Read the autofill provider so we don't accidentally erase it.
         String autofillProvider =
-                Settings.Secure.getStringForUser(
-                    context.getContentResolver(),
-                    Settings.Secure.AUTOFILL_SERVICE,
-                    UserHandle.myUserId());
+                settingsWrapper.getStringForUser(
+                        Settings.Secure.AUTOFILL_SERVICE, UserHandle.myUserId());
 
         // If there is an autofill provider and it is the placeholder indicating
         // that the currently selected primary provider does not support autofill
         // then we should wipe the setting to keep it in sync.
         if (autofillProvider != null && primaryProviders.isEmpty()) {
             if (autofillProvider.equals(AUTOFILL_PLACEHOLDER_VALUE)) {
-                if (!Settings.Secure.putString(
-                        context.getContentResolver(),
+                if (!settingsWrapper.putStringForUser(
                         Settings.Secure.AUTOFILL_SERVICE,
-                        "")) {
-                    Slog.w(TAG, "Failed to remove autofill package: " + packageName);
+                        "",
+                        UserHandle.myUserId(),
+                        /* overrideableByRestore= */ true)) {
+                    Slog.e(TAG, "Failed to remove autofill package: " + packageName);
                 }
             } else {
                 // If the existing autofill provider is from the app being removed
                 // then erase the autofill service setting.
                 ComponentName cn = ComponentName.unflattenFromString(autofillProvider);
                 if (cn != null && cn.getPackageName().equals(packageName)) {
-                   if (!Settings.Secure.putString(
-                            context.getContentResolver(),
+                    if (!settingsWrapper.putStringForUser(
                             Settings.Secure.AUTOFILL_SERVICE,
-                            "")) {
-                        Slog.w(TAG, "Failed to remove autofill package: " + packageName);
+                            "",
+                            UserHandle.myUserId(),
+                            /* overrideableByRestore= */ true)) {
+                        Slog.e(TAG, "Failed to remove autofill package: " + packageName);
                     }
                 }
             }
@@ -1193,19 +1195,17 @@
 
         // Read the credential providers to remove any reference of the removed app.
         String rawCredentialProviders =
-                Settings.Secure.getStringForUser(
-                    context.getContentResolver(),
-                    Settings.Secure.CREDENTIAL_SERVICE,
-                    UserHandle.myUserId());
+                settingsWrapper.getStringForUser(
+                        Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId());
 
         // Remove any providers that belong to the removed app.
-        Set<String> credentialProviders =
-                getStoredProviders(rawCredentialProviders, packageName);
-        if (!Settings.Secure.putString(
-                context.getContentResolver(),
+        Set<String> credentialProviders = getStoredProviders(rawCredentialProviders, packageName);
+        if (!settingsWrapper.putStringForUser(
                 Settings.Secure.CREDENTIAL_SERVICE,
-                String.join(":", credentialProviders))) {
-            Slog.w(TAG, "Failed to remove secondary package: " + packageName);
+                String.join(":", credentialProviders),
+                UserHandle.myUserId(),
+                /* overrideableByRestore= */ true)) {
+            Slog.e(TAG, "Failed to remove secondary package: " + packageName);
         }
     }
 
@@ -1232,4 +1232,38 @@
 
         return providers;
     }
+
+    /** A wrapper class that can be used by tests for intercepting reads/writes. */
+    public static class SettingsWrapper {
+        private final Context mContext;
+
+        public SettingsWrapper(@NonNull Context context) {
+            this.mContext = context;
+        }
+
+        ContentResolver getContentResolver() {
+            return mContext.getContentResolver();
+        }
+
+        /** Retrieves the string value of a system setting */
+        public String getStringForUser(String name, int userHandle) {
+            return Settings.Secure.getStringForUser(getContentResolver(), name, userHandle);
+        }
+
+        /** Updates the string value of a system setting */
+        public boolean putStringForUser(
+                String name,
+                String value,
+                int userHandle,
+                boolean overrideableByRestore) {
+            return Settings.Secure.putStringForUser(
+                    getContentResolver(),
+                    name,
+                    value,
+                    null,
+                    false,
+                    userHandle,
+                    overrideableByRestore);
+        }
+    }
 }
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index f092dcc..4203576 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -22,11 +22,11 @@
 import android.content.Intent;
 import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
-import android.credentials.ui.DisabledProviderData;
-import android.credentials.ui.IntentFactory;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
-import android.credentials.ui.UserSelectionDialogResult;
+import android.credentials.selection.DisabledProviderData;
+import android.credentials.selection.IntentFactory;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
+import android.credentials.selection.UserSelectionDialogResult;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index 25281ba..7e709fe 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -26,9 +26,9 @@
 import android.credentials.GetCredentialRequest;
 import android.credentials.GetCredentialResponse;
 import android.credentials.IGetCandidateCredentialsCallback;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
 import android.os.CancellationSignal;
 import android.os.IBinder;
 import android.os.RemoteException;
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 49ea19a..b33f531 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -26,8 +26,8 @@
 import android.credentials.GetCredentialRequest;
 import android.credentials.GetCredentialResponse;
 import android.credentials.IGetCredentialCallback;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
 import android.os.Binder;
 import android.os.CancellationSignal;
 import android.os.RemoteException;
diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
index efb394d..21ac9e4 100644
--- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
+++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
@@ -22,7 +22,7 @@
 import android.credentials.CreateCredentialResponse;
 import android.credentials.GetCredentialException;
 import android.credentials.GetCredentialResponse;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.ProviderPendingIntentResponse;
 import android.service.credentials.BeginGetCredentialResponse;
 import android.service.credentials.CredentialProviderService;
 
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index fbfc9ca..30af567 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -26,9 +26,9 @@
 import android.credentials.IGetCredentialCallback;
 import android.credentials.IPrepareGetCredentialCallback;
 import android.credentials.PrepareGetCredentialResponseInternal;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
 import android.os.CancellationSignal;
 import android.os.RemoteException;
 import android.service.credentials.CallingAppInfo;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index d4b8800..6a1b1db7 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -21,8 +21,8 @@
 import android.content.Context;
 import android.credentials.ClearCredentialStateException;
 import android.credentials.CredentialProviderInfo;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
 import android.os.ICancellationSignal;
 import android.service.credentials.CallingAppInfo;
 import android.service.credentials.ClearCredentialStateRequest;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 6f79852..6361aeb 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -25,9 +25,9 @@
 import android.credentials.CreateCredentialException;
 import android.credentials.CreateCredentialResponse;
 import android.credentials.CredentialProviderInfo;
-import android.credentials.ui.CreateCredentialProviderData;
-import android.credentials.ui.Entry;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.CreateCredentialProviderData;
+import android.credentials.selection.Entry;
+import android.credentials.selection.ProviderPendingIntentResponse;
 import android.os.Bundle;
 import android.os.ICancellationSignal;
 import android.service.credentials.BeginCreateCredentialRequest;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 7bd1cc4..fcaef9f 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -26,10 +26,10 @@
 import android.credentials.CredentialProviderInfo;
 import android.credentials.GetCredentialException;
 import android.credentials.GetCredentialResponse;
-import android.credentials.ui.AuthenticationEntry;
-import android.credentials.ui.Entry;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.AuthenticationEntry;
+import android.credentials.selection.Entry;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
 import android.os.ICancellationSignal;
 import android.service.autofill.Flags;
 import android.service.credentials.Action;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index bafa4a5..f162916 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -25,10 +25,10 @@
 import android.credentials.CredentialOption;
 import android.credentials.GetCredentialException;
 import android.credentials.GetCredentialResponse;
-import android.credentials.ui.Entry;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.Entry;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
 import android.os.ICancellationSignal;
 import android.service.credentials.CallingAppInfo;
 import android.service.credentials.CredentialEntry;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index f2055d0..c16e232 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -25,8 +25,8 @@
 import android.content.pm.PackageManager;
 import android.credentials.Credential;
 import android.credentials.CredentialProviderInfo;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
 import android.os.ICancellationSignal;
 import android.os.RemoteException;
 import android.util.Slog;
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 67c52e6..bf7df86 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -24,8 +24,8 @@
 import android.content.Intent;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.flags.Flags;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.UserSelectionDialogResult;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.UserSelectionDialogResult;
 import android.os.Binder;
 import android.os.CancellationSignal;
 import android.os.Handler;
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
index d828349..23db11f 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
@@ -16,10 +16,10 @@
 
 package com.android.server.credentials.metrics;
 
-import static android.credentials.ui.RequestInfo.TYPE_CREATE;
-import static android.credentials.ui.RequestInfo.TYPE_GET;
-import static android.credentials.ui.RequestInfo.TYPE_GET_VIA_REGISTRY;
-import static android.credentials.ui.RequestInfo.TYPE_UNDEFINED;
+import static android.credentials.selection.RequestInfo.TYPE_CREATE;
+import static android.credentials.selection.RequestInfo.TYPE_GET;
+import static android.credentials.selection.RequestInfo.TYPE_GET_VIA_REGISTRY;
+import static android.credentials.selection.RequestInfo.TYPE_UNDEFINED;
 
 import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
 import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CREATE_CREDENTIAL;
@@ -32,7 +32,7 @@
 import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNKNOWN;
 import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNREGISTER_CREDENTIAL_DESCRIPTION;
 
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.RequestInfo;
 import android.util.Slog;
 
 import java.util.AbstractMap;
diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
index 83b57c4..8adcfbc 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
@@ -33,7 +33,7 @@
 import android.content.ComponentName;
 import android.credentials.CreateCredentialRequest;
 import android.credentials.GetCredentialRequest;
-import android.credentials.ui.UserSelectionDialogResult;
+import android.credentials.selection.UserSelectionDialogResult;
 import android.util.Slog;
 
 import com.android.server.credentials.MetricUtilities;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f288103..519c9bb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -71,6 +71,7 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_TIME;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER;
@@ -484,6 +485,7 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.net.module.util.ProxyUtils;
+import com.android.net.thread.flags.Flags;
 import com.android.server.AlarmManagerInternal;
 import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
@@ -13339,6 +13341,11 @@
                 UserManager.DISALLOW_SMS, new String[]{MANAGE_DEVICE_POLICY_SMS});
         USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, new String[]{MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS});
+        if (Flags.threadUserRestrictionEnabled()) {
+            USER_RESTRICTION_PERMISSIONS.put(
+                    UserManager.DISALLOW_THREAD_NETWORK,
+                    new String[]{MANAGE_DEVICE_POLICY_THREAD_NETWORK});
+        }
         USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, new String[]{MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION});
         USER_RESTRICTION_PERMISSIONS.put(
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
index 4c487a7..ba72977 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
@@ -367,8 +367,11 @@
         // TODO(b/312397262): consider virtual displays cases
         synchronized (mLock) {
             if (mIsDualDisplayBlockingEnabled
-                    && !mExternalDisplaysConnected.get(displayId, false)
-                    && mDisplayManager.getDisplay(displayId).getType() == TYPE_EXTERNAL) {
+                    && !mExternalDisplaysConnected.get(displayId, false)) {
+                var display = mDisplayManager.getDisplay(displayId);
+                if (display == null || display.getType() != TYPE_EXTERNAL) {
+                    return;
+                }
                 mExternalDisplaysConnected.put(displayId, true);
 
                 // Only update the supported state when going from 0 external display to 1
diff --git a/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java b/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
index ddf4a08..04cebab 100644
--- a/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
+++ b/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
@@ -591,6 +591,20 @@
     }
 
     @Test
+    public void testOnDisplayAddedWithNullDisplayDoesNotThrowNPE() {
+        createProvider(
+                createConfig(
+                        /* identifier= */ 1, /* name= */ "ONE",
+                        /* flags= */0, (c) -> true,
+                        FoldableDeviceStateProvider::hasNoConnectedExternalDisplay)
+        );
+
+        when(mDisplayManager.getDisplay(1)).thenReturn(null);
+        // This call should not throw NPE.
+        mProvider.onDisplayAdded(1);
+    }
+
+    @Test
     public void hasNoConnectedDisplay_afterExternalDisplayAddedAndRemoved_returnsTrue() {
         createProvider(
                 createConfig(
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 86ad494..2b8bcc7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -203,6 +203,7 @@
 import com.android.server.security.KeyAttestationApplicationIdProviderService;
 import com.android.server.security.KeyChainSystemService;
 import com.android.server.security.rkp.RemoteProvisioningService;
+import com.android.server.selinux.SelinuxAuditLogsService;
 import com.android.server.sensorprivacy.SensorPrivacyService;
 import com.android.server.sensors.SensorService;
 import com.android.server.signedconfig.SignedConfigService;
@@ -433,6 +434,9 @@
     private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService";
     private static final String GAME_MANAGER_SERVICE_CLASS =
             "com.android.server.app.GameManagerService$Lifecycle";
+    private static final String ENHANCED_CONFIRMATION_SERVICE_CLASS =
+            "com.android.ecm.EnhancedConfirmationService";
+
     private static final String UWB_APEX_SERVICE_JAR_PATH =
             "/apex/com.android.uwb/javalib/service-uwb.jar";
     private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
@@ -1592,6 +1596,12 @@
             mSystemServiceManager.startService(DropBoxManagerService.class);
             t.traceEnd();
 
+            if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()) {
+                t.traceBegin("StartEnhancedConfirmationService");
+                mSystemServiceManager.startService(ENHANCED_CONFIRMATION_SERVICE_CLASS);
+                t.traceEnd();
+            }
+
             // Grants default permissions and defines roles
             t.traceBegin("StartRoleManagerService");
             LocalManagerRegistry.addManager(RoleServicePlatformHelper.class,
@@ -2609,6 +2619,14 @@
                 t.traceEnd();
             }
 
+            t.traceBegin("StartSelinuxAuditLogsService");
+            try {
+                SelinuxAuditLogsService.schedule(context);
+            } catch (Throwable e) {
+                reportWtf("starting SelinuxAuditLogsService", e);
+            }
+            t.traceEnd();
+
             // LauncherAppsService uses ShortcutService.
             t.traceBegin("StartShortcutServiceLifecycle");
             mSystemServiceManager.startService(ShortcutService.Lifecycle.class);
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
index edacda0..15c9b9f 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
@@ -20,7 +20,6 @@
 import android.os.Build
 import android.util.Slog
 import com.android.server.permission.access.MutateStateScope
-import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
 import com.android.server.permission.access.util.andInv
 import com.android.server.permission.access.util.hasAnyBit
@@ -61,10 +60,11 @@
         if (version <= 12 /*&& SdkLevel.isAtLeastT()*/) {
             Slog.v(
                 LOG_TAG,
-                "Upgrading scoped permissions for package: $packageName" +
+                "Upgrading scoped media and body sensor permissions for package: $packageName" +
                     ", version: $version, user: $userId"
             )
             upgradeAuralVisualMediaPermissions(packageState, userId)
+            upgradeBodySensorPermissions(packageState, userId)
         }
         // TODO Enable isAtLeastU check, when moving subsystem to mainline.
         if (version <= 14 /*&& SdkLevel.isAtLeastU()*/) {
@@ -182,6 +182,50 @@
         }
     }
 
+    private fun MutateStateScope.upgradeBodySensorPermissions(
+        packageState: PackageState,
+        userId: Int
+    ) {
+        if (
+            Manifest.permission.BODY_SENSORS_BACKGROUND !in
+                packageState.androidPackage!!.requestedPermissions
+        ) {
+            return
+        }
+
+        // Should have been granted when first getting exempt as if the perm was just split
+        val appId = packageState.appId
+        val backgroundBodySensorsFlags =
+            with(policy) {
+                getPermissionFlags(appId, userId, Manifest.permission.BODY_SENSORS_BACKGROUND)
+            }
+        if (backgroundBodySensorsFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)) {
+            return
+        }
+
+        // Add Upgrade Exemption - BODY_SENSORS_BACKGROUND is a restricted permission
+        with(policy) {
+            updatePermissionFlags(
+                appId,
+                userId,
+                Manifest.permission.BODY_SENSORS_BACKGROUND,
+                PermissionFlags.UPGRADE_EXEMPT,
+                PermissionFlags.UPGRADE_EXEMPT,
+            )
+        }
+
+        val bodySensorsFlags =
+            with(policy) { getPermissionFlags(appId, userId, Manifest.permission.BODY_SENSORS) }
+        val isForegroundBodySensorsGranted = PermissionFlags.isAppOpGranted(bodySensorsFlags)
+        if (isForegroundBodySensorsGranted) {
+            grantRuntimePermission(
+                packageState,
+                userId,
+                Manifest.permission.BODY_SENSORS_BACKGROUND
+            )
+        }
+    }
+
     /** Upgrade permission based on the grant in [Manifest.permission_group.READ_MEDIA_VISUAL] */
     private fun MutateStateScope.upgradeUserSelectedVisualMediaPermission(
         packageState: PackageState,
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
index 24d4952..3284cf1 100644
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
@@ -129,7 +129,10 @@
         val packageState = newState.externalState.packageStates[packageName] ?: return
         val androidPackage = packageState.androidPackage ?: return
         val appId = packageState.appId
-        val appIdPermissionFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags
+        // The user may happen removed due to DeletePackageHelper.removeUnusedPackagesLPw() calling
+        // deletePackageX() asynchronously.
+        val userState = newState.userStates[userId] ?: return
+        val devicePermissionFlags = userState.appIdDevicePermissionFlags[appId] ?: return
         androidPackage.requestedPermissions.forEach { permissionName ->
             val isRequestedByOtherPackages =
                 anyPackageInAppId(appId) {
@@ -139,7 +142,7 @@
             if (isRequestedByOtherPackages) {
                 return@forEach
             }
-            appIdPermissionFlags[appId]?.forEachIndexed { _, deviceId, _ ->
+            devicePermissionFlags.forEachIndexed { _, deviceId, _ ->
                 setPermissionFlags(appId, deviceId, userId, permissionName, 0)
             }
         }
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
index 30afa72..dc9631a 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
@@ -16,13 +16,14 @@
 package com.android.server.inputmethod;
 
 import static com.android.server.inputmethod.ClientController.ClientControllerCallback;
-import static com.android.server.inputmethod.ClientController.ClientState;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -53,6 +54,7 @@
     private static final int ANY_DISPLAY_ID = Display.DEFAULT_DISPLAY;
     private static final int ANY_CALLER_UID = 1;
     private static final int ANY_CALLER_PID = 1;
+    private static final String SOME_PACKAGE_NAME = "some.package";
 
     @Rule
     public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
@@ -81,7 +83,8 @@
     }
 
     @Test
-    // TODO(b/314150112): Enable host side mode for this test once b/315544364 is fixed.
+    // TODO(b/314150112): Enable host side mode for this test once Ravenwood is enabled for
+    //  inputmethod server classes.
     @IgnoreUnderRavenwood(blockedBy = {InputBinding.class, IInputMethodClientInvoker.class})
     public void testAddClient_cannotAddTheSameClientTwice() {
         var invoker = IInputMethodClientInvoker.create(mClient, mHandler);
@@ -103,7 +106,8 @@
     }
 
     @Test
-    // TODO(b/314150112): Enable host side mode for this test once b/315544364 is fixed.
+    // TODO(b/314150112): Enable host side mode for this test once Ravenwood is enabled for
+    //  inputmethod server classes.
     @IgnoreUnderRavenwood(blockedBy = {InputBinding.class, IInputMethodClientInvoker.class})
     public void testAddClient() throws Exception {
         synchronized (ImfLock.class) {
@@ -112,12 +116,13 @@
                     ANY_CALLER_PID);
 
             verify(invoker.asBinder()).linkToDeath(any(IBinder.DeathRecipient.class), eq(0));
-            assertThat(mController.mClients).containsEntry(invoker.asBinder(), added);
+            assertThat(mController.getClient(invoker.asBinder())).isSameInstanceAs(added);
         }
     }
 
     @Test
-    // TODO(b/314150112): Enable host side mode for this test once b/315544364 is fixed.
+    // TODO(b/314150112): Enable host side mode for this test once Ravenwood is enabled for
+    //  inputmethod server classes.
     @IgnoreUnderRavenwood(blockedBy = {InputBinding.class, IInputMethodClientInvoker.class})
     public void testRemoveClient() {
         var callback = new TestClientControllerCallback();
@@ -128,7 +133,7 @@
             var invoker = IInputMethodClientInvoker.create(mClient, mHandler);
             added = mController.addClient(invoker, mConnection, ANY_DISPLAY_ID, ANY_CALLER_UID,
                     ANY_CALLER_PID);
-            assertThat(mController.mClients).containsEntry(invoker.asBinder(), added);
+            assertThat(mController.getClient(invoker.asBinder())).isSameInstanceAs(added);
             assertThat(mController.removeClient(mClient)).isTrue();
         }
 
@@ -137,6 +142,36 @@
         assertThat(removed).isSameInstanceAs(added);
     }
 
+    @Test
+    // TODO(b/314150112): Enable host side mode for this test once Ravenwood is enabled for
+    //  inputmethod server classes and updated to newer Mockito with static mock support (mock
+    //  InputMethodUtils#checkIfPackageBelongsToUid instead of PackageManagerInternal#isSameApp)
+    @IgnoreUnderRavenwood(blockedBy = {InputMethodUtils.class})
+    public void testVerifyClientAndPackageMatch() {
+        when(mMockPackageManagerInternal.isSameApp(eq(SOME_PACKAGE_NAME),  /* flags= */
+                anyLong(), eq(ANY_CALLER_UID), /* userId= */ anyInt())).thenReturn(true);
+
+        synchronized (ImfLock.class) {
+            var invoker = IInputMethodClientInvoker.create(mClient, mHandler);
+            mController.addClient(invoker, mConnection, ANY_DISPLAY_ID, ANY_CALLER_UID,
+                    ANY_CALLER_PID);
+            assertThat(
+                    mController.verifyClientAndPackageMatch(mClient, SOME_PACKAGE_NAME)).isTrue();
+        }
+    }
+
+    @Test
+    public void testVerifyClientAndPackageMatch_unknownClient() {
+        synchronized (ImfLock.class) {
+            assertThrows(IllegalArgumentException.class,
+                    () -> {
+                        synchronized (ImfLock.class) {
+                            mController.verifyClientAndPackageMatch(mClient, SOME_PACKAGE_NAME);
+                        }
+                    });
+        }
+    }
+
     private static class TestClientControllerCallback implements ClientControllerCallback {
 
         private final CountDownLatch mLatch = new CountDownLatch(1);
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index 438bea4..1c71a62 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -22,7 +22,6 @@
 import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SOFT_INPUT;
 import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SWITCH_USER;
 import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_SOFT_INPUT;
-import static com.android.server.inputmethod.ClientController.ClientState;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_NOT_ALWAYS;
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index 3aca1ca..f8accc3 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -103,6 +103,7 @@
         ":PackageParserTestApp4",
         ":PackageParserTestApp5",
         ":PackageParserTestApp6",
+        ":PackageParserTestApp7",
     ],
     resource_zips: [":PackageManagerServiceServerTests_apks_as_resources"],
 
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index 71f5c75..a0e0e1e 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -15,6 +15,17 @@
  */
 package com.android.server.pm;
 
+import static android.content.UriRelativeFilter.PATH;
+import static android.content.UriRelativeFilter.QUERY;
+import static android.content.UriRelativeFilter.FRAGMENT;
+import static android.content.UriRelativeFilterGroup.ACTION_ALLOW;
+import static android.content.UriRelativeFilterGroup.ACTION_BLOCK;
+import static android.os.PatternMatcher.PATTERN_ADVANCED_GLOB;
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+import static android.os.PatternMatcher.PATTERN_PREFIX;
+import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+import static android.os.PatternMatcher.PATTERN_SUFFIX;
+
 import static com.android.internal.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -36,11 +47,15 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.content.IntentFilter;
+import android.content.UriRelativeFilter;
+import android.content.UriRelativeFilterGroup;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.Property;
 import android.content.pm.ServiceInfo;
@@ -50,6 +65,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 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.util.ArraySet;
 
 import androidx.annotation.Nullable;
@@ -106,6 +124,7 @@
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -123,6 +142,9 @@
     @Rule
     public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     private File mTmpDir;
     private static final File FRAMEWORK = new File("/system/framework/framework-res.apk");
     private static final String TEST_APP1_APK = "PackageParserTestApp1.apk";
@@ -131,6 +153,7 @@
     private static final String TEST_APP4_APK = "PackageParserTestApp4.apk";
     private static final String TEST_APP5_APK = "PackageParserTestApp5.apk";
     private static final String TEST_APP6_APK = "PackageParserTestApp6.apk";
+    private static final String TEST_APP7_APK = "PackageParserTestApp7.apk";
     private static final String PACKAGE_NAME = "com.android.servicestests.apps.packageparserapp";
 
     @Before
@@ -375,6 +398,87 @@
         assertNotEquals("$automotive", actualDisplayCategory);
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+    public void testParseUriRelativeFilterGroups() throws Exception {
+        final File testFile = extractFile(TEST_APP7_APK);
+        try {
+            final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
+            final List<ParsedActivity> activities = pkg.getActivities();
+            final List<ParsedIntentInfo> intents = activities.get(0).getIntents();
+            final IntentFilter intentFilter = intents.get(0).getIntentFilter();
+            assertEquals(7, intentFilter.countUriRelativeFilterGroups());
+
+            UriRelativeFilterGroup group = intentFilter.getUriRelativeFilterGroup(0);
+            Collection<UriRelativeFilter> filters = group.getUriRelativeFilters();
+            assertEquals(ACTION_BLOCK, group.getAction());
+            assertEquals(3, filters.size());
+            assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_PREFIX, "/gizmos")));
+            assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_SIMPLE_GLOB,
+                    ".*query=string.*")));
+            assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_LITERAL,
+                    "fragment")));
+
+            group = intentFilter.getUriRelativeFilterGroup(1);
+            filters = group.getUriRelativeFilters();
+            assertEquals(ACTION_ALLOW, group.getAction());
+            assertEquals(2, filters.size());
+            assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_LITERAL,
+                    "query=string")));
+            assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_SUFFIX,
+                    "fragment")));
+
+            group = intentFilter.getUriRelativeFilterGroup(2);
+            filters = group.getUriRelativeFilters();
+            assertEquals(ACTION_ALLOW, group.getAction());
+            assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_LITERAL, "/gizmos")));
+            assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_LITERAL,
+                    ".*query=string.*")));
+            assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_LITERAL,
+                    "fragment")));
+
+            group = intentFilter.getUriRelativeFilterGroup(3);
+            filters = group.getUriRelativeFilters();
+            assertEquals(ACTION_ALLOW, group.getAction());
+            assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_PREFIX, "/gizmos")));
+            assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_PREFIX,
+                    ".*query=string.*")));
+            assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_PREFIX,
+                    "fragment")));
+
+            group = intentFilter.getUriRelativeFilterGroup(4);
+            filters = group.getUriRelativeFilters();
+            assertEquals(ACTION_ALLOW, group.getAction());
+            assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_SIMPLE_GLOB,
+                    "/gizmos")));
+            assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_SIMPLE_GLOB,
+                    ".*query=string.*")));
+            assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_SIMPLE_GLOB,
+                    "fragment")));
+
+            group = intentFilter.getUriRelativeFilterGroup(5);
+            filters = group.getUriRelativeFilters();
+            assertEquals(ACTION_ALLOW, group.getAction());
+            assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_ADVANCED_GLOB,
+                    "/gizmos")));
+            assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_ADVANCED_GLOB,
+                    ".*query=string.*")));
+            assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_ADVANCED_GLOB,
+                    "fragment")));
+
+            group = intentFilter.getUriRelativeFilterGroup(6);
+            filters = group.getUriRelativeFilters();
+            assertEquals(ACTION_ALLOW, group.getAction());
+            assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_SUFFIX, "/gizmos")));
+            assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_SUFFIX,
+                    ".*query=string.*")));
+            assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_SUFFIX,
+                    "fragment")));
+        } finally {
+            testFile.delete();
+        }
+    }
+
     private static final int PROPERTY_TYPE_BOOLEAN = 1;
     private static final int PROPERTY_TYPE_FLOAT = 2;
     private static final int PROPERTY_TYPE_INTEGER = 3;
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 02e3ef4..75febd9 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -61,6 +61,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityOptions.LaunchCookie;
 import android.app.PropertyInvalidatedCache;
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.IVirtualDeviceManager;
@@ -1557,7 +1558,7 @@
         when(mMockProjectionService
                 .setContentRecordingSession(any(ContentRecordingSession.class), eq(projection)))
                 .thenReturn(true);
-        doReturn(mock(IBinder.class)).when(projection).getLaunchCookie();
+        doReturn(new LaunchCookie()).when(projection).getLaunchCookie();
         doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection));
 
         final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index c556aca..64076e6 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -1727,6 +1727,7 @@
 
         var desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID_2);
         assertThat(desiredSpecs.primary.render.max).isEqualTo(expectedMaxRenderFrameRate);
+        assertThat(desiredSpecs.appRequest.render.max).isEqualTo(expectedMaxRenderFrameRate);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
new file mode 100644
index 0000000..2f12a3b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
@@ -0,0 +1,677 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.am;
+
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_HOME;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
+import static android.content.Context.BIND_WAIVE_PRIORITY;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED;
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
+import static com.android.server.am.ProcessList.HOME_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
+import static com.android.server.am.ProcessList.SERVICE_ADJ;
+import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.DropBoxManagerInternal;
+import com.android.server.LocalServices;
+import com.android.server.am.ActivityManagerService.Injector;
+import com.android.server.am.ApplicationExitInfoTest.ServiceThreadRule;
+import com.android.server.appop.AppOpsService;
+import com.android.server.firewall.IntentFirewall;
+import com.android.server.wm.ActivityTaskManagerService;
+import com.android.server.wm.WindowProcessController;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.verification.VerificationMode;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.function.Consumer;
+
+/**
+ * Test class for the service timeout.
+ *
+ * Build/Install/Run:
+ *  atest ServiceBindingOomAdjPolicyTest
+ */
+@Presubmit
+public final class ServiceBindingOomAdjPolicyTest {
+    private static final String TAG = ServiceBindingOomAdjPolicyTest.class.getSimpleName();
+
+    private static final String TEST_APP1_NAME = "com.example.foo";
+    private static final String TEST_SERVICE1_NAME = "com.example.foo.Foobar";
+    private static final int TEST_APP1_UID = 10123;
+    private static final int TEST_APP1_PID = 12345;
+
+    private static final String TEST_APP2_NAME = "com.example.bar";
+    private static final String TEST_SERVICE2_NAME = "com.example.bar.Buz";
+    private static final int TEST_APP2_UID = 10124;
+    private static final int TEST_APP2_PID = 12346;
+
+    @Rule
+    public final ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
+    private Context mContext;
+    private HandlerThread mHandlerThread;
+
+    @Mock
+    private AppOpsService mAppOpsService;
+    @Mock
+    private DropBoxManagerInternal mDropBoxManagerInt;
+    @Mock
+    private PackageManagerInternal mPackageManagerInt;
+    @Mock
+    private UsageStatsManagerInternal mUsageStatsManagerInt;
+    @Mock
+    private AppErrors mAppErrors;
+    @Mock
+    private IntentFirewall mIntentFirewall;
+
+    private ActivityManagerService mAms;
+    private ProcessList mProcessList;
+    private ActiveServices mActiveServices;
+
+    private int mCurrentCallingUid;
+    private int mCurrentCallingPid;
+
+    /** Run at the test class initialization */
+    @BeforeClass
+    public static void setUpOnce() {
+        System.setProperty("dexmaker.share_classloader", "true");
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+        final ProcessList realProcessList = new ProcessList();
+        mProcessList = spy(realProcessList);
+
+        LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
+        LocalServices.addService(DropBoxManagerInternal.class, mDropBoxManagerInt);
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+        doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+
+        final ActivityManagerService realAms = new ActivityManagerService(
+                new TestInjector(mContext), mServiceThreadRule.getThread());
+        final ActivityTaskManagerService realAtm = new ActivityTaskManagerService(mContext);
+        realAtm.initialize(null, null, mContext.getMainLooper());
+        realAms.mActivityTaskManager = spy(realAtm);
+        realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal());
+        realAms.mOomAdjuster = spy(realAms.mOomAdjuster);
+        realAms.mOomAdjuster.mCachedAppOptimizer = spy(realAms.mOomAdjuster.mCachedAppOptimizer);
+        realAms.mPackageManagerInt = mPackageManagerInt;
+        realAms.mUsageStatsService = mUsageStatsManagerInt;
+        realAms.mAppProfiler = spy(realAms.mAppProfiler);
+        realAms.mProcessesReady = true;
+        mAms = spy(realAms);
+        realProcessList.mService = mAms;
+
+        doReturn(false).when(mPackageManagerInt).filterAppAccess(anyString(), anyInt(), anyInt());
+        doReturn(true).when(mIntentFirewall).checkService(any(), any(), anyInt(), anyInt(), any(),
+                any());
+        doReturn(false).when(mAms.mAtmInternal).hasSystemAlertWindowPermission(anyInt(), anyInt(),
+                any());
+        doReturn(true).when(mAms.mOomAdjuster.mCachedAppOptimizer).useFreezer();
+        doNothing().when(mAms.mOomAdjuster.mCachedAppOptimizer).freezeAppAsyncInternalLSP(
+                any(), anyLong(), anyBoolean());
+        doReturn(false).when(mAms.mAppProfiler).updateLowMemStateLSP(anyInt(), anyInt(),
+                anyInt(), anyLong());
+
+        mCurrentCallingUid = TEST_APP1_UID;
+        mCurrentCallingPid = TEST_APP1_PID;
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        mHandlerThread.quit();
+    }
+
+    @Test
+    public void testServiceSelfBindingOomAdj() throws Exception {
+        // Enable the flags.
+        mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be 0 oom adj updates.
+        performTestServiceSelfBindingOomAdj(never(), never());
+
+        // Disable the flags.
+        mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update.
+        performTestServiceSelfBindingOomAdj(atLeastOnce(), atLeastOnce());
+    }
+
+    @SuppressWarnings("GuardedBy")
+    private void performTestServiceSelfBindingOomAdj(VerificationMode bindMode,
+            VerificationMode unbindMode) throws Exception {
+        final ProcessRecord app = addProcessRecord(
+                TEST_APP1_PID,           // pid
+                TEST_APP1_UID,           // uid
+                PROCESS_STATE_SERVICE,   // procstate
+                SERVICE_ADJ,             // adj
+                PROCESS_CAPABILITY_NONE, // capabilities
+                TEST_APP1_NAME           // packageName
+        );
+        final Intent serviceIntent = createServiceIntent(TEST_APP1_NAME, TEST_SERVICE1_NAME,
+                TEST_APP1_UID);
+        final IServiceConnection serviceConnection = mock(IServiceConnection.class);
+
+        // Make a self binding.
+        assertNotEquals(0, mAms.bindService(
+                app.getThread(),         // caller
+                null,                    // token
+                serviceIntent,           // service
+                null,                    // resolveType
+                serviceConnection,       // connection
+                BIND_AUTO_CREATE,        // flags
+                TEST_APP1_NAME,          // callingPackage
+                USER_SYSTEM              // userId
+        ));
+
+        verify(mAms.mOomAdjuster, bindMode).updateOomAdjPendingTargetsLocked(anyInt());
+        clearInvocations(mAms.mOomAdjuster);
+
+        // Unbind the service.
+        mAms.unbindService(serviceConnection);
+
+        verify(mAms.mOomAdjuster, unbindMode).updateOomAdjPendingTargetsLocked(anyInt());
+        clearInvocations(mAms.mOomAdjuster);
+
+        removeProcessRecord(app);
+    }
+
+    @Test
+    public void testServiceDistinctBindingOomAdjMoreImportant() throws Exception {
+        // Enable the flags.
+        mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update
+        // because the client is more important.
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+                this::setHasForegroundServices,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME,
+                HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHomeProcess,
+                BIND_AUTO_CREATE,
+                atLeastOnce(), atLeastOnce());
+
+        // Disable the flags.
+        mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update
+        // because the client is more important.
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+                this::setHasForegroundServices,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME,
+                HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHomeProcess,
+                BIND_AUTO_CREATE,
+                atLeastOnce(), atLeastOnce());
+    }
+
+    @Test
+    public void testServiceDistinctBindingOomAdjLessImportant() throws Exception {
+        // Enable the flags.
+        mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be 0 oom adj update
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_HOME, HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+                this::setHomeProcess,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE,
+                never(), never());
+
+        // Disable the flags.
+        mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_HOME, HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+                this::setHomeProcess,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE,
+                atLeastOnce(), atLeastOnce());
+    }
+
+    @Test
+    public void testServiceDistinctBindingOomAdjWaivePriority() throws Exception {
+        // Enable the flags.
+        mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be 0 oom adj update for binding
+        // because we're using the BIND_WAIVE_PRIORITY;
+        // but for the unbinding, because client is better than service, we can't skip it safely.
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+                this::setHasForegroundServices,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME,
+                HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHomeProcess,
+                BIND_AUTO_CREATE | BIND_WAIVE_PRIORITY,
+                never(), atLeastOnce());
+
+        // Verify that there should be 0 oom adj update
+        // because we're using the BIND_WAIVE_PRIORITY;
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_HOME, HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+                this::setHomeProcess,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE | BIND_WAIVE_PRIORITY,
+                never(), never());
+
+        // Disable the flags.
+        mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update
+        // because the client is more important.
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+                this::setHasForegroundServices,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME,
+                HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHomeProcess,
+                BIND_AUTO_CREATE,
+                atLeastOnce(), atLeastOnce());
+    }
+
+    @Test
+    public void testServiceDistinctBindingOomAdjNoIncludeCapabilities() throws Exception {
+        // Enable the flags.
+        mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be 0 oom adj update
+        // because we didn't specify the "BIND_INCLUDE_CAPABILITIES"
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_HOME, HOME_APP_ADJ,
+                PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, TEST_APP1_NAME,
+                this::setHomeProcess,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE,
+                never(), never());
+
+        // Disable the flags.
+        mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_HOME, HOME_APP_ADJ,
+                PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, TEST_APP1_NAME,
+                this::setHomeProcess,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE,
+                atLeastOnce(), atLeastOnce());
+    }
+
+    @Test
+    public void testServiceDistinctBindingOomAdjWithIncludeCapabilities() throws Exception {
+        // Enable the flags.
+        mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update
+        // because we use the "BIND_INCLUDE_CAPABILITIES"
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_HOME, HOME_APP_ADJ,
+                PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, TEST_APP1_NAME,
+                this::setHomeProcess,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE | BIND_INCLUDE_CAPABILITIES,
+                atLeastOnce(), atLeastOnce());
+
+        // Disable the flags.
+        mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_HOME, HOME_APP_ADJ,
+                PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, TEST_APP1_NAME,
+                this::setHomeProcess,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE | BIND_INCLUDE_CAPABILITIES,
+                atLeastOnce(), atLeastOnce());
+    }
+
+    @Test
+    public void testServiceDistinctBindingOomAdjFreezeCaller() throws Exception {
+        // Enable the flags.
+        mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be 0 oom adj update
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_CACHED_EMPTY, CACHED_APP_MIN_ADJ, PROCESS_CAPABILITY_NONE,
+                TEST_APP1_NAME, null,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE,
+                never(), never());
+
+        // Disable the flags.
+        mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+        // Verify that there should be at least 1 oom adj update
+        performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+                PROCESS_STATE_CACHED_EMPTY, CACHED_APP_MIN_ADJ, PROCESS_CAPABILITY_NONE,
+                TEST_APP1_NAME, null,
+                TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+                this::setHasForegroundServices,
+                BIND_AUTO_CREATE,
+                atLeastOnce(), atLeastOnce());
+    }
+
+    @SuppressWarnings("GuardedBy")
+    private void performTestServiceDistinctBindingOomAdj(int clientPid, int clientUid,
+            int clientProcState, int clientAdj, int clientCap, String clientPackageName,
+            Consumer<ProcessRecord> clientAppFixer,
+            int servicePid, int serviceUid, int serviceProcState, int serviceAdj,
+            int serviceCap, String servicePackageName, String serviceName,
+            Consumer<ProcessRecord> serviceAppFixer, int bindingFlags,
+            VerificationMode bindMode, VerificationMode unbindMode) throws Exception {
+        final ProcessRecord clientApp = addProcessRecord(
+                clientPid,
+                clientUid,
+                clientProcState,
+                clientAdj,
+                clientCap,
+                clientPackageName
+        );
+        final ProcessRecord serviceApp = addProcessRecord(
+                servicePid,
+                serviceUid,
+                serviceProcState,
+                serviceAdj,
+                serviceCap,
+                servicePackageName
+        );
+        final Intent serviceIntent = createServiceIntent(servicePackageName, serviceName,
+                serviceUid);
+        final IServiceConnection serviceConnection = mock(IServiceConnection.class);
+        if (clientAppFixer != null) clientAppFixer.accept(clientApp);
+        if (serviceAppFixer != null) serviceAppFixer.accept(serviceApp);
+
+        // Make a self binding.
+        assertNotEquals(0, mAms.bindService(
+                clientApp.getThread(), // caller
+                null,                  // token
+                serviceIntent,         // service
+                null,                  // resolveType
+                serviceConnection,     // connection
+                bindingFlags,          // flags
+                clientPackageName,     // callingPackage
+                USER_SYSTEM            // userId
+        ));
+
+        verify(mAms.mOomAdjuster, bindMode).updateOomAdjPendingTargetsLocked(anyInt());
+        clearInvocations(mAms.mOomAdjuster);
+
+        if (clientApp.isFreezable()) {
+            verify(mAms.mOomAdjuster.mCachedAppOptimizer,
+                    times(Flags.serviceBindingOomAdjPolicy() ? 1 : 0))
+                    .freezeAppAsyncInternalLSP(eq(clientApp), eq(0L), anyBoolean());
+            clearInvocations(mAms.mOomAdjuster.mCachedAppOptimizer);
+        }
+
+        // Unbind the service.
+        mAms.unbindService(serviceConnection);
+
+        verify(mAms.mOomAdjuster, unbindMode).updateOomAdjPendingTargetsLocked(anyInt());
+        clearInvocations(mAms.mOomAdjuster);
+
+        removeProcessRecord(clientApp);
+        removeProcessRecord(serviceApp);
+    }
+
+    private void setHasForegroundServices(ProcessRecord app) {
+        app.mServices.setHasForegroundServices(true,
+                FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, false);
+    }
+
+    private void setHomeProcess(ProcessRecord app) {
+        final WindowProcessController wpc = app.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+    }
+
+    @SuppressWarnings("GuardedBy")
+    private ProcessRecord addProcessRecord(int pid, int uid, int procState, int adj, int cap,
+                String packageName) {
+        final IApplicationThread appThread = mock(IApplicationThread.class);
+        final IBinder threadBinder = mock(IBinder.class);
+        final ProcessRecord app = makeProcessRecord(pid, uid, uid, null, 0,
+                procState, adj, cap, 0L, 0L, packageName, packageName, mAms);
+
+        app.makeActive(appThread, mAms.mProcessStats);
+        doReturn(threadBinder).when(appThread).asBinder();
+        mProcessList.addProcessNameLocked(app);
+        mProcessList.updateLruProcessLocked(app, false, null);
+
+        setFieldValue(ProcessRecord.class, app, "mWindowProcessController",
+                mock(WindowProcessController.class));
+
+        doReturn(app.getSetCapability()).when(mAms.mOomAdjuster).getDefaultCapability(
+                eq(app), anyInt());
+
+        return app;
+    }
+
+    @SuppressWarnings("GuardedBy")
+    private Intent createServiceIntent(String packageName, String serviceName, int serviceUid) {
+        final ComponentName compName = new ComponentName(packageName, serviceName);
+        final Intent serviceIntent = new Intent().setComponent(compName);
+        final ResolveInfo rInfo = new ResolveInfo();
+        rInfo.serviceInfo = makeServiceInfo(compName.getClassName(), compName.getPackageName(),
+                serviceUid);
+        doReturn(rInfo).when(mPackageManagerInt).resolveService(any(Intent.class), any(),
+                anyLong(), anyInt(), anyInt());
+
+        return serviceIntent;
+    }
+
+    @SuppressWarnings("GuardedBy")
+    private void removeProcessRecord(ProcessRecord app) {
+        app.setKilled(true);
+        mProcessList.removeProcessNameLocked(app.processName, app.uid);
+        mProcessList.removeLruProcessLocked(app);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid,
+            int connectionGroup, int procState, int adj, int cap, long pss, long rss,
+            String processName, String packageName, ActivityManagerService ams) {
+        final ProcessRecord app = ApplicationExitInfoTest.makeProcessRecord(pid, uid, packageUid,
+                definingUid, connectionGroup, procState, pss, rss, processName, packageName, ams);
+        app.mState.setCurProcState(procState);
+        app.mState.setSetProcState(procState);
+        app.mState.setCurAdj(adj);
+        app.mState.setSetAdj(adj);
+        app.mState.setCurCapability(cap);
+        app.mState.setSetCapability(cap);
+        app.mState.setCached(procState >= PROCESS_STATE_LAST_ACTIVITY || adj >= CACHED_APP_MIN_ADJ);
+        return app;
+    }
+
+    @SuppressWarnings("GuardedBy")
+    private ServiceInfo makeServiceInfo(String serviceName, String packageName, int packageUid) {
+        final ServiceInfo sInfo = new ServiceInfo();
+        sInfo.name = serviceName;
+        sInfo.processName = packageName;
+        sInfo.packageName = packageName;
+        sInfo.applicationInfo = new ApplicationInfo();
+        sInfo.applicationInfo.uid = packageUid;
+        sInfo.applicationInfo.packageName = packageName;
+        sInfo.exported = true;
+        return sInfo;
+    }
+
+    private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
+        try {
+            Field field = clazz.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            Field mfield = Field.class.getDeclaredField("accessFlags");
+            mfield.setAccessible(true);
+            mfield.setInt(field, mfield.getInt(field) & ~(Modifier.FINAL | Modifier.PRIVATE));
+            field.set(obj, val);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+        }
+    }
+
+    private class TestInjector extends Injector {
+        TestInjector(Context context) {
+            super(context);
+        }
+
+        @Override
+        public AppOpsService getAppOpsService(File recentAccessesFile, File storageFile,
+                Handler handler) {
+            return mAppOpsService;
+        }
+
+        @Override
+        public Handler getUiHandler(ActivityManagerService service) {
+            return mHandlerThread.getThreadHandler();
+        }
+
+        @Override
+        public ProcessList getProcessList(ActivityManagerService service) {
+            return mProcessList;
+        }
+
+        @Override
+        public ActiveServices getActiveServices(ActivityManagerService service) {
+            if (mActiveServices == null) {
+                mActiveServices = spy(new ActiveServices(service));
+            }
+            return mActiveServices;
+        }
+
+        @Override
+        public int getCallingUid() {
+            return mCurrentCallingUid;
+        }
+
+        @Override
+        public int getCallingPid() {
+            return mCurrentCallingPid;
+        }
+
+        @Override
+        public long clearCallingIdentity() {
+            return (((long) mCurrentCallingUid) << 32) | mCurrentCallingPid;
+        }
+
+        @Override
+        public void restoreCallingIdentity(long ident) {
+        }
+
+        @Override
+        public AppErrors getAppErrors() {
+            return mAppErrors;
+        }
+
+        @Override
+        public IntentFirewall getIntentFirewall() {
+            return mIntentFirewall;
+        }
+    }
+
+    // TODO: [b/302724778] Remove manual JNI load
+    static {
+        System.loadLibrary("mockingservicestestjni");
+    }
+}
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 93a2eef..28471b3 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
@@ -180,6 +180,7 @@
         JobSchedulerService.sElapsedRealtimeClock =
                 Clock.fixed(Instant.ofEpochMilli(FROZEN_TIME), ZoneOffset.UTC);
         // Initialize real objects.
+        doReturn(Long.MAX_VALUE).when(mPrefetchController).getNextEstimatedLaunchTimeLocked(any());
         ArgumentCaptor<BroadcastReceiver> receiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
         mFlexibilityController = new FlexibilityController(mJobSchedulerService,
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 293391f..c6608e6 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
@@ -45,6 +45,7 @@
 import static com.android.server.job.controllers.JobStatus.NO_EARLIEST_RUNTIME;
 import static com.android.server.job.controllers.JobStatus.NO_LATEST_RUNTIME;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -78,6 +79,7 @@
 
 import java.time.Clock;
 import java.time.ZoneOffset;
+import java.util.Arrays;
 
 @RunWith(AndroidJUnit4.class)
 public class JobStatusTest {
@@ -138,6 +140,35 @@
     }
 
     @Test
+    public void testApplyBasicPiiFilters_email() {
+        assertEquals("[EMAIL]", JobStatus.applyBasicPiiFilters("test@email.com"));
+        assertEquals("[EMAIL]", JobStatus.applyBasicPiiFilters("test+plus@email.com"));
+        assertEquals("[EMAIL]", JobStatus.applyBasicPiiFilters("t.e_st+plus-minus@email.com"));
+
+        assertEquals("prefix:[EMAIL]", JobStatus.applyBasicPiiFilters("prefix:test@email.com"));
+
+        assertEquals("not-an-email", JobStatus.applyBasicPiiFilters("not-an-email"));
+    }
+
+    @Test
+    public void testApplyBasicPiiFilters_mixture() {
+        assertEquals("[PHONE]:[EMAIL]",
+                JobStatus.applyBasicPiiFilters("123-456-7890:test+plus@email.com"));
+        assertEquals("prefix:[PHONE]:[EMAIL]",
+                JobStatus.applyBasicPiiFilters("prefix:123-456-7890:test+plus@email.com"));
+    }
+
+    @Test
+    public void testApplyBasicPiiFilters_phone() {
+        assertEquals("[PHONE]", JobStatus.applyBasicPiiFilters("123-456-7890"));
+        assertEquals("[PHONE]", JobStatus.applyBasicPiiFilters("+1-234-567-8900"));
+
+        assertEquals("prefix:[PHONE]", JobStatus.applyBasicPiiFilters("prefix:123-456-7890"));
+
+        assertEquals("not-a-phone-number", JobStatus.applyBasicPiiFilters("not-a-phone-number"));
+    }
+
+    @Test
     public void testCanRunInBatterySaver_regular() {
         final JobInfo jobInfo =
                 new JobInfo.Builder(101, new ComponentName("foo", "bar")).build();
@@ -245,6 +276,42 @@
     }
 
     @Test
+    public void testGetFilteredDebugTags() {
+        final JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+                .addDebugTag("test@email.com")
+                .addDebugTag("123-456-7890")
+                .addDebugTag("random")
+                .build();
+        JobStatus job = createJobStatus(jobInfo);
+        String[] expected = new String[]{"[EMAIL]", "[PHONE]", "random"};
+        String[] result = job.getFilteredDebugTags();
+        Arrays.sort(expected);
+        Arrays.sort(result);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void testGetFilteredTraceTag() {
+        JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+                .setTraceTag("test@email.com")
+                .build();
+        JobStatus job = createJobStatus(jobInfo);
+        assertEquals("[EMAIL]", job.getFilteredTraceTag());
+
+        jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+                .setTraceTag("123-456-7890")
+                .build();
+        job = createJobStatus(jobInfo);
+        assertEquals("[PHONE]", job.getFilteredTraceTag());
+
+        jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+                .setTraceTag("random")
+                .build();
+        job = createJobStatus(jobInfo);
+        assertEquals("random", job.getFilteredTraceTag());
+    }
+
+    @Test
     public void testIsUserVisibleJob() {
         JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
                 .setUserInitiated(false)
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/altitude/AltitudeConverterTest.java b/services/tests/mockingservicestests/src/com/android/server/location/altitude/AltitudeConverterTest.java
index 8d9a6c5..9a143d5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/altitude/AltitudeConverterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/altitude/AltitudeConverterTest.java
@@ -21,6 +21,8 @@
 import static org.junit.Assert.assertThrows;
 
 import android.content.Context;
+import android.frameworks.location.altitude.GetGeoidHeightRequest;
+import android.frameworks.location.altitude.GetGeoidHeightResponse;
 import android.location.Location;
 import android.location.altitude.AltitudeConverter;
 
@@ -176,4 +178,20 @@
         assertThrows(IllegalArgumentException.class,
                 () -> mAltitudeConverter.addMslAltitudeToLocation(mContext, location));
     }
+
+    @Test
+    public void testGetGeoidHeight_expectedBehavior() throws IOException {
+        GetGeoidHeightRequest request = new GetGeoidHeightRequest();
+        request.latitudeDegrees = -35.334815;
+        request.longitudeDegrees = -45;
+        // Requires data to be loaded from raw assets.
+        GetGeoidHeightResponse response = mAltitudeConverter.getGeoidHeight(mContext, request);
+        assertThat(response.geoidHeightMeters).isWithin(2).of(-5.0622);
+        assertThat(response.geoidHeightErrorMeters).isGreaterThan(0f);
+        assertThat(response.geoidHeightErrorMeters).isLessThan(1f);
+        assertThat(response.expirationDistanceMeters).isWithin(1).of(-6.33);
+        assertThat(response.additionalGeoidHeightErrorMeters).isGreaterThan(0f);
+        assertThat(response.additionalGeoidHeightErrorMeters).isLessThan(1f);
+        assertThat(response.success).isTrue();
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
index 4eba219..efab19c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
@@ -29,6 +29,7 @@
 
 import android.content.Context;
 import android.location.Location;
+import android.location.LocationRequest;
 import android.location.LocationResult;
 import android.location.provider.ProviderRequest;
 import android.platform.test.annotations.Presubmit;
@@ -218,4 +219,22 @@
         verify(mDelegate, never()).onSetRequest(ProviderRequest.EMPTY_REQUEST);
         verify(mListener, after(75).times(1)).onReportLocation(any(LocationResult.class));
     }
+
+    @Test
+    public void testNoThrottle_highAccuracy() {
+        ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(
+                50).setQuality(LocationRequest.QUALITY_HIGH_ACCURACY).build();
+
+        mProvider.getController().setRequest(request);
+        verify(mDelegate).onSetRequest(request);
+
+        LocationResult loc = createLocationResult("test_provider", mRandom);
+        mDelegateProvider.reportLocation(loc);
+        verify(mListener, times(1)).onReportLocation(loc);
+
+        mInjector.getDeviceStationaryHelper().setStationary(true);
+        mInjector.getDeviceIdleHelper().setIdle(true);
+        verify(mDelegate, never()).onSetRequest(ProviderRequest.EMPTY_REQUEST);
+        verify(mListener, after(75).times(1)).onReportLocation(any(LocationResult.class));
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
index a65ef00..bf00b75 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
@@ -552,20 +552,22 @@
         when(mComputer.getPackageStateFiltered(eq(PACKAGE), anyInt(), anyInt())).thenReturn(
                 null);
 
-        assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT)).isNull();
+        assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT,
+                CALLER_PACKAGE)).isNull();
     }
 
     @Test
     public void getArchivedAppIcon_notArchived() {
-        assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT)).isNull();
+        assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT,
+                CALLER_PACKAGE)).isNull();
     }
 
     @Test
     public void getArchivedAppIcon_success() {
         mUserState.setArchiveState(createArchiveState()).setInstalled(false);
 
-        assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT)).isEqualTo(
-                mIcon);
+        assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT,
+                CALLER_PACKAGE)).isEqualTo(mIcon);
     }
 
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 5bec903..656bc71 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -556,7 +556,7 @@
     @Test
     public void testCreateUserWithLongName_TruncatesName() {
         UserInfo user = mUms.createUserWithThrow(generateLongString(), USER_TYPE_FULL_SECONDARY, 0);
-        assertThat(user.name.length()).isEqualTo(500);
+        assertThat(user.name.length()).isEqualTo(UserManager.MAX_USER_NAME_LENGTH);
         UserInfo user1 = mUms.createUserWithThrow("Test", USER_TYPE_FULL_SECONDARY, 0);
         assertThat(user1.name.length()).isEqualTo(4);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/selinux/RateLimiterTest.java b/services/tests/mockingservicestests/src/com/android/server/selinux/RateLimiterTest.java
new file mode 100644
index 0000000..01c7fbe
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/selinux/RateLimiterTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.server.selinux;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.os.Clock;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class RateLimiterTest {
+
+    private final MockClock mMockClock = new MockClock();
+
+    @Test
+    public void testRateLimiter_1QPS() {
+        RateLimiter rateLimiter = new RateLimiter(mMockClock, Duration.ofSeconds(1));
+
+        // First acquire is granted.
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        // Next acquire is negated because it's too soon.
+        assertThat(rateLimiter.tryAcquire()).isFalse();
+        // Wait >=1 seconds.
+        mMockClock.currentTimeMillis += Duration.ofSeconds(1).toMillis();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+    }
+
+    @Test
+    public void testRateLimiter_3QPS() {
+        RateLimiter rateLimiter =
+                new RateLimiter(
+                        mMockClock,
+                        Duration.ofSeconds(1).dividedBy(3).truncatedTo(ChronoUnit.MILLIS));
+
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        mMockClock.currentTimeMillis += Duration.ofSeconds(1).dividedBy(2).toMillis();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        mMockClock.currentTimeMillis += Duration.ofSeconds(1).dividedBy(3).toMillis();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        mMockClock.currentTimeMillis += Duration.ofSeconds(1).dividedBy(4).toMillis();
+        assertThat(rateLimiter.tryAcquire()).isFalse();
+    }
+
+    @Test
+    public void testRateLimiter_infiniteQPS() {
+        RateLimiter rateLimiter = new RateLimiter(mMockClock, Duration.ofMillis(0));
+
+        // so many permits.
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+
+        mMockClock.currentTimeMillis += Duration.ofSeconds(10).toMillis();
+        // still so many permits.
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+
+        mMockClock.currentTimeMillis += Duration.ofDays(-10).toMillis();
+        // only going backwards in time you will stop the permits.
+        assertThat(rateLimiter.tryAcquire()).isFalse();
+        assertThat(rateLimiter.tryAcquire()).isFalse();
+        assertThat(rateLimiter.tryAcquire()).isFalse();
+    }
+
+    @Test
+    public void testRateLimiter_negativeQPS() {
+        RateLimiter rateLimiter = new RateLimiter(mMockClock, Duration.ofMillis(-10));
+
+        // Negative QPS is effectively turning of the rate limiter.
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        mMockClock.currentTimeMillis += Duration.ofSeconds(1000).toMillis();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+        assertThat(rateLimiter.tryAcquire()).isTrue();
+    }
+
+    private static final class MockClock extends Clock {
+
+        public long currentTimeMillis = 0;
+
+        @Override
+        public long currentTimeMillis() {
+            return currentTimeMillis;
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/selinux/SelinuxAuditLogsBuilderTest.java b/services/tests/mockingservicestests/src/com/android/server/selinux/SelinuxAuditLogsBuilderTest.java
new file mode 100644
index 0000000..b36c9bd
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/selinux/SelinuxAuditLogsBuilderTest.java
@@ -0,0 +1,202 @@
+/*
+ * 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.server.selinux;
+
+import static com.android.server.selinux.SelinuxAuditLogBuilder.PATH_MATCHER;
+import static com.android.server.selinux.SelinuxAuditLogBuilder.SCONTEXT_MATCHER;
+import static com.android.server.selinux.SelinuxAuditLogBuilder.TCONTEXT_MATCHER;
+import static com.android.server.selinux.SelinuxAuditLogBuilder.toCategories;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.selinux.SelinuxAuditLogBuilder.SelinuxAuditLog;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SelinuxAuditLogsBuilderTest {
+
+    private final SelinuxAuditLogBuilder mAuditLogBuilder = new SelinuxAuditLogBuilder();
+
+    @Test
+    public void testMatcher_scontext() {
+        assertThat(SCONTEXT_MATCHER.reset("u:r:sdk_sandbox_audit:s0").matches()).isTrue();
+        assertThat(SCONTEXT_MATCHER.group("stype")).isEqualTo("sdk_sandbox_audit");
+        assertThat(SCONTEXT_MATCHER.group("scategories")).isNull();
+
+        assertThat(SCONTEXT_MATCHER.reset("u:r:sdk_sandbox_audit:s0:c123,c456").matches()).isTrue();
+        assertThat(SCONTEXT_MATCHER.group("stype")).isEqualTo("sdk_sandbox_audit");
+        assertThat(toCategories(SCONTEXT_MATCHER.group("scategories")))
+                .isEqualTo(new int[] {123, 456});
+
+        assertThat(SCONTEXT_MATCHER.reset("u:r:not_sdk_sandbox:s0").matches()).isFalse();
+        assertThat(SCONTEXT_MATCHER.reset("u:object_r:sdk_sandbox_audit:s0").matches()).isFalse();
+        assertThat(SCONTEXT_MATCHER.reset("u:r:sdk_sandbox_audit:s0:p123").matches()).isFalse();
+    }
+
+    @Test
+    public void testMatcher_tcontext() {
+        assertThat(TCONTEXT_MATCHER.reset("u:object_r:target_type:s0").matches()).isTrue();
+        assertThat(TCONTEXT_MATCHER.group("ttype")).isEqualTo("target_type");
+        assertThat(TCONTEXT_MATCHER.group("tcategories")).isNull();
+
+        assertThat(TCONTEXT_MATCHER.reset("u:object_r:target_type2:s0:c666").matches()).isTrue();
+        assertThat(TCONTEXT_MATCHER.group("ttype")).isEqualTo("target_type2");
+        assertThat(toCategories(TCONTEXT_MATCHER.group("tcategories"))).isEqualTo(new int[] {666});
+
+        assertThat(TCONTEXT_MATCHER.reset("u:r:target_type:s0").matches()).isFalse();
+        assertThat(TCONTEXT_MATCHER.reset("u:r:sdk_sandbox_audit:s0:x456").matches()).isFalse();
+    }
+
+    @Test
+    public void testMatcher_path() {
+        assertThat(PATH_MATCHER.reset("\"/data\"").matches()).isTrue();
+        assertThat(PATH_MATCHER.group("path")).isEqualTo("/data");
+        assertThat(PATH_MATCHER.reset("\"/data/local\"").matches()).isTrue();
+        assertThat(PATH_MATCHER.group("path")).isEqualTo("/data/local");
+        assertThat(PATH_MATCHER.reset("\"/data/local/tmp\"").matches()).isTrue();
+        assertThat(PATH_MATCHER.group("path")).isEqualTo("/data/local");
+
+        assertThat(PATH_MATCHER.reset("\"/data/local").matches()).isFalse();
+        assertThat(PATH_MATCHER.reset("\"_data_local\"").matches()).isFalse();
+    }
+
+    @Test
+    public void testSelinuxAuditLogsBuilder_noOptionals() {
+        mAuditLogBuilder.reset(
+                "granted { p } scontext=u:r:sdk_sandbox_audit:s0 tcontext=u:object_r:t:s0"
+                        + " tclass=c");
+        assertAuditLog(
+                mAuditLogBuilder.build(), true, new String[] {"p"}, "sdk_sandbox_audit", "t", "c");
+
+        mAuditLogBuilder.reset(
+                "tclass=c2 granted { p2 } tcontext=u:object_r:t2:s0"
+                        + " scontext=u:r:sdk_sandbox_audit:s0");
+        assertAuditLog(
+                mAuditLogBuilder.build(),
+                true,
+                new String[] {"p2"},
+                "sdk_sandbox_audit",
+                "t2",
+                "c2");
+    }
+
+    @Test
+    public void testSelinuxAuditLogsBuilder_withCategories() {
+        mAuditLogBuilder.reset(
+                "granted { p } scontext=u:r:sdk_sandbox_audit:s0:c123"
+                        + " tcontext=u:object_r:t:s0:c456,c666 tclass=c");
+        assertAuditLog(
+                mAuditLogBuilder.build(),
+                true,
+                new String[] {"p"},
+                "sdk_sandbox_audit",
+                new int[] {123},
+                "t",
+                new int[] {456, 666},
+                "c",
+                null,
+                false);
+    }
+
+    @Test
+    public void testSelinuxAuditLogsBuilder_withPath() {
+        mAuditLogBuilder.reset(
+                "granted { p } scontext=u:r:sdk_sandbox_audit:s0 path=\"/very/long/path\""
+                        + " tcontext=u:object_r:t:s0 tclass=c");
+        assertAuditLog(
+                mAuditLogBuilder.build(),
+                true,
+                new String[] {"p"},
+                "sdk_sandbox_audit",
+                null,
+                "t",
+                null,
+                "c",
+                "/very/long",
+                false);
+    }
+
+    @Test
+    public void testSelinuxAuditLogsBuilder_withPermissive() {
+        mAuditLogBuilder.reset(
+                "granted { p } scontext=u:r:sdk_sandbox_audit:s0 permissive=0"
+                        + " tcontext=u:object_r:t:s0 tclass=c");
+        assertAuditLog(
+                mAuditLogBuilder.build(),
+                true,
+                new String[] {"p"},
+                "sdk_sandbox_audit",
+                null,
+                "t",
+                null,
+                "c",
+                null,
+                false);
+
+        mAuditLogBuilder.reset(
+                "granted { p } scontext=u:r:sdk_sandbox_audit:s0 tcontext=u:object_r:t:s0 tclass=c"
+                        + " permissive=1");
+        assertAuditLog(
+                mAuditLogBuilder.build(),
+                true,
+                new String[] {"p"},
+                "sdk_sandbox_audit",
+                null,
+                "t",
+                null,
+                "c",
+                null,
+                true);
+    }
+
+    private void assertAuditLog(
+            SelinuxAuditLog auditLog,
+            boolean granted,
+            String[] permissions,
+            String sType,
+            String tType,
+            String tClass) {
+        assertAuditLog(
+                auditLog, granted, permissions, sType, null, tType, null, tClass, null, false);
+    }
+
+    private void assertAuditLog(
+            SelinuxAuditLog auditLog,
+            boolean granted,
+            String[] permissions,
+            String sType,
+            int[] sCategories,
+            String tType,
+            int[] tCategories,
+            String tClass,
+            String path,
+            boolean permissive) {
+        assertThat(auditLog).isNotNull();
+        assertThat(auditLog.mGranted).isEqualTo(granted);
+        assertThat(auditLog.mPermissions).isEqualTo(permissions);
+        assertThat(auditLog.mSType).isEqualTo(sType);
+        assertThat(auditLog.mSCategories).isEqualTo(sCategories);
+        assertThat(auditLog.mTType).isEqualTo(tType);
+        assertThat(auditLog.mTCategories).isEqualTo(tCategories);
+        assertThat(auditLog.mTClass).isEqualTo(tClass);
+        assertThat(auditLog.mPath).isEqualTo(path);
+        assertThat(auditLog.mPermissive).isEqualTo(permissive);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/selinux/SelinuxAuditLogsCollectorTest.java b/services/tests/mockingservicestests/src/com/android/server/selinux/SelinuxAuditLogsCollectorTest.java
new file mode 100644
index 0000000..9758ea5
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/selinux/SelinuxAuditLogsCollectorTest.java
@@ -0,0 +1,644 @@
+/*
+ * 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.server.selinux;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import android.util.EventLog;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.os.Clock;
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+@RunWith(AndroidJUnit4.class)
+public class SelinuxAuditLogsCollectorTest {
+
+    // Fake tag to use for testing
+    private static final int ANSWER_TAG = 42;
+
+    private final MockClock mClock = new MockClock();
+
+    private final SelinuxAuditLogsCollector mSelinuxAutidLogsCollector =
+            // Ignore rate limiting for tests
+            new SelinuxAuditLogsCollector(
+                    new RateLimiter(mClock, /* window= */ Duration.ofMillis(0)),
+                    new QuotaLimiter(
+                            mClock, /* windowSize= */ Duration.ofHours(1), /* maxPermits= */ 5));
+
+    private MockitoSession mMockitoSession;
+
+    @Before
+    public void setUp() {
+        // move the clock forward for the limiters.
+        mClock.currentTimeMillis += Duration.ofHours(1).toMillis();
+        // Ignore what was written in the event logs by previous tests.
+        mSelinuxAutidLogsCollector.mLastWrite = Instant.now();
+
+        mMockitoSession =
+                mockitoSession().initMocks(this).mockStatic(FrameworkStatsLog.class).startMocking();
+    }
+
+    @After
+    public void tearDown() {
+        mMockitoSession.finishMocking();
+    }
+
+    @Test
+    public void testWriteSdkSandboxAuditLogs() {
+        writeTestLog("granted", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm1", "sdk_sandbox_audit", "ttype1", "tclass1");
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                true,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                null,
+                                false));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm1"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype1",
+                                null,
+                                "tclass1",
+                                null,
+                                false));
+    }
+
+    @Test
+    public void testWriteSdkSandboxAuditLogs_multiplePerms() {
+        writeTestLog("denied", "perm1 perm2", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm3 perm4", "sdk_sandbox_audit", "ttype", "tclass");
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm1", "perm2"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                null,
+                                false));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm3", "perm4"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                null,
+                                false));
+    }
+
+    @Test
+    public void testWriteSdkSandboxAuditLogs_withPaths() {
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass", "/good/path");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass", "/very/long/path");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass", "/short_path");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass", "not_a_path");
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                "/good/path",
+                                false));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                "/very/long",
+                                false));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                "/short_path",
+                                false));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                null,
+                                false));
+    }
+
+    @Test
+    public void testWriteSdkSandboxAuditLogs_withCategories() {
+        writeTestLog(
+                "denied", "perm", "sdk_sandbox_audit", new int[] {123}, "ttype", null, "tclass");
+        writeTestLog(
+                "denied",
+                "perm",
+                "sdk_sandbox_audit",
+                new int[] {123, 456},
+                "ttype",
+                null,
+                "tclass");
+        writeTestLog(
+                "denied", "perm", "sdk_sandbox_audit", null, "ttype", new int[] {666}, "tclass");
+        writeTestLog(
+                "denied",
+                "perm",
+                "sdk_sandbox_audit",
+                new int[] {123, 456},
+                "ttype",
+                new int[] {666, 777},
+                "tclass");
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                new int[] {123},
+                                "ttype",
+                                null,
+                                "tclass",
+                                null,
+                                false));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                new int[] {123, 456},
+                                "ttype",
+                                null,
+                                "tclass",
+                                null,
+                                false));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                new int[] {666},
+                                "tclass",
+                                null,
+                                false));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                new int[] {123, 456},
+                                "ttype",
+                                new int[] {666, 777},
+                                "tclass",
+                                null,
+                                false));
+    }
+
+    @Test
+    public void testWriteSdkSandboxAuditLogs_withPathAndCategories() {
+        writeTestLog(
+                "denied",
+                "perm",
+                "sdk_sandbox_audit",
+                new int[] {123},
+                "ttype",
+                new int[] {666},
+                "tclass",
+                "/a/path");
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                new int[] {123},
+                                "ttype",
+                                new int[] {666},
+                                "tclass",
+                                "/a/path",
+                                false));
+    }
+
+    @Test
+    public void testWriteSdkSandboxAuditLogs_permissive() {
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass", true);
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass", false);
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                null,
+                                false),
+                times(2));
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.SELINUX_AUDIT_LOG,
+                                false,
+                                new String[] {"perm"},
+                                "sdk_sandbox_audit",
+                                null,
+                                "ttype",
+                                null,
+                                "tclass",
+                                null,
+                                true));
+    }
+
+    @Test
+    public void testNotWriteAuditLogs_notSdkSandbox() {
+        writeTestLog("denied", "perm", "stype", "ttype", "tclass");
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                anyInt(),
+                                anyBoolean(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyBoolean()),
+                never());
+    }
+
+    @Test
+    public void testWriteSdkSandboxAuditLogs_upToQuota() {
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        // These are not pushed.
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                anyInt(),
+                                anyBoolean(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyBoolean()),
+                times(5));
+    }
+
+    @Test
+    public void testWriteSdkSandboxAuditLogs_resetQuota() {
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                anyInt(),
+                                anyBoolean(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyBoolean()),
+                times(5));
+
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        // move the clock forward to reset the quota limiter.
+        mClock.currentTimeMillis += Duration.ofHours(1).toMillis();
+        done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                anyInt(),
+                                anyBoolean(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyBoolean()),
+                times(10));
+    }
+
+    @Test
+    public void testNotWriteAuditLogs_stopRequested() {
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        // These are not pushed.
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+
+        mSelinuxAutidLogsCollector.mStopRequested.set(true);
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+        assertThat(done).isFalse();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                anyInt(),
+                                anyBoolean(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyBoolean()),
+                never());
+
+        mSelinuxAutidLogsCollector.mStopRequested.set(false);
+        done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+        assertThat(done).isTrue();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                anyInt(),
+                                anyBoolean(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyBoolean()),
+                times(5));
+    }
+
+    @Test
+    public void testAuditLogs_resumeJobDoesNotExceedLimit() {
+        writeTestLog("denied", "perm", "sdk_sandbox_audit", "ttype", "tclass");
+        mSelinuxAutidLogsCollector.mStopRequested.set(true);
+
+        boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+
+        assertThat(done).isFalse();
+        verify(
+                () ->
+                        FrameworkStatsLog.write(
+                                anyInt(),
+                                anyBoolean(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyString(),
+                                any(),
+                                anyBoolean()),
+                never());
+    }
+
+    private static void writeTestLog(
+            String granted, String permissions, String sType, String tType, String tClass) {
+        EventLog.writeEvent(
+                ANSWER_TAG,
+                String.format(
+                        "avc: %s { %s } scontext=u:r:%s:s0 tcontext=u:object_r:%s:s0 tclass=%s",
+                        granted, permissions, sType, tType, tClass));
+    }
+
+    private static void writeTestLog(
+            String granted,
+            String permissions,
+            String sType,
+            String tType,
+            String tClass,
+            String path) {
+        EventLog.writeEvent(
+                ANSWER_TAG,
+                String.format(
+                        "avc: %s { %s } path=\"%s\" scontext=u:r:%s:s0 tcontext=u:object_r:%s:s0"
+                                + " tclass=%s",
+                        granted, permissions, path, sType, tType, tClass));
+    }
+
+    private static void writeTestLog(
+            String granted,
+            String permissions,
+            String sType,
+            int[] sCategories,
+            String tType,
+            int[] tCategories,
+            String tClass) {
+        EventLog.writeEvent(
+                ANSWER_TAG,
+                String.format(
+                        "avc: %s { %s } scontext=u:r:%s:s0%s tcontext=u:object_r:%s:s0%s tclass=%s",
+                        granted,
+                        permissions,
+                        sType,
+                        toCategoriesString(sCategories),
+                        tType,
+                        toCategoriesString(tCategories),
+                        tClass));
+    }
+
+    private static void writeTestLog(
+            String granted,
+            String permissions,
+            String sType,
+            int[] sCategories,
+            String tType,
+            int[] tCategories,
+            String tClass,
+            String path) {
+        EventLog.writeEvent(
+                ANSWER_TAG,
+                String.format(
+                        "avc: %s { %s } path=\"%s\" scontext=u:r:%s:s0%s"
+                                + " tcontext=u:object_r:%s:s0%s tclass=%s",
+                        granted,
+                        permissions,
+                        path,
+                        sType,
+                        toCategoriesString(sCategories),
+                        tType,
+                        toCategoriesString(tCategories),
+                        tClass));
+    }
+
+    private static void writeTestLog(
+            String granted,
+            String permissions,
+            String sType,
+            String tType,
+            String tClass,
+            boolean permissive) {
+        EventLog.writeEvent(
+                ANSWER_TAG,
+                String.format(
+                        "avc: %s { %s } scontext=u:r:%s:s0 tcontext=u:object_r:%s:s0 tclass=%s"
+                                + " permissive=%s",
+                        granted, permissions, sType, tType, tClass, permissive ? "1" : "0"));
+    }
+
+    private static String toCategoriesString(int[] categories) {
+        return (categories == null || categories.length == 0)
+                ? ""
+                : ":c"
+                        + Arrays.stream(categories)
+                                .mapToObj(String::valueOf)
+                                .collect(Collectors.joining(",c"));
+    }
+
+    private static final class MockClock extends Clock {
+
+        public long currentTimeMillis = 0;
+
+        @Override
+        public long currentTimeMillis() {
+            return currentTimeMillis;
+        }
+    }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index bb70080..9251376 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -21,6 +21,9 @@
 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.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -96,18 +99,11 @@
         mClock.realtime = 123;
 
         mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
-                mStepDetailsCalculator, mClock, mMonotonicClock, mTracer) {
-            @Override
-            public boolean readFileToParcel(Parcel out, AtomicFile file) {
-                mReadFiles.add(file.getBaseFile().getName());
-                return super.readFileToParcel(out, file);
-            }
-        };
+                mStepDetailsCalculator, mClock, mMonotonicClock, mTracer);
 
         when(mStepDetailsCalculator.getHistoryStepDetails())
                 .thenReturn(new BatteryStats.HistoryStepDetails());
 
-
         mHistoryPrinter = new BatteryStats.HistoryPrinter();
     }
 
@@ -276,6 +272,15 @@
 
         mReadFiles.clear();
 
+        // Make an immutable copy and spy on it
+        mHistory = spy(mHistory.copy());
+
+        doAnswer(invocation -> {
+            AtomicFile file = invocation.getArgument(1);
+            mReadFiles.add(file.getBaseFile().getName());
+            return invocation.callRealMethod();
+        }).when(mHistory).readFileToParcel(any(), any());
+
         // Prepare history for iteration
         mHistory.iterate(0, MonotonicClock.UNDEFINED);
 
@@ -309,6 +314,15 @@
 
         mReadFiles.clear();
 
+        // Make an immutable copy and spy on it
+        mHistory = spy(mHistory.copy());
+
+        doAnswer(invocation -> {
+            AtomicFile file = invocation.getArgument(1);
+            mReadFiles.add(file.getBaseFile().getName());
+            return invocation.callRealMethod();
+        }).when(mHistory).readFileToParcel(any(), any());
+
         // Prepare history for iteration
         mHistory.iterate(1000, 3000);
 
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 4dae2d5..8e53d52 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
@@ -28,6 +28,9 @@
 import android.os.BatteryConsumer;
 import android.os.Binder;
 import android.os.Process;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +41,7 @@
 import com.android.internal.os.KernelSingleUidTimeReader;
 import com.android.internal.os.PowerProfile;
 import com.android.internal.power.EnergyConsumerStats;
+import com.android.server.power.optimization.Flags;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -54,6 +58,8 @@
 @RunWith(AndroidJUnit4.class)
 @SuppressWarnings("GuardedBy")
 public class SystemServicePowerCalculatorTest {
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     private static final double PRECISION = 0.000001;
     private static final int APP_UID1 = 100;
@@ -108,6 +114,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DISABLE_SYSTEM_SERVICE_POWER_ATTR)
     public void testPowerProfileBasedModel() {
         prepareBatteryStats(null);
 
@@ -135,6 +142,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DISABLE_SYSTEM_SERVICE_POWER_ATTR)
     public void testMeasuredEnergyBasedModel() {
         final boolean[] supportedPowerBuckets =
                 new boolean[EnergyConsumerStats.NUMBER_STANDARD_POWER_BUCKETS];
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 8958fac..e22d99d 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -36,6 +36,7 @@
         "-Werror",
     ],
     static_libs: [
+        "cts-input-lib",
         "frameworks-base-testutils",
         "services.accessibility",
         "services.appwidget",
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
new file mode 100644
index 0000000..52c7d8d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
@@ -0,0 +1,280 @@
+/*
+ * 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.accessibility
+
+import android.hardware.display.DisplayManagerGlobal
+import android.os.SystemClock
+import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.DisplayAdjustments
+import android.view.DisplayInfo
+import android.view.IInputFilterHost
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
+import android.view.InputEvent
+import android.view.MotionEvent
+import android.view.MotionEvent.ACTION_DOWN
+import android.view.MotionEvent.ACTION_MOVE
+import android.view.MotionEvent.ACTION_UP
+import android.view.MotionEvent.ACTION_HOVER_ENTER
+import android.view.MotionEvent.ACTION_HOVER_EXIT
+import android.view.MotionEvent.ACTION_HOVER_MOVE
+import android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.cts.input.inputeventmatchers.withDeviceId
+import com.android.cts.input.inputeventmatchers.withMotionAction
+import com.android.server.LocalServices
+import com.android.server.accessibility.magnification.MagnificationProcessor
+import com.android.server.wm.WindowManagerInternal
+import java.util.concurrent.LinkedBlockingQueue
+import org.hamcrest.Matchers.allOf
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.stubbing.OngoingStubbing
+
+
+/**
+ * Create a MotionEvent with the provided action, eventTime, and source
+ */
+fun createMotionEvent(action: Int, downTime: Long, eventTime: Long, source: Int, deviceId: Int):
+        MotionEvent {
+    val x = 1f
+    val y = 2f
+    val pressure = 3f
+    val size = 1f
+    val metaState = 0
+    val xPrecision = 0f
+    val yPrecision = 0f
+    val edgeFlags = 0
+    val displayId = 0
+    return MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
+        xPrecision, yPrecision, deviceId, edgeFlags, source, displayId)
+}
+
+/**
+ * Tests for AccessibilityInputFilter, focusing on the input event processing as seen by the callers
+ * of the InputFilter interface.
+ * The main interaction with AccessibilityInputFilter in these tests is with the filterInputEvent
+ * and sendInputEvent APIs of InputFilter.
+ */
+@RunWith(AndroidJUnit4::class)
+class AccessibilityInputFilterInputTest {
+    private val instrumentation = InstrumentationRegistry.getInstrumentation()
+
+    private companion object{
+        const val ALL_A11Y_FEATURES = (AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK
+                or AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION
+                or AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER
+                or AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
+                or AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS
+                or AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS)
+    }
+
+    @Rule
+    @JvmField
+    val mocks: MockitoRule = MockitoJUnit.rule()
+
+    @Mock
+    private lateinit var mockA11yController: WindowManagerInternal.AccessibilityControllerInternal
+
+    @Mock
+    private lateinit var mockWindowManagerService: WindowManagerInternal
+
+    @Mock
+    private lateinit var mockMagnificationProcessor: MagnificationProcessor
+
+    private val inputEvents = LinkedBlockingQueue<InputEvent>()
+    private val verifier = BlockingQueueEventVerifier(inputEvents)
+
+    @Mock
+    private lateinit var host: IInputFilterHost
+    private lateinit var ams: AccessibilityManagerService
+    private lateinit var a11yInputFilter: AccessibilityInputFilter
+    private val touchDeviceId = 1
+
+    @Before
+    fun setUp() {
+        val context = instrumentation.context
+        LocalServices.removeServiceForTest(WindowManagerInternal::class.java)
+        LocalServices.addService(WindowManagerInternal::class.java, mockWindowManagerService)
+
+        whenever(mockA11yController.isAccessibilityTracingEnabled).thenReturn(false)
+        whenever(
+            mockWindowManagerService.accessibilityController).thenReturn(
+            mockA11yController)
+
+        ams = Mockito.spy(AccessibilityManagerService(context))
+        val displayList = arrayListOf(createStubDisplay(DEFAULT_DISPLAY, DisplayInfo()))
+        whenever(ams.validDisplayList).thenReturn(displayList)
+        whenever(ams.magnificationProcessor).thenReturn(mockMagnificationProcessor)
+
+        doAnswer {
+            val event = it.getArgument(0) as MotionEvent
+            inputEvents.add(MotionEvent.obtain(event))
+        }.`when`(host).sendInputEvent(any(), anyInt())
+
+        a11yInputFilter = AccessibilityInputFilter(context, ams)
+        a11yInputFilter.install(host)
+    }
+
+    @After
+    fun tearDown() {
+        if (this::a11yInputFilter.isInitialized) {
+            a11yInputFilter.uninstall()
+        }
+    }
+
+    /**
+     * When no features are enabled, the events pass through the filter without getting modified.
+     */
+    @Test
+    fun testSingleDeviceTouchEventsWithoutA11yFeatures() {
+        enableFeatures(0)
+
+        val downTime = SystemClock.uptimeMillis()
+        val downEvent = createMotionEvent(
+            ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(downEvent)
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_DOWN), withDeviceId(touchDeviceId)))
+
+        val moveEvent = createMotionEvent(
+            ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(moveEvent)
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_MOVE), withDeviceId(touchDeviceId)))
+
+        val upEvent = createMotionEvent(
+            ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(upEvent)
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_UP), withDeviceId(touchDeviceId)))
+
+        verifier.assertNoEvents()
+    }
+
+    /**
+     * Enable all a11y features and send a touchscreen stream of DOWN -> MOVE -> UP events.
+     * These get converted into HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT events by the input filter.
+     */
+    @Test
+    fun testSingleDeviceTouchEventsWithAllA11yFeatures() {
+        enableFeatures(ALL_A11Y_FEATURES)
+
+        val downTime = SystemClock.uptimeMillis()
+        val downEvent = createMotionEvent(
+            ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(MotionEvent.obtain(downEvent))
+
+        // DOWN event gets transformed to HOVER_ENTER
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_HOVER_ENTER), withDeviceId(touchDeviceId)))
+
+        // MOVE becomes HOVER_MOVE
+        val moveEvent = createMotionEvent(
+            ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(moveEvent)
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_HOVER_MOVE), withDeviceId(touchDeviceId)))
+
+        // UP becomes HOVER_EXIT
+        val upEvent = createMotionEvent(
+            ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(upEvent)
+
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_HOVER_EXIT), withDeviceId(touchDeviceId)))
+
+        verifier.assertNoEvents()
+    }
+
+    /**
+     * Enable all a11y features and send a touchscreen event stream. In the middle of the gesture,
+     * disable the a11y features.
+     * When the a11y features are disabled, the filter generates HOVER_EXIT without further input
+     * from the dispatcher.
+     */
+    @Test
+    fun testSingleDeviceTouchEventsDisableFeaturesMidGesture() {
+        enableFeatures(ALL_A11Y_FEATURES)
+
+        val downTime = SystemClock.uptimeMillis()
+        val downEvent = createMotionEvent(
+            ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(MotionEvent.obtain(downEvent))
+
+        // DOWN event gets transformed to HOVER_ENTER
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_HOVER_ENTER), withDeviceId(touchDeviceId)))
+        verifier.assertNoEvents()
+
+        enableFeatures(0)
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_HOVER_EXIT), withDeviceId(touchDeviceId)))
+        verifier.assertNoEvents()
+
+        val moveEvent = createMotionEvent(
+            ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(moveEvent)
+        val upEvent = createMotionEvent(
+            ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+        send(upEvent)
+        // As the original gesture continues, no additional events should be getting sent by the
+        // filter because the HOVER_EXIT above already effectively finished the current gesture and
+        // the DOWN event was never sent to the host.
+
+        // Bug: the down event was swallowed, so the remainder of the gesture should be swallowed
+        // too. However, the MOVE and UP events are currently passed back to the dispatcher.
+        // TODO(b/310014874) - ensure a11y sends consistent input streams to the dispatcher
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_MOVE), withDeviceId(touchDeviceId)))
+        verifier.assertReceivedMotion(
+            allOf(withMotionAction(ACTION_UP), withDeviceId(touchDeviceId)))
+
+        verifier.assertNoEvents()
+    }
+
+    private fun createStubDisplay(displayId: Int, displayInfo: DisplayInfo): Display {
+        val display = Display(DisplayManagerGlobal.getInstance(), displayId,
+            displayInfo, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS)
+        return display
+    }
+
+    private fun send(event: InputEvent) {
+        // We need to make a copy of the event before sending it to the filter, because the filter
+        // will recycle it, but the caller of this function might want to still be able to use
+        // this event for subsequent checks
+        val eventCopy = if (event is MotionEvent) MotionEvent.obtain(event) else event
+        a11yInputFilter.filterInputEvent(eventCopy, FLAG_PASS_TO_USER)
+    }
+
+    private fun enableFeatures(features: Int) {
+        instrumentation.runOnMainSync { a11yInputFilter.setUserAndEnabledFeatures(0, features) }
+    }
+}
+
+private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt b/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt
new file mode 100644
index 0000000..b12f537
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.accessibility
+
+import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
+import android.view.InputEvent
+import android.view.MotionEvent
+import java.time.Duration
+import java.util.concurrent.BlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.fail
+
+import org.hamcrest.Matcher
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Assert.assertNull
+
+private fun <T> getEvent(queue: BlockingQueue<T>, timeout: Duration): T? {
+    return queue.poll(timeout.toMillis(), TimeUnit.MILLISECONDS)
+}
+
+class BlockingQueueEventVerifier(val queue: BlockingQueue<InputEvent>) {
+    fun assertReceivedMotion(matcher: Matcher<MotionEvent>) {
+        val event = getMotionEvent()
+        assertThat("MotionEvent checks", event, matcher)
+    }
+
+    fun assertNoEvents() {
+        val event = getEvent(queue, Duration.ofMillis(50))
+        assertNull(event)
+    }
+
+    private fun getMotionEvent(): MotionEvent {
+        val event = getEvent(queue, Duration.ofMillis(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong()))
+        if (event == null) {
+            fail("Did not get an event")
+        }
+        if (event is MotionEvent) {
+            return event
+        }
+        fail("Instead of motion, got $event")
+        throw RuntimeException("should not reach here")
+    }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 0815fe5..dd5d826 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -33,6 +33,9 @@
 import android.os.IBinder;
 import android.os.UserHandle;
 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.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -40,6 +43,7 @@
 import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
 
+import com.android.server.biometrics.Flags;
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
 
@@ -66,6 +70,9 @@
 
     @Rule
     public final MockitoRule mockito = MockitoJUnit.rule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
 
     private Handler mHandler;
     private UserAwareBiometricScheduler mScheduler;
@@ -122,6 +129,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void testScheduleOperation_whenNoUser() {
         mCurrentUserId = UserHandle.USER_NULL;
 
@@ -183,6 +191,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void testScheduleOperation_whenSameUser() {
         mCurrentUserId = 10;
 
@@ -199,6 +208,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void testScheduleOperation_whenDifferentUser() {
         mCurrentUserId = 10;
 
@@ -219,6 +229,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void testStartUser_alwaysStartsNextOperation() {
         BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
         when(nextClient.getTargetUserId()).thenReturn(10);
@@ -246,6 +257,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void testStartUser_failsClearsStopUserClient() {
         // When a stop user client fails, check that mStopUserClient
         // is set to null to prevent the scheduler from getting stuck.
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
index f8b5b04..84c3684 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
@@ -50,12 +50,17 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 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;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.TestableContext;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.server.biometrics.Flags;
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
 import com.android.server.biometrics.log.OperationContextExt;
@@ -94,6 +99,9 @@
     @Rule
     public final TestableContext mContext = new TestableContext(
             InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Mock
     private ISession mHal;
@@ -127,6 +135,8 @@
     private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
     @Captor
     private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+    @Captor
+    private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumerCaptor;
 
     @Rule
     public final MockitoRule mockito = MockitoJUnit.rule();
@@ -149,6 +159,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void authWithContext_v2() throws RemoteException {
         final FaceAuthenticationClient client = createClient(2);
         client.start(mCallback);
@@ -189,6 +200,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void notifyHalWhenContextChanges() throws RemoteException {
         final FaceAuthenticationClient client = createClient();
         client.start(mCallback);
@@ -211,6 +223,36 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+    public void subscribeContextAndStartHal() throws RemoteException {
+        final FaceAuthenticationClient client = createClient();
+        client.start(mCallback);
+
+        verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+
+        mStartHalConsumerCaptor.getValue().accept(
+                mOperationContextCaptor.getValue().toAidlContext());
+        final ArgumentCaptor<OperationContext> captor =
+                ArgumentCaptor.forClass(OperationContext.class);
+
+        verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
+
+        OperationContext opContext = captor.getValue();
+
+        assertThat(opContext).isSameInstanceAs(
+                mOperationContextCaptor.getValue().toAidlContext());
+
+        mContextInjector.getValue().accept(opContext);
+
+        verify(mHal).onContextChanged(same(opContext));
+
+        client.stopHalOperation();
+
+        verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+    }
+
+    @Test
     public void cancelsAuthWhenNotInForeground() throws Exception {
         final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo();
         topTask.topActivity = new ComponentName("other", "thing");
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
index fbf0e13..e626f73 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
@@ -37,11 +37,16 @@
 import android.os.RemoteException;
 import android.os.Vibrator;
 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;
 import android.testing.TestableContext;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.server.biometrics.Flags;
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
 import com.android.server.biometrics.log.OperationContextExt;
@@ -71,6 +76,9 @@
     @Rule
     public final TestableContext mContext = new TestableContext(
             InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Mock
     private ISession mHal;
@@ -91,6 +99,8 @@
     @Captor
     private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
     @Captor
+    private ArgumentCaptor<Consumer<OperationContext>> mStartHalCaptor;
+    @Captor
     private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
 
     @Rule
@@ -114,6 +124,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void detectWithContext_v2() throws RemoteException {
         final FaceDetectClient client = createClient(2);
         client.start(mCallback);
@@ -132,6 +143,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void notifyHalWhenContextChanges() throws RemoteException {
         final FaceDetectClient client = createClient();
         client.start(mCallback);
@@ -154,6 +166,35 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+    public void subscribeContextAndStartHal() throws RemoteException {
+        final FaceDetectClient client = createClient();
+        client.start(mCallback);
+
+        verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                mStartHalCaptor.capture(), mContextInjector.capture(), any());
+
+        mStartHalCaptor.getValue().accept(mOperationContextCaptor.getValue().toAidlContext());
+        final ArgumentCaptor<OperationContext> captor =
+                ArgumentCaptor.forClass(OperationContext.class);
+
+        verify(mHal).detectInteractionWithContext(captor.capture());
+
+        OperationContext opContext = captor.getValue();
+
+        assertThat(opContext).isSameInstanceAs(
+                mOperationContextCaptor.getValue().toAidlContext());
+
+        mContextInjector.getValue().accept(opContext);
+
+        verify(mHal).onContextChanged(same(opContext));
+
+        client.stopHalOperation();
+
+        verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+    }
+
+    @Test
     public void doesNotPlayHapticOnInteractionDetected() throws Exception {
         final FaceDetectClient client = createClient();
         client.start(mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
index d662620..43ed07a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
@@ -28,17 +28,21 @@
 import static org.mockito.Mockito.when;
 
 import android.hardware.biometrics.common.OperationContext;
-import android.hardware.biometrics.face.FaceEnrollOptions;
 import android.hardware.biometrics.face.ISession;
 import android.hardware.face.Face;
 import android.os.IBinder;
 import android.os.RemoteException;
 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;
 import android.testing.TestableContext;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.server.biometrics.Flags;
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
 import com.android.server.biometrics.log.OperationContextExt;
@@ -68,6 +72,9 @@
     @Rule
     public final TestableContext mContext = new TestableContext(
             InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Mock
     private ISession mHal;
@@ -89,6 +96,8 @@
     private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
     @Captor
     private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+    @Captor
+    private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumer;
 
     @Rule
     public final MockitoRule mockito = MockitoJUnit.rule();
@@ -109,6 +118,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void enrollWithContext_v2() throws RemoteException {
         final FaceEnrollClient client = createClient(2);
         client.start(mCallback);
@@ -123,6 +133,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void notifyHalWhenContextChanges() throws RemoteException {
         final FaceEnrollClient client = createClient(3);
         client.start(mCallback);
@@ -145,6 +156,37 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+    public void subscribeContextAndStartHal() throws RemoteException {
+        final FaceEnrollClient client = createClient(3);
+        client.start(mCallback);
+
+        verify(mBiometricContext).subscribe(
+                mOperationContextCaptor.capture(), mStartHalConsumer.capture(),
+                mContextInjector.capture(), any());
+
+        mStartHalConsumer.getValue().accept(mOperationContextCaptor.getValue().toAidlContext());
+        final ArgumentCaptor<OperationContext> captor =
+                ArgumentCaptor.forClass(OperationContext.class);
+
+        verify(mHal).enrollWithContext(any(), anyByte(), any(), any(), captor.capture());
+
+        OperationContext opContext = captor.getValue();
+
+        assertThat(opContext).isSameInstanceAs(
+                mOperationContextCaptor.getValue().toAidlContext());
+
+        mContextInjector.getValue().accept(opContext);
+
+        verify(mHal).onContextChanged(same(opContext));
+
+        client.stopHalOperation();
+
+        verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void enrollWithFaceOptions() throws RemoteException {
         final FaceEnrollClient client = createClient(4);
         client.start(mCallback);
@@ -152,6 +194,20 @@
         verify(mHal).enrollWithOptions(any());
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+    public void enrollWithFaceOptionsAfterSubscribingContext() throws RemoteException {
+        final FaceEnrollClient client = createClient(4);
+        client.start(mCallback);
+
+        verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                mStartHalConsumer.capture(), any(), any());
+
+        mStartHalConsumer.getValue().accept(mOperationContextCaptor.getValue().toAidlContext());
+
+        verify(mHal).enrollWithOptions(any());
+    }
+
     private FaceEnrollClient createClient() throws RemoteException {
         return createClient(200 /* version */);
     }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
index 78c1e08..949d6ee 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
@@ -38,11 +38,15 @@
 import android.os.Looper;
 import android.os.UserManager;
 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 androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
+import com.android.server.biometrics.Flags;
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.sensors.AuthenticationStateListeners;
 import com.android.server.biometrics.sensors.BiometricScheduler;
@@ -50,6 +54,7 @@
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -70,6 +75,10 @@
     private static final int USER_ID = 20;
     private static final float FRR_THRESHOLD = 0.2f;
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
     @Mock
     private Context mContext;
     @Mock
@@ -145,6 +154,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void scheduleGenerateChallenge_cachesResult() {
         final IFaceServiceReceiver[] mocks = IntStream.range(0, 3)
                 .mapToObj(i -> mock(IFaceServiceReceiver.class))
@@ -163,6 +173,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void scheduleRevokeChallenge_waitsUntilEmpty() {
         final long challenge = 22;
         final IFaceServiceReceiver[] mocks = IntStream.range(0, 3)
@@ -182,6 +193,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void scheduleRevokeChallenge_doesNotWaitForever() {
         mFace10.scheduleGenerateChallenge(
                 SENSOR_ID, USER_ID, mBinder, mock(IFaceServiceReceiver.class), TAG);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 4ed6f74..f96d9e8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -56,6 +56,7 @@
 import android.os.RemoteException;
 import android.os.test.TestLooper;
 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;
@@ -158,6 +159,9 @@
     private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
     @Captor
     private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+    @Captor
+    private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumerCaptor;
+
     private final TestLooper mLooper = new TestLooper();
 
     @Before
@@ -175,12 +179,19 @@
     public void authNoContext_v1() throws RemoteException {
         final FingerprintAuthenticationClient client = createClient(1);
         client.start(mCallback);
+        if (Flags.deHidl()) {
+            verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                    mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+            mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+                    .getValue().toAidlContext());
+        }
 
         verify(mHal).authenticate(eq(OP_ID));
         verify(mHal, never()).authenticateWithContext(anyLong(), any());
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void authWithContext_v2() throws RemoteException {
         final FingerprintAuthenticationClient client = createClient(2);
         client.start(mCallback);
@@ -262,15 +273,24 @@
     public void luxProbeWhenAwake() throws RemoteException {
         when(mBiometricContext.isAwake()).thenReturn(false);
         when(mBiometricContext.isAod()).thenReturn(false);
+
         final FingerprintAuthenticationClient client = createClient();
         client.start(mCallback);
+        if (Flags.deHidl()) {
+            verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                    mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+            mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+                    .getValue().toAidlContext());
+        }
 
         final ArgumentCaptor<OperationContext> captor =
                 ArgumentCaptor.forClass(OperationContext.class);
         verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
         OperationContext opContext = captor.getValue();
-        verify(mBiometricContext).subscribe(
-                mOperationContextCaptor.capture(), mContextInjector.capture());
+        if (!Flags.deHidl()) {
+            verify(mBiometricContext).subscribe(
+                    mOperationContextCaptor.capture(), mContextInjector.capture());
+        }
         assertThat(mOperationContextCaptor.getValue().toAidlContext())
                 .isSameInstanceAs(opContext);
 
@@ -305,6 +325,12 @@
         when(mBiometricContext.isAod()).thenReturn(false);
         final FingerprintAuthenticationClient client = createClient();
         client.start(mCallback);
+        if (Flags.deHidl()) {
+            verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                    mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+            mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+                    .getValue().toAidlContext());
+        }
 
         verify(mLuxProbe, isAwake ? times(1) : never()).enable();
     }
@@ -315,13 +341,21 @@
         when(mBiometricContext.isAod()).thenReturn(true);
         final FingerprintAuthenticationClient client = createClient();
         client.start(mCallback);
+        if (Flags.deHidl()) {
+            verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                    mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+            mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+                    .getValue().toAidlContext());
+        }
 
         final ArgumentCaptor<OperationContext> captor =
                 ArgumentCaptor.forClass(OperationContext.class);
         verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
         OperationContext opContext = captor.getValue();
-        verify(mBiometricContext).subscribe(
-                mOperationContextCaptor.capture(), mContextInjector.capture());
+        if (!Flags.deHidl()) {
+            verify(mBiometricContext).subscribe(
+                    mOperationContextCaptor.capture(), mContextInjector.capture());
+        }
         assertThat(opContext).isSameInstanceAs(
                 mOperationContextCaptor.getValue().toAidlContext());
 
@@ -345,6 +379,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void notifyHalWhenContextChanges() throws RemoteException {
         final FingerprintAuthenticationClient client = createClient();
         client.start(mCallback);
@@ -367,6 +402,36 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+    public void subscribeContextAndStartHal() throws RemoteException {
+        final FingerprintAuthenticationClient client = createClient();
+        client.start(mCallback);
+
+        verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+
+        mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+                .getValue().toAidlContext());
+        final ArgumentCaptor<OperationContext> captor =
+                ArgumentCaptor.forClass(OperationContext.class);
+
+        verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
+
+        OperationContext opContext = captor.getValue();
+
+        assertThat(opContext).isSameInstanceAs(
+                mOperationContextCaptor.getValue().toAidlContext());
+
+        mContextInjector.getValue().accept(opContext);
+
+        verify(mHal).onContextChanged(same(opContext));
+
+        client.stopHalOperation();
+
+        verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+    }
+
+    @Test
     public void showHideOverlay_cancel() throws RemoteException {
         showHideOverlay(c -> c.cancel());
     }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
index a467c84..9edb8dd 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
@@ -35,11 +35,16 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 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;
 import android.testing.TestableContext;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.server.biometrics.Flags;
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
 import com.android.server.biometrics.log.OperationContextExt;
@@ -67,6 +72,9 @@
     @Rule
     public final TestableContext mContext = new TestableContext(
             InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Mock
     private ISession mHal;
@@ -88,6 +96,8 @@
     private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
     @Captor
     private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+    @Captor
+    private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumerCaptor;
 
     @Rule
     public final MockitoRule mockito = MockitoJUnit.rule();
@@ -109,6 +119,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void detectNoContext_v2() throws RemoteException {
         final FingerprintDetectClient client = createClient(2);
 
@@ -127,6 +138,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void notifyHalWhenContextChanges() throws RemoteException {
         final FingerprintDetectClient client = createClient();
         client.start(mCallback);
@@ -149,6 +161,31 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+    public void subscribeContextAndStartHal() throws RemoteException {
+        final FingerprintDetectClient client = createClient();
+        client.start(mCallback);
+
+        verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+
+        mStartHalConsumerCaptor.getValue().accept(
+                mOperationContextCaptor.getValue().toAidlContext());
+        final ArgumentCaptor<OperationContext> captor =
+                ArgumentCaptor.forClass(OperationContext.class);
+        verify(mHal).detectInteractionWithContext(captor.capture());
+        OperationContext opContext = captor.getValue();
+
+        assertThat(opContext).isSameInstanceAs(
+                mOperationContextCaptor.getValue().toAidlContext());
+        mContextInjector.getValue().accept(opContext);
+        verify(mHal).onContextChanged(same(opContext));
+
+        client.stopHalOperation();
+        verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+    }
+
+    @Test
     public void testWhenListenerIsNull() {
         final AidlSession aidl = new AidlSession(0, mHal, USER_ID, mAidlResponseHandler);
         final FingerprintDetectClient client =  new FingerprintDetectClient(mContext, () -> aidl,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index e7d4a2e..951c9393 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -40,12 +40,17 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 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;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.TestableContext;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.server.biometrics.Flags;
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
 import com.android.server.biometrics.log.CallbackWithProbe;
@@ -73,6 +78,9 @@
 public class FingerprintEnrollClientTest {
 
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
 
     private static final byte[] HAT = new byte[69];
     private static final int USER_ID = 8;
@@ -117,6 +125,8 @@
     private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
     @Captor
     private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+    @Captor
+    private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumerCaptor;
 
     @Rule
     public final MockitoRule mockito = MockitoJUnit.rule();
@@ -140,6 +150,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void enrollWithContext_v2() throws RemoteException {
         final FingerprintEnrollClient client = createClient(2);
 
@@ -236,6 +247,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
     public void notifyHalWhenContextChanges() throws RemoteException {
         final FingerprintEnrollClient client = createClient();
         client.start(mCallback);
@@ -257,6 +269,30 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+    public void subscribeContextAndStartHal() throws RemoteException {
+        final FingerprintEnrollClient client = createClient();
+        client.start(mCallback);
+
+        verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+                mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+
+        mStartHalConsumerCaptor.getValue().accept(
+                mOperationContextCaptor.getValue().toAidlContext());
+        final ArgumentCaptor<OperationContext> captor =
+                ArgumentCaptor.forClass(OperationContext.class);
+        verify(mHal).enrollWithContext(any(), captor.capture());
+        OperationContext opContext = captor.getValue();
+
+        mContextInjector.getValue().accept(
+                mOperationContextCaptor.getValue().toAidlContext());
+        verify(mHal).onContextChanged(same(opContext));
+
+        client.stopHalOperation();
+        verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+    }
+
+    @Test
     public void showHideOverlay_cancel() throws RemoteException {
         showHideOverlay(c -> c.cancel());
     }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
index ccbbaa5..5943832 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
@@ -33,19 +33,21 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.WindowManager;
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.input.flags.Flags;
 import com.android.server.LocalServices;
 import com.android.server.input.InputManagerInternal;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -58,6 +60,9 @@
     private static final String LANGUAGE_TAG = "en-US";
     private static final String LAYOUT_TYPE = "qwerty";
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Mock
     private InputManagerInternal mInputManagerInternalMock;
     @Mock
@@ -72,11 +77,12 @@
 
     @Before
     public void setUp() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_POINTER_CHOREOGRAPHER);
+
         MockitoAnnotations.initMocks(this);
         mInputManagerMockHelper = new InputManagerMockHelper(
                 TestableLooper.get(this), mNativeWrapperMock, mIInputManagerMock);
 
-        doReturn(true).when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
         LocalServices.removeServiceForTest(InputManagerInternal.class);
         LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock);
 
@@ -129,11 +135,7 @@
         mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken,
                 /* displayId= */ 1);
         verify(mNativeWrapperMock).openUinputMouse(eq("name"), eq(1), eq(1), anyString());
-        verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
-        doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         mInputController.unregisterInputDevice(deviceToken);
-        verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(
-                eq(Display.INVALID_DISPLAY));
     }
 
     @Test
@@ -143,14 +145,11 @@
         mInputController.createMouse("mouse1", /*vendorId= */ 1, /*productId= */ 1, deviceToken,
                 /* displayId= */ 1);
         verify(mNativeWrapperMock).openUinputMouse(eq("mouse1"), eq(1), eq(1), anyString());
-        verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
         final IBinder deviceToken2 = new Binder();
         mInputController.createMouse("mouse2", /*vendorId= */ 1, /*productId= */ 1, deviceToken2,
                 /* displayId= */ 2);
         verify(mNativeWrapperMock).openUinputMouse(eq("mouse2"), eq(1), eq(1), anyString());
-        verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(2));
         mInputController.unregisterInputDevice(deviceToken);
-        verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 9ff29d2..5442af8 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -339,8 +339,8 @@
         LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
 
         mSetFlagsRule.initAllFlagsToReleaseConfigDefault();
+        mSetFlagsRule.enableFlags(com.android.input.flags.Flags.FLAG_ENABLE_POINTER_CHOREOGRAPHER);
 
-        doReturn(true).when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
         doNothing().when(mInputManagerInternalMock)
                 .setMousePointerAccelerationEnabled(anyBoolean(), anyInt());
         doNothing().when(mInputManagerInternalMock).setPointerIconVisible(anyBoolean(), anyInt());
@@ -1333,7 +1333,6 @@
         mInputController.addDeviceForTesting(BINDER, fd,
                 InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS,
                 DEVICE_NAME_1, INPUT_DEVICE_ID);
-        doReturn(DISPLAY_ID_1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         assertThat(mDeviceImpl.sendButtonEvent(BINDER,
                 new VirtualMouseButtonEvent.Builder()
                         .setButtonCode(buttonCode)
@@ -1363,7 +1362,6 @@
         mInputController.addDeviceForTesting(BINDER, fd,
                 InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
                 INPUT_DEVICE_ID);
-        doReturn(DISPLAY_ID_1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         assertThat(mDeviceImpl.sendRelativeEvent(BINDER,
                 new VirtualMouseRelativeEvent.Builder()
                         .setRelativeX(x)
@@ -1394,7 +1392,6 @@
         mInputController.addDeviceForTesting(BINDER, fd,
                 InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
                 INPUT_DEVICE_ID);
-        doReturn(DISPLAY_ID_1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         assertThat(mDeviceImpl.sendScrollEvent(BINDER,
                 new VirtualMouseScrollEvent.Builder()
                         .setXAxisMovement(x)
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
index 3e4f1df..81981e6 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
@@ -183,9 +183,8 @@
     private VirtualCameraConfig createVirtualCameraConfig(
             int width, int height, int format, int maximumFramesPerSecond,
             String name, int sensorOrientation, int lensFacing) {
-        return new VirtualCameraConfig.Builder()
+        return new VirtualCameraConfig.Builder(name)
                 .addStreamConfig(width, height, format, maximumFramesPerSecond)
-                .setName(name)
                 .setVirtualCameraCallback(mCallbackHandler, mVirtualCameraCallbackMock)
                 .setSensorOrientation(sensorOrientation)
                 .setLensFacing(lensFacing)
diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
index d850c73..57f3cc0 100644
--- a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
@@ -22,6 +22,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 
+import androidx.annotation.NonNull;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -40,10 +41,12 @@
 public final class CredentialManagerServiceTest {
 
     Context mContext = null;
+    MockSettingsWrapper mSettingsWrapper = null;
 
     @Before
     public void setUp() throws CertificateException {
         mContext = ApplicationProvider.getApplicationContext();
+        mSettingsWrapper = new MockSettingsWrapper(mContext);
     }
 
     @Test
@@ -81,7 +84,8 @@
                 Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
                 "com.example.test/com.example.test.TestActivity");
 
-        CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test");
+        CredentialManagerService.updateProvidersWhenPackageRemoved(
+                mSettingsWrapper, "com.example.test");
 
         assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo("");
         assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE))
@@ -101,7 +105,8 @@
         setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE, testCredentialValue);
         setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue);
 
-        CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test3");
+        CredentialManagerService.updateProvidersWhenPackageRemoved(
+                mSettingsWrapper, "com.example.test3");
 
         // Since the provider removed was not a primary provider then we should do nothing.
         assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE))
@@ -125,7 +130,8 @@
                 Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
                 "com.example.test/com.example.test.TestActivity");
 
-        CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test");
+        CredentialManagerService.updateProvidersWhenPackageRemoved(
+                mSettingsWrapper, "com.example.test");
 
         assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo("");
         assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE))
@@ -144,7 +150,8 @@
         setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE, testCredentialValue);
         setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue);
 
-        CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test3");
+        CredentialManagerService.updateProvidersWhenPackageRemoved(
+                mSettingsWrapper, "com.example.test3");
 
         // Since the provider removed was not a primary provider then we should do nothing.
         assertCredentialPropertyEquals(
@@ -176,12 +183,36 @@
         assertThat(actualValueSet).isEqualTo(newValueSet);
     }
 
-    private void setSettingsKey(String key, String value) {
-        assertThat(Settings.Secure.putString(mContext.getContentResolver(), key, value)).isTrue();
+    private void setSettingsKey(String name, String value) {
+        assertThat(
+                        mSettingsWrapper.putStringForUser(
+                                name, value, UserHandle.myUserId(), true))
+                .isTrue();
     }
 
-    private String getSettingsKey(String key) {
-        return Settings.Secure.getStringForUser(
-                mContext.getContentResolver(), key, UserHandle.myUserId());
+    private String getSettingsKey(String name) {
+        return mSettingsWrapper.getStringForUser(name, UserHandle.myUserId());
+    }
+
+    private static final class MockSettingsWrapper
+            extends CredentialManagerService.SettingsWrapper {
+
+        MockSettingsWrapper(@NonNull Context context) {
+            super(context);
+        }
+
+        /** Updates the string value of a system setting */
+        @Override
+        public boolean putStringForUser(
+                String name,
+                String value,
+                int userHandle,
+                boolean overrideableByRestore) {
+            // This will ensure that when the settings putStringForUser method is called by
+            // CredentialManagerService that the overrideableByRestore bit is true.
+            assertThat(overrideableByRestore).isTrue();
+
+            return Settings.Secure.putStringForUser(getContentResolver(), name, value, userHandle);
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java b/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java
index 6bc0fbf..0f3f27a 100644
--- a/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java
@@ -39,8 +39,8 @@
 import android.credentials.CredentialOption;
 import android.credentials.GetCredentialException;
 import android.credentials.GetCredentialResponse;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
 import android.net.Uri;
 import android.os.Bundle;
 import android.service.credentials.CallingAppInfo;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 6207349..1bd6e29 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -659,6 +659,64 @@
         mTestLooper.dispatchAll();
         assertThat(mActiveMediaSessionsPaused).isFalse();
     }
+    @Test
+    public void handleRoutingInformation_physicalAddressOfSender_Tv_activeSourceChange() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+        mPowerManager.setInteractive(true);
+        // Physical address reported in this message is the same as message sender's (TV) physical
+        // address.
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingInformation(Constants.ADDR_TV, 0x0000);
+
+        assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
+                .isEqualTo(Constants.HANDLED);
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                0x0000);
+        // Active source's logical address is invalidated.
+        // See {@link HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation}.
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                ADDR_INVALID);
+        assertThat(mPowerManager.isInteractive()).isFalse();
+    }
+
+    @Test
+    public void handleRoutingInformation_physicalAddressOfSender_notTv_noActiveSourceChange() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+        // Add a device to the network and assert that this device is included in the list of
+        // devices.
+        HdmiDeviceInfo infoPlayback = HdmiDeviceInfo.cecDeviceBuilder()
+                .setLogicalAddress(Constants.ADDR_PLAYBACK_3)
+                .setPhysicalAddress(0x1000)
+                .setPortId(PORT_1)
+                .setDeviceType(HdmiDeviceInfo.DEVICE_PLAYBACK)
+                .setVendorId(0x1000)
+                .setDisplayName("Playback 3")
+                .build();
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoPlayback);
+        mPowerManager.setInteractive(true);
+        // Physical address reported in this message is the same as message sender's (Playback_3)
+        // physical address.
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingInformation(Constants.ADDR_PLAYBACK_3, 0x1000);
+
+        assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
+                .isEqualTo(Constants.HANDLED);
+        assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+                mPlaybackPhysicalAddress);
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                mPlaybackLogicalAddress);
+        assertThat(mPowerManager.isInteractive()).isTrue();
+    }
 
     @Test
     public void handleSetStreamPath() {
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 5e38010..67ae998 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -170,6 +170,11 @@
                     }
 
                     @Override
+                    boolean isPowerOnOrTransient() {
+                        return true;
+                    }
+
+                    @Override
                     void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
                         mDeviceEventListeners.add(new DeviceEventListener(device, status));
                     }
@@ -1839,4 +1844,38 @@
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
     }
+
+    @Test
+    public void handleStandby_fromActiveSource_standby() {
+        mPowerManager.setInteractive(true);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_1, 0x1000,
+                "HdmiCecLocalDeviceTvTest");
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+                ADDR_TV);
+        assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
+                .isEqualTo(Constants.HANDLED);
+        mTestLooper.dispatchAll();
+
+        assertThat(mPowerManager.isInteractive()).isFalse();
+    }
+
+    @Test
+    public void handleStandby_fromNonActiveSource_noStandby() {
+        mPowerManager.setInteractive(true);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mHdmiControlService.setActiveSource(ADDR_PLAYBACK_2, 0x2000,
+                "HdmiCecLocalDeviceTvTest");
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+                ADDR_TV);
+        assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
+                .isEqualTo(Constants.HANDLED);
+        mTestLooper.dispatchAll();
+
+        assertThat(mPowerManager.isInteractive()).isTrue();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index eca19c8..2da2f50 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -506,6 +506,14 @@
     }
 
     @Test
+    public void testUnlockUserWithTokenWithBadHandleReturnsFalse() {
+        final long badTokenHandle = 123456789;
+        final byte[] token = "some-high-entropy-secure-token".getBytes();
+        mService.initializeSyntheticPassword(PRIMARY_USER_ID);
+        assertFalse(mLocalService.unlockUserWithToken(badTokenHandle, token, PRIMARY_USER_ID));
+    }
+
+    @Test
     public void testGetHashFactorPrimaryUser() throws RemoteException {
         LockscreenCredential password = newPassword("password");
         initSpAndSetCredential(PRIMARY_USER_ID, password);
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 097cc51..abd3abe 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
@@ -49,6 +49,7 @@
 import static org.testng.Assert.assertThrows;
 
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions.LaunchCookie;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.ApplicationInfo;
@@ -784,7 +785,7 @@
             @RecordContent int recordedContent)
             throws NameNotFoundException {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
-        projection.setLaunchCookie(mock(IBinder.class));
+        projection.setLaunchCookie(new LaunchCookie());
         projection.start(mIMediaProjectionCallback);
         projection.notifyVirtualDisplayCreated(10);
         // Waiting for user to review consent.
@@ -825,7 +826,7 @@
     public void testSetUserReviewGrantedConsentResult_displayMirroring_noPriorSession()
             throws NameNotFoundException {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
-        projection.setLaunchCookie(mock(IBinder.class));
+        projection.setLaunchCookie(new LaunchCookie());
         projection.start(mIMediaProjectionCallback);
         // Skip setting the prior session details.
 
@@ -844,7 +845,7 @@
     public void testSetUserReviewGrantedConsentResult_displayMirroring_sessionNotWaiting()
             throws NameNotFoundException {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
-        projection.setLaunchCookie(mock(IBinder.class));
+        projection.setLaunchCookie(new LaunchCookie());
         projection.start(mIMediaProjectionCallback);
         // Session is not waiting for user's consent.
         doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index dc1d2c5..1c6d36b 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -17,16 +17,19 @@
 package com.android.server.os;
 
 import android.app.admin.flags.Flags;
-import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
 
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
 
 import android.app.role.RoleManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.BugreportManager.BugreportCallback;
 import android.os.IBinder;
@@ -48,6 +51,8 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.io.FileDescriptor;
 import java.util.concurrent.CompletableFuture;
@@ -66,6 +71,9 @@
     private BugreportManagerServiceImpl mService;
     private BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;
 
+    @Mock
+    private PackageManager mPackageManager;
+
     private int mCallingUid = 1234;
     private String mCallingPackage  = "test.package";
     private AtomicFile mMappingFile;
@@ -74,7 +82,8 @@
     private String mBugreportFile2 = "bugreport-file2.zip";
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mMappingFile = new AtomicFile(mContext.getFilesDir(), "bugreport-mapping.xml");
         ArraySet<String> mAllowlistedPackages = new ArraySet<>();
@@ -83,6 +92,7 @@
                 new BugreportManagerServiceImpl.Injector(mContext, mAllowlistedPackages,
                         mMappingFile));
         mBugreportFileManager = new BugreportManagerServiceImpl.BugreportFileManager(mMappingFile);
+        when(mPackageManager.getPackageUidAsUser(anyString(), anyInt())).thenReturn(mCallingUid);
     }
 
     @After
@@ -115,12 +125,13 @@
 
         assertThrows(IllegalArgumentException.class, () ->
                 mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                        mContext, callingInfo, Process.myUserHandle().getIdentifier(),
-                        "unknown-file.zip", /* forceUpdateMapping= */ true));
+                        mContext, mPackageManager,  callingInfo,
+                        Process.myUserHandle().getIdentifier(), "unknown-file.zip",
+                        /* forceUpdateMapping= */ true));
 
         // No exception should be thrown.
         mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                mContext, callingInfo, mContext.getUserId(), mBugreportFile,
+                mContext, mPackageManager, callingInfo, mContext.getUserId(), mBugreportFile,
                 /* forceUpdateMapping= */ true);
     }
 
@@ -132,7 +143,7 @@
                 callingInfo, mBugreportFile, /* keepOnRetrieval= */ true);
 
         mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                mContext, callingInfo, mContext.getUserId(), mBugreportFile,
+                mContext, mPackageManager, callingInfo, mContext.getUserId(), mBugreportFile,
                 /* forceUpdateMapping= */ true);
 
         assertThat(mBugreportFileManager.mBugreportFilesToPersist).containsExactly(mBugreportFile);
@@ -148,10 +159,10 @@
 
         // No exception should be thrown.
         mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                mContext, callingInfo, mContext.getUserId(), mBugreportFile,
+                mContext, mPackageManager, callingInfo, mContext.getUserId(), mBugreportFile,
                 /* forceUpdateMapping= */ true);
         mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                mContext, callingInfo, mContext.getUserId(), mBugreportFile2,
+                mContext, mPackageManager, callingInfo, mContext.getUserId(), mBugreportFile2,
                 /* forceUpdateMapping= */ true);
     }
 
@@ -160,8 +171,9 @@
         Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
         assertThrows(IllegalArgumentException.class,
                 () -> mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                        mContext, callingInfo, Process.myUserHandle().getIdentifier(),
-                        "test-file.zip", /* forceUpdateMapping= */ true));
+                        mContext, mPackageManager, callingInfo,
+                        Process.myUserHandle().getIdentifier(), "test-file.zip",
+                        /* forceUpdateMapping= */ true));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 0805485..81df597 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -157,6 +157,7 @@
                     return mMockDevicePolicyManager;
                 case Context.APP_SEARCH_SERVICE:
                 case Context.ROLE_SERVICE:
+                case Context.APP_OPS_SERVICE:
                     // RoleManager is final and cannot be mocked, so we only override the inject
                     // accessor methods in ShortcutService.
                     return getTestContext().getSystemService(name);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index d7ed7c2..8d8dc9c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -23,6 +23,7 @@
 import android.content.pm.UserProperties;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.Xml;
 
 import androidx.test.filters.MediumTest;
@@ -31,6 +32,7 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -52,10 +54,13 @@
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class UserManagerServiceUserPropertiesTest {
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     /** Test that UserProperties can properly read the xml information that it writes. */
     @Test
     public void testWriteReadXml() throws Exception {
+        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
         final UserProperties defaultProps = new UserProperties.Builder()
                 .setShowInLauncher(21)
                 .setStartWithParent(false)
@@ -73,6 +78,7 @@
                 .setDeleteAppWithParent(false)
                 .setAlwaysVisible(false)
                 .setCrossProfileContentSharingStrategy(0)
+                .setProfileApiVisibility(34)
                 .build();
         final UserProperties actualProps = new UserProperties(defaultProps);
         actualProps.setShowInLauncher(14);
@@ -90,6 +96,7 @@
         actualProps.setDeleteAppWithParent(true);
         actualProps.setAlwaysVisible(true);
         actualProps.setCrossProfileContentSharingStrategy(1);
+        actualProps.setProfileApiVisibility(36);
 
         // Write the properties to xml.
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -114,6 +121,7 @@
     /** Tests parcelling an object in which all properties are present. */
     @Test
     public void testParcelUnparcel() throws Exception {
+        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
         final UserProperties originalProps = new UserProperties.Builder()
                 .setShowInLauncher(2145)
                 .build();
@@ -124,6 +132,7 @@
     /** Tests copying a UserProperties object varying permissions. */
     @Test
     public void testCopyLacksPermissions() throws Exception {
+        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
         final UserProperties defaultProps = new UserProperties.Builder()
                 .setShowInLauncher(2145)
                 .setStartWithParent(true)
@@ -134,6 +143,7 @@
                 .setAuthAlwaysRequiredToDisableQuietMode(false)
                 .setAllowStoppingUserWithDelayedLocking(false)
                 .setAlwaysVisible(true)
+                .setProfileApiVisibility(110)
                 .build();
         final UserProperties orig = new UserProperties(defaultProps);
         orig.setShowInLauncher(2841);
@@ -209,6 +219,8 @@
                 copy::isCredentialShareableWithParent, true);
         assertEqualGetterOrThrows(orig::getCrossProfileContentSharingStrategy,
                 copy::getCrossProfileContentSharingStrategy, true);
+        assertEqualGetterOrThrows(orig::getProfileApiVisibility, copy::getProfileApiVisibility,
+                true);
     }
 
     /**
@@ -270,5 +282,6 @@
         assertThat(expected.getAlwaysVisible()).isEqualTo(actual.getAlwaysVisible());
         assertThat(expected.getCrossProfileContentSharingStrategy())
                 .isEqualTo(actual.getCrossProfileContentSharingStrategy());
+        assertThat(expected.getProfileApiVisibility()).isEqualTo(actual.getProfileApiVisibility());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 7083706..1ee604e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -41,6 +41,7 @@
 import android.os.Bundle;
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.ArrayMap;
 
 import androidx.test.InstrumentationRegistry;
@@ -50,6 +51,7 @@
 import com.android.frameworks.servicestests.R;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -71,9 +73,11 @@
     public void setup() {
         mResources = InstrumentationRegistry.getTargetContext().getResources();
     }
-
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
     @Test
     public void testUserTypeBuilder_createUserType() {
+        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
         final Bundle restrictions = makeRestrictionsBundle("r1", "r2");
         final Bundle systemSettings = makeSettingsBundle("s1", "s2");
         final Bundle secureSettings = makeSettingsBundle("secure_s1", "secure_s2");
@@ -97,7 +101,8 @@
                 .setInheritDevicePolicy(340)
                 .setDeleteAppWithParent(true)
                 .setAlwaysVisible(true)
-                .setCrossProfileContentSharingStrategy(1);
+                .setCrossProfileContentSharingStrategy(1)
+                .setProfileApiVisibility(34);
 
         final UserTypeDetails type = new UserTypeDetails.Builder()
                 .setName("a.name")
@@ -180,6 +185,7 @@
         assertTrue(type.getDefaultUserPropertiesReference().getAlwaysVisible());
         assertEquals(1, type.getDefaultUserPropertiesReference()
                 .getCrossProfileContentSharingStrategy());
+        assertEquals(34, type.getDefaultUserPropertiesReference().getProfileApiVisibility());
 
         assertEquals(23, type.getBadgeLabel(0));
         assertEquals(24, type.getBadgeLabel(1));
@@ -199,6 +205,7 @@
 
     @Test
     public void testUserTypeBuilder_defaults() {
+        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
         UserTypeDetails type = new UserTypeDetails.Builder()
                 .setName("name") // Required (no default allowed)
                 .setBaseType(FLAG_FULL) // Required (no default allowed)
@@ -238,6 +245,8 @@
                 props.getShowInQuietMode());
         assertEquals(UserProperties.CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION,
                 props.getCrossProfileContentSharingStrategy());
+        assertEquals(UserProperties.PROFILE_API_VISIBILITY_VISIBLE,
+                props.getProfileApiVisibility());
 
         assertFalse(type.hasBadge());
     }
@@ -310,6 +319,7 @@
     /** Tests {@link UserTypeFactory#customizeBuilders} for a reasonable xml file. */
     @Test
     public void testUserTypeFactoryCustomize_profile() throws Exception {
+        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
         final String userTypeAosp1 = "android.test.1"; // Profile user that is not customized
         final String userTypeAosp2 = "android.test.2"; // Profile user that is customized
         final String userTypeOem1 = "custom.test.1"; // Custom-defined profile
@@ -332,7 +342,8 @@
                 .setShowInQuietMode(24)
                 .setDeleteAppWithParent(true)
                 .setAlwaysVisible(false)
-                .setCrossProfileContentSharingStrategy(1);
+                .setCrossProfileContentSharingStrategy(1)
+                .setProfileApiVisibility(36);
 
         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
         builders.put(userTypeAosp1, new UserTypeDetails.Builder()
@@ -383,6 +394,7 @@
         assertFalse(aospType.getDefaultUserPropertiesReference().getAlwaysVisible());
         assertEquals(1, aospType.getDefaultUserPropertiesReference()
                 .getCrossProfileContentSharingStrategy());
+        assertEquals(36, aospType.getDefaultUserPropertiesReference().getProfileApiVisibility());
 
         // userTypeAosp2 should be modified.
         aospType = builders.get(userTypeAosp2).createUserTypeDetails();
@@ -439,6 +451,7 @@
         assertTrue(aospType.getDefaultUserPropertiesReference().getAlwaysVisible());
         assertEquals(0, aospType.getDefaultUserPropertiesReference()
                 .getCrossProfileContentSharingStrategy());
+        assertEquals(36, aospType.getDefaultUserPropertiesReference().getProfileApiVisibility());
 
         // userTypeOem1 should be created.
         UserTypeDetails.Builder customType = builders.get(userTypeOem1);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index a743fff..db561c4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 import static org.testng.Assert.assertEquals;
@@ -33,10 +34,12 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.platform.test.annotations.Postsubmit;
 import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -53,6 +56,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -95,6 +99,8 @@
     private UserSwitchWaiter mUserSwitchWaiter;
     private UserRemovalWaiter mUserRemovalWaiter;
     private int mOriginalCurrentUserId;
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Before
     public void setUp() throws Exception {
@@ -166,6 +172,7 @@
 
     @Test
     public void testCloneUser() throws Exception {
+        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
         assumeCloneEnabled();
         UserHandle mainUser = mUserManager.getMainUser();
         assumeTrue("Main user is null", mainUser != null);
@@ -222,6 +229,7 @@
                 .isEqualTo(cloneUserProperties.getCrossProfileContentSharingStrategy());
         assertThrows(SecurityException.class, cloneUserProperties::getDeleteAppWithParent);
         assertThrows(SecurityException.class, cloneUserProperties::getAlwaysVisible);
+        assertThrows(SecurityException.class, cloneUserProperties::getProfileApiVisibility);
         compareDrawables(mUserManager.getUserBadge(),
                 Resources.getSystem().getDrawable(userTypeDetails.getBadgePlain()));
 
@@ -303,6 +311,7 @@
 
     @Test
     public void testPrivateProfile() throws Exception {
+        mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
         UserHandle mainUser = mUserManager.getMainUser();
         assumeTrue("Main user is null", mainUser != null);
         // Get the default properties for private profile user type.
@@ -344,7 +353,8 @@
         assertThrows(SecurityException.class, privateProfileUserProperties::getDeleteAppWithParent);
         assertThrows(SecurityException.class,
                 privateProfileUserProperties::getAllowStoppingUserWithDelayedLocking);
-
+        assertThrows(SecurityException.class,
+                privateProfileUserProperties::getProfileApiVisibility);
         compareDrawables(mUserManager.getUserBadge(),
                 Resources.getSystem().getDrawable(userTypeDetails.getBadgePlain()));
 
@@ -1632,6 +1642,106 @@
         assertThat(mainUserCount).isEqualTo(1);
     }
 
+    @Test
+    public void testAddUserAccountData_validStringValuesAreSaved_validBundleIsSaved() {
+        assumeManagedUsersSupported();
+
+        String userName = "User";
+        String accountName = "accountName";
+        String accountType = "accountType";
+        String arrayKey = "StringArrayKey";
+        String stringKey = "StringKey";
+        String intKey = "IntKey";
+        String nestedBundleKey = "PersistableBundleKey";
+        String value1 = "Value 1";
+        String value2 = "Value 2";
+        String value3 = "Value 3";
+
+        UserInfo userInfo = mUserManager.createUser(userName,
+                UserManager.USER_TYPE_FULL_SECONDARY, 0);
+
+        PersistableBundle accountOptions = new PersistableBundle();
+        String[] stringArray = {value1, value2};
+        accountOptions.putInt(intKey, 1234);
+        PersistableBundle nested = new PersistableBundle();
+        nested.putString(stringKey, value3);
+        accountOptions.putPersistableBundle(nestedBundleKey, nested);
+        accountOptions.putStringArray(arrayKey, stringArray);
+
+        mUserManager.clearSeedAccountData();
+        mUserManager.setSeedAccountData(mContext.getUserId(), accountName,
+                accountType, accountOptions);
+
+        //assert userName accountName and accountType were saved correctly
+        assertTrue(mUserManager.getUserInfo(userInfo.id).name.equals(userName));
+        assertTrue(mUserManager.getSeedAccountName().equals(accountName));
+        assertTrue(mUserManager.getSeedAccountType().equals(accountType));
+
+        //assert bundle with correct values was added
+        assertThat(mUserManager.getSeedAccountOptions().containsKey(arrayKey)).isTrue();
+        assertThat(mUserManager.getSeedAccountOptions().getPersistableBundle(nestedBundleKey)
+                .getString(stringKey)).isEqualTo(value3);
+        assertThat(mUserManager.getSeedAccountOptions().getStringArray(arrayKey)[0])
+                .isEqualTo(value1);
+
+        mUserManager.removeUser(userInfo.id);
+    }
+
+    @Test
+    public void testAddUserAccountData_invalidStringValuesAreTruncated_invalidBundleIsDropped() {
+        assumeManagedUsersSupported();
+
+        String tooLongString = generateLongString();
+        String userName = "User " + tooLongString;
+        String accountType = "Account Type " + tooLongString;
+        String accountName = "accountName " + tooLongString;
+        String arrayKey = "StringArrayKey";
+        String stringKey = "StringKey";
+        String intKey = "IntKey";
+        String nestedBundleKey = "PersistableBundleKey";
+        String value1 = "Value 1";
+        String value2 = "Value 2";
+
+        UserInfo userInfo = mUserManager.createUser(userName,
+                UserManager.USER_TYPE_FULL_SECONDARY, 0);
+
+        PersistableBundle accountOptions = new PersistableBundle();
+        String[] stringArray = {value1, value2};
+        accountOptions.putInt(intKey, 1234);
+        PersistableBundle nested = new PersistableBundle();
+        nested.putString(stringKey, tooLongString);
+        accountOptions.putPersistableBundle(nestedBundleKey, nested);
+        accountOptions.putStringArray(arrayKey, stringArray);
+        mUserManager.clearSeedAccountData();
+        mUserManager.setSeedAccountData(mContext.getUserId(), accountName,
+                accountType, accountOptions);
+
+        //assert userName was truncated
+        assertTrue(mUserManager.getUserInfo(userInfo.id).name.length()
+                == UserManager.MAX_USER_NAME_LENGTH);
+
+        //assert accountName and accountType got truncated
+        assertTrue(mUserManager.getSeedAccountName().length()
+                == UserManager.MAX_ACCOUNT_STRING_LENGTH);
+        assertTrue(mUserManager.getSeedAccountType().length()
+                == UserManager.MAX_ACCOUNT_STRING_LENGTH);
+
+        //assert bundle with invalid values was dropped
+        assertThat(mUserManager.getSeedAccountOptions() == null).isTrue();
+
+        mUserManager.removeUser(userInfo.id);
+    }
+
+    private String generateLongString() {
+        String partialString = "Test Name Test Name Test Name Test Name Test Name Test Name Test "
+                + "Name Test Name Test Name Test Name "; //String of length 100
+        StringBuilder resultString = new StringBuilder();
+        for (int i = 0; i < 600; i++) {
+            resultString.append(partialString);
+        }
+        return resultString.toString();
+    }
+
     private boolean isPackageInstalledForUser(String packageName, int userId) {
         try {
             return mPackageManager.getPackageInfoAsUser(packageName, 0, userId) != null;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
index 757abde..e3ee21a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
@@ -436,6 +436,13 @@
         validateTagCount("action", 20000, tag)
         validateTagCount("category", 40000, tag)
         validateTagCount("data", 40000, tag)
+        validateTagCount("uri-relative-filter-group", 100, tag)
+    }
+
+    @Test
+    fun parseUriRelativeFilterGroupTag() {
+        val tag = "uri-relative-filter-group"
+        validateTagCount("data", 100, tag)
     }
 
     @Test
@@ -465,6 +472,54 @@
             R.styleable.AndroidManifestData_pathAdvancedPattern,
             4000
         )
+        validateTagAttr(tag, "query", R.styleable.AndroidManifestData_query, 4000)
+        validateTagAttr(
+            tag,
+            "queryPattern",
+            R.styleable.AndroidManifestData_queryPattern,
+            4000
+        )
+        validateTagAttr(
+            tag,
+            "queryPrefix",
+            R.styleable.AndroidManifestData_queryPrefix,
+            4000
+        )
+        validateTagAttr(tag,
+            "querySuffix",
+            R.styleable.AndroidManifestData_querySuffix,
+            4000
+        )
+        validateTagAttr(
+            tag,
+            "queryAdvancedPattern",
+            R.styleable.AndroidManifestData_queryAdvancedPattern,
+            4000
+        )
+        validateTagAttr(tag, "fragment", R.styleable.AndroidManifestData_query, 4000)
+        validateTagAttr(
+            tag,
+            "fragmentPattern",
+            R.styleable.AndroidManifestData_fragmentPattern,
+            4000
+        )
+        validateTagAttr(
+            tag,
+            "fragmentPrefix",
+            R.styleable.AndroidManifestData_fragmentPrefix,
+            4000
+        )
+        validateTagAttr(tag,
+            "fragmentSuffix",
+            R.styleable.AndroidManifestData_fragmentSuffix,
+            4000
+        )
+        validateTagAttr(
+            tag,
+            "fragmentAdvancedPattern",
+            R.styleable.AndroidManifestData_fragmentAdvancedPattern,
+            4000
+        )
         validateTagAttr(tag, "mimeType", R.styleable.AndroidManifestData_mimeType, 255)
         validateTagAttr(tag, "mimeGroup", R.styleable.AndroidManifestData_mimeGroup, 1024)
     }
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
index 3e78f9a..131b380 100644
--- a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
+++ b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
@@ -102,3 +102,17 @@
     resource_dirs: ["res"],
     manifest: "AndroidManifestApp6.xml",
 }
+
+android_test_helper_app {
+    name: "PackageParserTestApp7",
+    sdk_version: "current",
+    srcs: ["**/*.java"],
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    resource_dirs: ["res"],
+    manifest: "AndroidManifestApp7.xml",
+}
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp7.xml b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp7.xml
new file mode 100644
index 0000000..cb87a48
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp7.xml
@@ -0,0 +1,67 @@
+<?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.servicestests.apps.packageparserapp" >
+
+    <application>
+        <activity android:name=".TestActivity"
+                  android:exported="true" >
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="http"
+                    android:host="www.example.com" />
+                <uri-relative-filter-group android:allow="false">
+                    <data android:pathPrefix="/gizmos" />
+                    <data android:queryPattern=".*query=string.*" />
+                    <data android:fragment="fragment" />
+                </uri-relative-filter-group>
+                <uri-relative-filter-group>
+                    <data android:query="query=string" />
+                    <data android:fragmentSuffix="fragment" />
+                </uri-relative-filter-group>
+                <uri-relative-filter-group>
+                    <data android:path="/gizmos" />
+                    <data android:query=".*query=string.*" />
+                    <data android:fragment="fragment" />
+                </uri-relative-filter-group>
+                <uri-relative-filter-group>
+                    <data android:pathPrefix="/gizmos" />
+                    <data android:queryPrefix=".*query=string.*" />
+                    <data android:fragmentPrefix="fragment" />
+                </uri-relative-filter-group>
+                <uri-relative-filter-group>
+                    <data android:pathPattern="/gizmos" />
+                    <data android:queryPattern=".*query=string.*" />
+                    <data android:fragmentPattern="fragment" />
+                </uri-relative-filter-group>
+                <uri-relative-filter-group>
+                    <data android:pathAdvancedPattern="/gizmos" />
+                    <data android:queryAdvancedPattern=".*query=string.*" />
+                    <data android:fragmentAdvancedPattern="fragment" />
+                </uri-relative-filter-group>
+                <uri-relative-filter-group>
+                    <data android:pathSuffix="/gizmos" />
+                    <data android:querySuffix=".*query=string.*" />
+                    <data android:fragmentSuffix="fragment" />
+                </uri-relative-filter-group>
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
index 0e20daf..99d5a6d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
@@ -143,12 +143,13 @@
                 Policy.policyState(false, true), 0);
 
         ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
-        assertThat(zenPolicy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
+        assertThat(zenPolicy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_ALLOW);
 
         Policy notAllowed = new Policy(0, 0, 0, 0,
                 Policy.policyState(false, false), 0);
         ZenPolicy zenPolicyNotAllowed = notificationPolicyToZenPolicy(notAllowed);
-        assertThat(zenPolicyNotAllowed.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+        assertThat(zenPolicyNotAllowed.getPriorityChannelsAllowed()).isEqualTo(
+                ZenPolicy.STATE_DISALLOW);
     }
 
     @Test
@@ -158,11 +159,12 @@
                 Policy.policyState(false, true), 0);
 
         ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
-        assertThat(zenPolicy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_UNSET);
+        assertThat(zenPolicy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_UNSET);
 
         Policy notAllowed = new Policy(0, 0, 0, 0,
                 Policy.policyState(false, false), 0);
         ZenPolicy zenPolicyNotAllowed = notificationPolicyToZenPolicy(notAllowed);
-        assertThat(zenPolicyNotAllowed.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_UNSET);
+        assertThat(zenPolicyNotAllowed.getPriorityChannelsAllowed()).isEqualTo(
+                ZenPolicy.STATE_UNSET);
     }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index e523e79f..539bb37 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -284,7 +284,7 @@
                 actual.getPriorityConversationSenders());
         assertEquals(expected.getPriorityCallSenders(), actual.getPriorityCallSenders());
         assertEquals(expected.getPriorityMessageSenders(), actual.getPriorityMessageSenders());
-        assertEquals(expected.getPriorityChannels(), actual.getPriorityChannels());
+        assertEquals(expected.getPriorityChannelsAllowed(), actual.getPriorityChannelsAllowed());
     }
 
     @Test
@@ -716,7 +716,7 @@
         assertEquals(policy.getPriorityCategorySystem(), fromXml.getPriorityCategorySystem());
         assertEquals(policy.getPriorityCategoryReminders(), fromXml.getPriorityCategoryReminders());
         assertEquals(policy.getPriorityCategoryEvents(), fromXml.getPriorityCategoryEvents());
-        assertEquals(policy.getPriorityChannels(), fromXml.getPriorityChannels());
+        assertEquals(policy.getPriorityChannelsAllowed(), fromXml.getPriorityChannelsAllowed());
 
         assertEquals(policy.getVisualEffectFullScreenIntent(),
                 fromXml.getVisualEffectFullScreenIntent());
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 25ad7db..87e822c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -4075,7 +4075,8 @@
 
         // UPDATE_ORIGIN_USER should change the bitmask and change the values.
         assertThat(rule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY);
-        assertThat(rule.getZenPolicy().getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+        assertThat(rule.getZenPolicy().getPriorityChannelsAllowed()).isEqualTo(
+                ZenPolicy.STATE_DISALLOW);
 
         assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue();
 
@@ -4339,7 +4340,8 @@
 
         // New ZenPolicy differs from the default config
         assertThat(rule.getZenPolicy()).isNotNull();
-        assertThat(rule.getZenPolicy().getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+        assertThat(rule.getZenPolicy().getPriorityChannelsAllowed()).isEqualTo(
+                ZenPolicy.STATE_DISALLOW);
 
         ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
         assertThat(storedRule.canBeUpdatedByApp()).isFalse();
@@ -4760,6 +4762,7 @@
                 .setShouldDimWallpaper(true)
                 .setShouldUseNightMode(true)
                 .build();
+        user1Rule.zenPolicy = new ZenPolicy();
         verifyNoMoreInteractions(mDeviceEffectsApplier);
 
         mZenModeHelper.onUserSwitched(1);
@@ -5040,6 +5043,109 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_MODES_API)
+    public void removeAndAddAutomaticZenRule_wasActive_isRestoredAsInactive() {
+        // Start with a rule.
+        mZenModeHelper.mConfig.automaticRules.clear();
+        AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+                .setConditionId(CONDITION_ID)
+                .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+                .build();
+        String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+                UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+
+        // User customizes it.
+        AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule)
+                .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
+                .build();
+        mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate",
+                Process.SYSTEM_UID);
+        assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+
+        // App activates it.
+        mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_TRUE, UPDATE_ORIGIN_APP,
+                CUSTOM_PKG_UID);
+        assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS);
+
+        // App deletes it.
+        mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it",
+                CUSTOM_PKG_UID);
+        assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0);
+        assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(1);
+        assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+
+        // App adds it again.
+        String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+                UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID);
+
+        // The rule is restored...
+        assertThat(newRuleId).isEqualTo(ruleId);
+        AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId);
+        assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS);
+
+        // ... but it is NOT active
+        ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(newRuleId);
+        assertThat(storedRule.isAutomaticActive()).isFalse();
+        assertThat(storedRule.isTrueOrUnknown()).isFalse();
+        assertThat(storedRule.condition).isNull();
+        assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_API)
+    public void removeAndAddAutomaticZenRule_wasSnoozed_isRestoredAsInactive() {
+        // Start with a rule.
+        mZenModeHelper.mConfig.automaticRules.clear();
+        AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+                .setConditionId(CONDITION_ID)
+                .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+                .build();
+        String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+                UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+
+        // User customizes it.
+        AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule)
+                .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
+                .build();
+        mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate",
+                Process.SYSTEM_UID);
+        assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+
+        // App activates it.
+        mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_TRUE, UPDATE_ORIGIN_APP,
+                CUSTOM_PKG_UID);
+        assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS);
+
+        // User snoozes it.
+        mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI,
+                "snoozing", "systemui", Process.SYSTEM_UID);
+        assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+
+        // App deletes it.
+        mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it",
+                CUSTOM_PKG_UID);
+        assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0);
+        assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(1);
+
+        // App adds it again.
+        String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+                UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID);
+
+        // The rule is restored...
+        assertThat(newRuleId).isEqualTo(ruleId);
+        AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId);
+        assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS);
+
+        // ... but it is NEITHER active NOR snoozed.
+        ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(newRuleId);
+        assertThat(storedRule.isAutomaticActive()).isFalse();
+        assertThat(storedRule.isTrueOrUnknown()).isFalse();
+        assertThat(storedRule.condition).isNull();
+        assertThat(storedRule.snoozing).isFalse();
+        assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+    }
+
+    @Test
     public void testRuleCleanup() throws Exception {
         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
         Instant now = Instant.ofEpochMilli(1701796461000L);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
index 57e1132..3a88294 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -218,7 +218,7 @@
 
         // unset applied, channels setting keeps its state
         channelsPriority.apply(unset);
-        assertThat(channelsPriority.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
+        assertThat(channelsPriority.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_ALLOW);
     }
 
     @Test
@@ -234,7 +234,7 @@
 
         // priority channels (less strict state) cannot override a setting that sets it to none
         none.apply(priority);
-        assertThat(none.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+        assertThat(none.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_DISALLOW);
     }
 
     @Test
@@ -250,7 +250,7 @@
 
         // applying a policy with channelType=none overrides priority setting
         priority.apply(none);
-        assertThat(priority.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+        assertThat(priority.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_DISALLOW);
     }
 
     @Test
@@ -265,7 +265,7 @@
 
         // applying a policy with a set channel type actually goes through
         unset.apply(priority);
-        assertThat(unset.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
+        assertThat(unset.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_ALLOW);
     }
 
     @Test
@@ -379,7 +379,7 @@
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
 
         ZenPolicy policy = builder.build();
-        assertThat(policy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_UNSET);
+        assertThat(policy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_UNSET);
     }
 
     @Test
@@ -696,7 +696,7 @@
         builder.allowPriorityChannels(true);
         ZenPolicy policy = builder.build();
 
-        assertThat(policy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_UNSET);
+        assertThat(policy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_UNSET);
         assertThat(policy.toString().contains("allowChannels")).isFalse();
     }
 
@@ -708,12 +708,12 @@
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
         builder.allowPriorityChannels(true);
         ZenPolicy policy = builder.build();
-        assertThat(policy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
+        assertThat(policy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_ALLOW);
 
         // disallow priority channels
         builder.allowPriorityChannels(false);
         policy = builder.build();
-        assertThat(policy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+        assertThat(policy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_DISALLOW);
     }
 
     @Test
@@ -734,7 +734,7 @@
         assertThat(newPolicy.getVisualEffectBadge()).isEqualTo(ZenPolicy.STATE_DISALLOW);
         assertThat(newPolicy.getVisualEffectPeek()).isEqualTo(ZenPolicy.STATE_UNSET);
 
-        assertThat(newPolicy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
+        assertThat(newPolicy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_ALLOW);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 7c2f7ee..c8abd8d 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -166,6 +166,7 @@
 
     @Mock
     private PhoneWindowManager.ButtonOverridePermissionChecker mButtonOverridePermissionChecker;
+    @Mock private WindowWakeUpPolicy mWindowWakeUpPolicy;
 
     @Mock private IBinder mInputToken;
     @Mock private IBinder mImeTargetWindowToken;
@@ -230,6 +231,10 @@
         TalkbackShortcutController getTalkbackShortcutController() {
             return new TestTalkbackShortcutController(mContext);
         }
+
+        WindowWakeUpPolicy getWindowWakeUpPolicy() {
+            return mWindowWakeUpPolicy;
+        }
     }
 
     TestPhoneWindowManager(Context context, boolean supportSettingsUpdate) {
@@ -620,7 +625,8 @@
 
     void assertPowerWakeUp() {
         mTestLooper.dispatchAll();
-        verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
+        verify(mWindowWakeUpPolicy)
+                .wakeUpFromKey(anyLong(), eq(KeyEvent.KEYCODE_POWER), anyBoolean());
     }
 
     void assertNoPowerSleep() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index 6e5baee..37e0818 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -46,6 +46,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.platform.test.annotations.Presubmit;
 import android.util.Log;
 import android.util.Rational;
@@ -63,6 +64,7 @@
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Build/Install/Run:
@@ -119,6 +121,29 @@
     }
 
     @Test
+    public void testAbortListenerCalled() {
+        AtomicBoolean callbackCalled = new AtomicBoolean(false);
+
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setOnAnimationAbortListener(new IRemoteCallback.Stub() {
+            @Override
+            public void sendResult(Bundle data) {
+                callbackCalled.set(true);
+            }
+        });
+
+        // Verify that the callback is called on abort
+        options.abort();
+        assertTrue(callbackCalled.get());
+
+        // Verify that the callback survives saving to bundle
+        ActivityOptions optionsCopy = ActivityOptions.fromBundle(options.toBundle());
+        callbackCalled.set(false);
+        optionsCopy.abort();
+        assertTrue(callbackCalled.get());
+    }
+
+    @Test
     public void testTransferLaunchCookie() {
         final Binder cookie = new Binder();
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -279,7 +304,9 @@
                 case "android.activity.pendingIntentCreatorBackgroundActivityStartMode":
                     // KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE
                 case "android.activity.launchCookie": // KEY_LAUNCH_COOKIE
+                case "android:activity.animAbortListener": // KEY_ANIM_ABORT_LISTENER
                     // Existing keys
+
                     break;
                 default:
                     unknownKeys.add(key);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 9e00f92..5d14334 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -417,6 +417,8 @@
                     di.logicalWidth, di.logicalHeight).mConfigInsets.top);
         }
 
+        // Flush the pending change (DecorInsets.Info#mNeedUpdate) for the rotation to be tested.
+        displayPolicy.getDecorInsetsInfo(Surface.ROTATION_90, di.logicalHeight, di.logicalWidth);
         // Add a window that provides the same insets in current rotation. But it specifies
         // different insets in other rotations.
         final WindowState bar2 = createWindow(null, navbar.mAttrs.type, "bar2");
@@ -446,6 +448,12 @@
         // The insets in other rotations should be still updated.
         assertEquals(doubleHeightFor90, displayPolicy.getDecorInsetsInfo(Surface.ROTATION_90,
                 di.logicalHeight, di.logicalWidth).mConfigInsets.bottom);
+        // Restore to previous height and the insets can still be updated.
+        bar2.mAttrs.paramsForRotation[Surface.ROTATION_90].providedInsets[0].setInsetsSize(
+                Insets.of(0, 0, 0, NAV_BAR_HEIGHT));
+        assertFalse(displayPolicy.updateDecorInsetsInfo());
+        assertEquals(NAV_BAR_HEIGHT, displayPolicy.getDecorInsetsInfo(Surface.ROTATION_90,
+                di.logicalHeight, di.logicalWidth).mConfigInsets.bottom);
 
         navbar.removeIfPossible();
         bar2.removeIfPossible();
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 3b4b220..9930c88 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+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_PINNED;
@@ -1207,6 +1208,29 @@
     }
 
     @Test
+    public void addTask_tasksAreAddedAccordingToZOrder() {
+        final Task firstTask = new TaskBuilder(mSupervisor).setTaskId(1)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+        final Task secondTask = new TaskBuilder(mSupervisor).setTaskId(2)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+
+        assertEquals(-1, firstTask.compareTo(secondTask));
+
+        // initial addition when tasks are created
+        mRecentTasks.add(firstTask);
+        mRecentTasks.add(secondTask);
+
+        assertRecentTasksOrder(secondTask, firstTask);
+
+        // Tasks are added in a different order
+        mRecentTasks.add(secondTask);
+        mRecentTasks.add(firstTask);
+
+        // order in recents don't change as first task has lower z-order
+        assertRecentTasksOrder(secondTask, firstTask);
+    }
+
+    @Test
     public void removeTask_callsTaskNotificationController() {
         final Task task = createTaskBuilder(".Task").build();
 
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 752dc5e..0c1a9c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -886,8 +886,6 @@
 
         spyOn(mActivity.mLetterboxUiController);
         doReturn(true).when(mActivity.mLetterboxUiController)
-                .isSurfaceReadyToShow(any());
-        doReturn(true).when(mActivity.mLetterboxUiController)
                 .isSurfaceVisible(any());
 
         assertTrue(mActivity.mLetterboxUiController.shouldShowLetterboxUi(
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 245b2c5..98ca094 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE;
+import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -24,11 +26,14 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 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.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -65,12 +70,14 @@
 import androidx.test.filters.MediumTest;
 
 import com.android.server.pm.pkg.AndroidPackage;
+import com.android.window.flags.Flags;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
 
 import java.util.Collections;
 import java.util.Set;
@@ -592,6 +599,70 @@
     }
 
     @Test
+    public void testIsAllowedToBeEmbeddedInTrustedMode_withManageActivityTasksPermission() {
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setCreateParentTask()
+                .createActivityCount(1)
+                .build();
+        final ActivityRecord activity = taskFragment.getTopMostActivity();
+
+        // Not allow embedding activity if not a trusted host.
+        assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
+                taskFragment.isAllowedToEmbedActivity(activity));
+
+        MockitoSession session =
+                mockitoSession().spyStatic(ActivityTaskManagerService.class).startMocking();
+        try {
+            doReturn(PERMISSION_GRANTED).when(() -> {
+                return ActivityTaskManagerService.checkPermission(
+                        eq(MANAGE_ACTIVITY_TASKS), anyInt(), anyInt());
+            });
+            // With the MANAGE_ACTIVITY_TASKS permission, trusted embedding is always allowed.
+            assertTrue(taskFragment.isAllowedToBeEmbeddedInTrustedMode());
+        } finally {
+            session.finishMocking();
+        }
+    }
+
+    @Test
+    public void testIsAllowedToEmbedActivityInUntrustedMode_withUntrustedEmbeddingAnyAppPermission(
+    ) {
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setCreateParentTask()
+                .createActivityCount(1)
+                .build();
+        final ActivityRecord activity = taskFragment.getTopMostActivity();
+
+        // Not allow embedding activity if not a trusted host.
+        assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
+                taskFragment.isAllowedToEmbedActivity(activity));
+
+        MockitoSession session =
+                mockitoSession()
+                        .spyStatic(ActivityTaskManagerService.class)
+                        .spyStatic(Flags.class)
+                        .startMocking();
+        try {
+            doReturn(PERMISSION_GRANTED).when(() -> {
+                return ActivityTaskManagerService.checkPermission(
+                        eq(EMBED_ANY_APP_IN_UNTRUSTED_MODE), anyInt(), anyInt());
+            });
+            // With the EMBED_ANY_APP_IN_UNTRUSTED_MODE permission, untrusted embedding is always
+            // allowed, but it doesn't always allow trusted embedding.
+            doReturn(true).when(() -> Flags.untrustedEmbeddingAnyAppPermission());
+            assertTrue(taskFragment.isAllowedToEmbedActivityInUntrustedMode(activity));
+            assertFalse(taskFragment.isAllowedToEmbedActivityInTrustedMode(activity));
+
+            // If the flag is disabled, the permission doesn't have effect.
+            doReturn(false).when(() -> Flags.untrustedEmbeddingAnyAppPermission());
+            assertFalse(taskFragment.isAllowedToEmbedActivityInUntrustedMode(activity));
+            assertFalse(taskFragment.isAllowedToEmbedActivityInTrustedMode(activity));
+        } finally {
+            session.finishMocking();
+        }
+    }
+
+    @Test
     public void testIgnoreRequestedOrientationForActivityEmbeddingSplit() {
         // Setup two activities in ActivityEmbedding split.
         final Task task = createTask(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 07cfbf0..16f963f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -628,6 +628,27 @@
     }
 
     @Test
+    public void testLaunchWindowingModeUpdatesExistingTask() {
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+        ActivityRecord activity = createSourceActivity(freeformDisplay);
+        final Task task = activity.getTask();
+        task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder()
+                        .setTask(task)
+                        .setOptions(options)
+                        .calculate());
+
+        assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode);
+    }
+
+    @Test
     public void testBoundsInOptionsInfersFreeformWithResizeableActivity() {
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchBounds(new Rect(0, 0, 100, 100));
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 51df1d4..7d8eb90 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1602,6 +1602,33 @@
     }
 
     @Test
+    public void testTransientWithParallelLaunch() {
+        final Task recentTask = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask();
+        final ActivityRecord recent = new ActivityBuilder(mAtm).setTask(recentTask)
+                .setVisible(false).build();
+        final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final Task appTask = app.getTask();
+        registerTestTransitionPlayer();
+        final TransitionController controller = mRootWindowContainer.mTransitionController;
+        final Transition transition = createTestTransition(TRANSIT_OPEN, controller);
+        transition.mParallelCollectType = Transition.PARALLEL_TYPE_RECENTS;
+        controller.moveToCollecting(transition);
+        transition.collect(recentTask);
+        transition.collect(appTask);
+        transition.setTransientLaunch(recent, appTask);
+        recentTask.moveToFront("move-recent-to-front");
+        transition.setAllReady();
+        transition.start();
+        // Assume that the app starts another activity in its task.
+        final Transition newTransition = controller.createAndStartCollecting(TRANSIT_OPEN);
+
+        assertEquals(newTransition, controller.getCollectingTransition());
+        assertTrue(controller.mWaitingTransitions.contains(transition));
+        assertTrue(controller.isTransientHide(appTask));
+        assertTrue(controller.isTransientVisible(appTask));
+    }
+
+    @Test
     public void testNotReadyPushPop() {
         final TransitionController controller = new TestTransitionController(mAtm);
         controller.setSyncEngine(mWm.mSyncEngine);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
index d255271..e9ece5d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static org.junit.Assert.assertEquals;
@@ -23,6 +26,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.times;
 
 import android.content.Intent;
 import android.platform.test.annotations.Presubmit;
@@ -35,6 +39,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Test class for {@link WindowContainerTransaction}.
  *
@@ -45,7 +52,6 @@
 @Presubmit
 @RunWith(WindowTestRunner.class)
 public class WindowContainerTransactionTests extends WindowTestsBase {
-
     @Test
     public void testRemoveTask() {
         final Task rootTask = createTask(mDisplayContent);
@@ -72,6 +78,123 @@
         verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask);
     }
 
+    @Test
+    public void testDesktopMode_tasksAreBroughtToFront() {
+        final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+        TaskDisplayArea tda = desktopOrganizer.mDefaultTDA;
+        List<ActivityRecord> activityRecords = new ArrayList<>();
+        int numberOfTasks = 4;
+        desktopOrganizer.createFreeformTasksWithActivities(desktopOrganizer,
+                activityRecords, numberOfTasks);
+
+        final Task task = createTask(mDisplayContent);
+        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
+        task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+        // Bring home to front of the tasks
+        desktopOrganizer.bringHomeToFront();
+
+        // Bring tasks in front of the home
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        desktopOrganizer.bringDesktopTasksToFront(wct);
+        applyTransaction(wct);
+
+        // Verify tasks are resumed and in correct z-order
+        verify(mRootWindowContainer, times(2)).ensureActivitiesVisible();
+        for (int i = 0; i < numberOfTasks - 1; i++) {
+            assertTrue(tda.mChildren
+                    .indexOf(desktopOrganizer.mTasks.get(i).getRootTask())
+                    < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(i + 1).getRootTask()));
+        }
+    }
+
+    @Test
+    public void testDesktopMode_moveTaskToDesktop() {
+        final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+        TaskDisplayArea tda = desktopOrganizer.mDefaultTDA;
+        List<ActivityRecord> activityRecords = new ArrayList<>();
+        int numberOfTasks = 4;
+        desktopOrganizer.createFreeformTasksWithActivities(desktopOrganizer,
+                activityRecords, numberOfTasks);
+
+        final Task task = createTask(mDisplayContent);
+        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
+        task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+        // Bring home to front of the tasks
+        desktopOrganizer.bringHomeToFront();
+
+        // Bring tasks in front of the home and newly moved task to on top of them
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        desktopOrganizer.bringDesktopTasksToFront(wct);
+        desktopOrganizer.addMoveToDesktopChanges(wct, task, true);
+        wct.setBounds(task.getTaskInfo().token, desktopOrganizer.getDefaultDesktopTaskBounds());
+        applyTransaction(wct);
+
+        // Verify tasks are resumed
+        verify(mRootWindowContainer, times(2)).ensureActivitiesVisible();
+
+        // Tasks are in correct z-order
+        for (int i = 0; i < numberOfTasks - 1; i++) {
+            assertTrue(tda.mChildren
+                    .indexOf(desktopOrganizer.mTasks.get(i).getRootTask())
+                    < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(i + 1).getRootTask()));
+        }
+        // New task is on top of other tasks
+        assertTrue(tda.mChildren
+                .indexOf(desktopOrganizer.mTasks.get(3).getRootTask())
+                < tda.mChildren.indexOf(task));
+
+        // New task is in freeform and has specified bounds
+        assertEquals(WINDOWING_MODE_FREEFORM, task.getWindowingMode());
+        assertEquals(desktopOrganizer.getDefaultDesktopTaskBounds(), task.getBounds());
+    }
+
+
+    @Test
+    public void testDesktopMode_moveTaskToFullscreen() {
+        final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+        List<ActivityRecord> activityRecords = new ArrayList<>();
+        int numberOfTasks = 4;
+        desktopOrganizer.createFreeformTasksWithActivities(desktopOrganizer,
+                activityRecords, numberOfTasks);
+
+        Task taskToMove = desktopOrganizer.mTasks.get(numberOfTasks - 1);
+
+        // Bring tasks in front of the home and newly moved task to on top of them
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        desktopOrganizer.addMoveToFullscreen(wct, taskToMove, false);
+        applyTransaction(wct);
+
+        // New task is in freeform
+        assertEquals(WINDOWING_MODE_FULLSCREEN, taskToMove.getWindowingMode());
+    }
+
+    @Test
+    public void testDesktopMode_moveTaskToFront() {
+        final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+        TaskDisplayArea tda = desktopOrganizer.mDefaultTDA;
+        List<ActivityRecord> activityRecords = new ArrayList<>();
+        int numberOfTasks = 5;
+        desktopOrganizer.createFreeformTasksWithActivities(desktopOrganizer,
+                activityRecords, numberOfTasks);
+
+        // Bring task 2 on top of other tasks
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.reorder(desktopOrganizer.mTasks.get(2).getTaskInfo().token, true /* onTop */);
+        applyTransaction(wct);
+
+        // Tasks are in correct z-order
+        assertTrue(tda.mChildren.indexOf(desktopOrganizer.mTasks.get(0).getRootTask())
+                < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(1).getRootTask()));
+        assertTrue(tda.mChildren.indexOf(desktopOrganizer.mTasks.get(1).getRootTask())
+                < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(3).getRootTask()));
+        assertTrue(tda.mChildren.indexOf(desktopOrganizer.mTasks.get(3).getRootTask())
+                < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(4).getRootTask()));
+        assertTrue(tda.mChildren.indexOf(desktopOrganizer.mTasks.get(4).getRootTask())
+                < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(2).getRootTask()));
+    }
+
     private Task createTask(int taskId) {
         return new Task.Builder(mAtm)
                 .setTaskId(taskId)
@@ -87,3 +210,4 @@
         }
     }
 }
+
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 fe9d837..06afa38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -1068,7 +1068,7 @@
             invocationOnMock.callRealMethod();
             return null;
         }).when(surface).lockCanvas(any());
-        mWm.mAccessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId, mTransaction);
+        mWm.mAccessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId);
         waitUntilHandlersIdle();
         try {
             verify(surface).lockCanvas(any());
@@ -1076,14 +1076,9 @@
             clearInvocations(surface);
             // Invalidate and redraw.
             mWm.mAccessibilityController.onDisplaySizeChanged(mDisplayContent);
-            mWm.mAccessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId, mTransaction);
+            mWm.mAccessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId);
             // Turn off magnification to release surface.
             mWm.mAccessibilityController.setMagnificationCallbacks(displayId, null);
-            if (!com.android.window.flags.Flags.drawMagnifierBorderOutsideWmlock()) {
-                verify(surface).release();
-                assertTrue(lockCanvasInWmLock[0]);
-                return;
-            }
             waitUntilHandlersIdle();
             // lockCanvas must not be called after releasing.
             verify(surface, never()).lockCanvas(any());
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 a0bafb6..be83744 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -116,6 +116,7 @@
 import android.window.TaskFragmentOrganizer;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
 
 import com.android.internal.policy.AttributeCache;
 import com.android.internal.util.ArrayUtils;
@@ -1899,12 +1900,14 @@
         final int mDesktopModeDefaultWidthDp = 840;
         final int mDesktopModeDefaultHeightDp = 630;
         final int mDesktopDensity = 284;
+        final int mOverrideDensity = 285;
 
         final ActivityTaskManagerService mService;
         final TaskDisplayArea mDefaultTDA;
         List<Task> mTasks;
         final DisplayContent mDisplay;
         Rect mStableBounds;
+        Task mHomeTask;
 
         TestDesktopOrganizer(ActivityTaskManagerService service, DisplayContent display) {
             mService = service;
@@ -1913,8 +1916,8 @@
             mService.mTaskOrganizerController.registerTaskOrganizer(this);
             mTasks = new ArrayList<>();
             mStableBounds = display.getBounds();
+            mHomeTask =  mDefaultTDA.getRootHomeTask();
         }
-
         TestDesktopOrganizer(ActivityTaskManagerService service) {
             this(service, service.mTaskSupervisor.mRootWindowContainer.getDefaultDisplay());
         }
@@ -1929,8 +1932,10 @@
         }
 
         public Rect getDefaultDesktopTaskBounds() {
-            int width = (int) (mDesktopModeDefaultWidthDp * mDesktopDensity + 0.5f);
-            int height = (int) (mDesktopModeDefaultHeightDp * mDesktopDensity + 0.5f);
+            int width = (int) (mDesktopModeDefaultWidthDp
+                    * (mOverrideDensity / mDesktopDensity) + 0.5f);
+            int height = (int) (mDesktopModeDefaultHeightDp
+                    * (mOverrideDensity / mDesktopDensity) + 0.5f);
             Rect outBounds = new Rect();
 
             outBounds.set(0, 0, width, height);
@@ -1942,8 +1947,69 @@
             return outBounds;
         }
 
+        public void createFreeformTasksWithActivities(TestDesktopOrganizer desktopOrganizer,
+                List<ActivityRecord> activityRecords, int numberOfTasks) {
+            for (int i = 0; i < numberOfTasks; i++) {
+                Rect bounds = new Rect(desktopOrganizer.getDefaultDesktopTaskBounds());
+                bounds.offset(20 * i, 20 * i);
+                desktopOrganizer.createTask(bounds);
+            }
+
+            for (int i = 0; i < numberOfTasks; i++) {
+                activityRecords.add(new TaskBuilder(mService.mTaskSupervisor)
+                        .setParentTask(desktopOrganizer.mTasks.get(i))
+                        .setCreateActivity(true)
+                        .build()
+                        .getTopMostActivity());
+            }
+
+            for (int i = 0; i < numberOfTasks; i++) {
+                activityRecords.get(i).setVisibleRequested(true);
+            }
+
+            for (int i = 0; i < numberOfTasks; i++) {
+                assertEquals(desktopOrganizer.mTasks.get(i), activityRecords.get(i).getRootTask());
+            }
+        }
+
+        public void bringHomeToFront() {
+            WindowContainerTransaction wct = new WindowContainerTransaction();
+            wct.reorder(mHomeTask.getTaskInfo().token, true /* onTop */);
+            applyTransaction(wct);
+        }
+
+        public void bringDesktopTasksToFront(WindowContainerTransaction wct) {
+            for (Task task: mTasks) {
+                wct.reorder(task.getTaskInfo().token, true /* onTop */);
+            }
+        }
+
+        public void addMoveToDesktopChanges(WindowContainerTransaction wct, Task task,
+                boolean overrideDensity) {
+            wct.setWindowingMode(task.getTaskInfo().token, WINDOWING_MODE_FREEFORM);
+            wct.reorder(task.getTaskInfo().token, true /* onTop */);
+            if (overrideDensity) {
+                wct.setDensityDpi(task.getTaskInfo().token, mOverrideDensity);
+            }
+        }
+
+        public void addMoveToFullscreen(WindowContainerTransaction wct, Task task,
+                boolean overrideDensity) {
+            wct.setWindowingMode(task.getTaskInfo().token, WINDOWING_MODE_FULLSCREEN);
+            wct.setBounds(task.getTaskInfo().token, new Rect());
+            if (overrideDensity) {
+                wct.setDensityDpi(task.getTaskInfo().token, mOverrideDensity);
+            }
+        }
+
+        private void applyTransaction(@androidx.annotation.NonNull WindowContainerTransaction wct) {
+            if (!wct.isEmpty()) {
+                mService.mWindowOrganizerController.applyTransaction(wct);
+            }
+        }
     }
 
+
     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
         return createTestWindowToken(type, dc, false /* persistOnEmpty */);
     }
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 63db297..b7706a9 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -1283,6 +1283,17 @@
         sb.append(mExtras);
         sb.append(" GroupId: ");
         sb.append(Log.pii(mGroupId));
+        sb.append(" SC Restrictions: ");
+        if (hasSimultaneousCallingRestriction()) {
+            sb.append("[ ");
+            for (PhoneAccountHandle handle : mSimultaneousCallingRestriction) {
+                sb.append(handle);
+                sb.append(" ");
+            }
+            sb.append("]");
+        } else {
+            sb.append("[NONE]");
+        }
         sb.append("]");
         return sb.toString();
     }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e81f482..2c6e1e4 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1360,7 +1360,7 @@
     /**
      * Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
      * calls. The returned list includes those accounts which have been explicitly enabled by
-     * the user or other users visible to the user.
+     * the user or enabled by other users but visible to the user.
      *
      * @see #EXTRA_PHONE_ACCOUNT_HANDLE
      * @return A list of {@code PhoneAccountHandle} objects.
@@ -1486,7 +1486,7 @@
             return service.getCallCapablePhoneAccounts(includeDisabledAccounts,
                     mContext.getOpPackageName(), mContext.getAttributionTag(), true).getList();
         } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a73c46b..e5a94c3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2179,6 +2179,14 @@
      */
     public static final String KEY_MMS_NETWORK_RELEASE_TIMEOUT_MILLIS_INT =
             "mms_network_release_timeout_millis_int";
+    /**
+     * Maximum size in bytes of the PDU to send or download when connected to a non-terrestrial
+     * network. MmsService will return a result code of MMS_ERROR_TOO_LARGE_FOR_TRANSPORT if
+     * the PDU exceeds this limit when connected to a non-terrestrial network.
+     * @hide
+     */
+    public static final String KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT =
+            "mms_max_ntn_payload_size_bytes_int";
 
     /**
      * The flatten {@link android.content.ComponentName componentName} of the activity that can
@@ -10376,6 +10384,7 @@
         sDefaults.putInt(KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT, -1);
         sDefaults.putInt(KEY_MMS_SUBJECT_MAX_LENGTH_INT, 40);
         sDefaults.putInt(KEY_MMS_NETWORK_RELEASE_TIMEOUT_MILLIS_INT, 5 * 1000);
+        sDefaults.putInt(KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT, 3 * 1000);
         sDefaults.putString(KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, "");
         sDefaults.putString(KEY_MMS_HTTP_PARAMS_STRING, "");
         sDefaults.putString(KEY_MMS_NAI_SUFFIX_STRING, "");
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index c958aba..b7baabf 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -3123,6 +3123,12 @@
     @FlaggedApi(Flags.FLAG_MMS_DISABLED_ERROR)
     public static final int MMS_ERROR_MMS_DISABLED_BY_CARRIER = 12;
 
+    /**
+     * The MMS pdu was too large to send or too large to download over the current connection.
+     * @hide
+     */
+    public static final int MMS_ERROR_TOO_LARGE_FOR_TRANSPORT = 13;
+
     /** Intent extra name for MMS sending result data in byte array type */
     public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 1bf11df..eb7e67d 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1125,7 +1125,7 @@
     /**
      * TelephonyProvider column name for satellite attach enabled for carrier. The value of this
      * column is set based on user settings.
-     * By default, it's disabled.
+     * By default, it's enabled.
      * <P>Type: INTEGER (int)</P>
      * @hide
      */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d76af50..a0f0338 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -25,6 +25,7 @@
 import android.Manifest;
 import android.annotation.BytesLong;
 import android.annotation.CallbackExecutor;
+import android.annotation.CurrentTimeMillisLong;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.LongDef;
@@ -18714,51 +18715,93 @@
      * call diagnostic data
      * @hide
      */
-    public static class EmergencyCallDiagnosticParams {
+    @SystemApi
+    @FlaggedApi(com.android.server.telecom.flags.Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
+    public static final class EmergencyCallDiagnosticParams {
+        public static final class Builder {
+            private boolean mCollectTelecomDumpSys;
+            private boolean mCollectTelephonyDumpsys;
 
-       private boolean mCollectTelecomDumpSys;
-       private boolean mCollectTelephonyDumpsys;
-       private boolean mCollectLogcat;
+            // If this is set to a value other than -1L, then the logcat collection is enabled.
+            // Logcat lines with this time or greater are collected how much is collected is
+            // dependent on internal implementation. Time represented as milliseconds since boot.
+            private long mLogcatStartTimeMillis = sUnsetLogcatStartTime;
 
-        //logcat lines with this time or greater are collected
-        //how much is collected is dependent on internal implementation.
-        //Time represented as milliseconds since January 1, 1970 UTC
+            /**
+             * Allows enabling of telecom dumpsys collection.
+             * @param collectTelecomDumpsys Determines whether telecom dumpsys should be collected.
+             * @return Builder instance corresponding to the configured call diagnostic params.
+             */
+            public @NonNull Builder setTelecomDumpSysCollectionEnabled(
+                    boolean collectTelecomDumpsys) {
+                mCollectTelecomDumpSys = collectTelecomDumpsys;
+                return this;
+            }
+
+            /**
+             * Allows enabling of telephony dumpsys collection.
+             * @param collectTelephonyDumpsys Determines if telephony dumpsys should be collected.
+             * @return Builder instance corresponding to the configured call diagnostic params.
+             */
+            public @NonNull Builder setTelephonyDumpSysCollectionEnabled(
+                    boolean collectTelephonyDumpsys) {
+                mCollectTelephonyDumpsys = collectTelephonyDumpsys;
+                return this;
+            }
+
+            /**
+             * Allows enabling of logcat (system,radio) collection.
+             * @param startTimeMillis Enables logcat collection as of the indicated timestamp.
+             * @return Builder instance corresponding to the configured call diagnostic params.
+             */
+            public @NonNull Builder setLogcatCollectionStartTimeMillis(
+                    @CurrentTimeMillisLong long startTimeMillis) {
+                mLogcatStartTimeMillis = startTimeMillis;
+                return this;
+            }
+
+            /**
+             * Build the EmergencyCallDiagnosticParams from the provided Builder config.
+             * @return {@link EmergencyCallDiagnosticParams} instance from provided builder.
+             */
+            public @NonNull EmergencyCallDiagnosticParams build() {
+                return new EmergencyCallDiagnosticParams(mCollectTelecomDumpSys,
+                        mCollectTelephonyDumpsys, mLogcatStartTimeMillis);
+            }
+        }
+
+        private boolean mCollectTelecomDumpSys;
+        private boolean mCollectTelephonyDumpsys;
+        private boolean mCollectLogcat;
         private long mLogcatStartTimeMillis;
 
+        private static long sUnsetLogcatStartTime = -1L;
+
+        private EmergencyCallDiagnosticParams(boolean collectTelecomDumpSys,
+                boolean collectTelephonyDumpsys, long logcatStartTimeMillis) {
+            mCollectTelecomDumpSys = collectTelecomDumpSys;
+            mCollectTelephonyDumpsys = collectTelephonyDumpsys;
+            mLogcatStartTimeMillis = logcatStartTimeMillis;
+            mCollectLogcat = logcatStartTimeMillis != sUnsetLogcatStartTime;
+        }
 
         public boolean isTelecomDumpSysCollectionEnabled() {
             return mCollectTelecomDumpSys;
         }
 
-        public void setTelecomDumpSysCollection(boolean collectTelecomDumpSys) {
-            mCollectTelecomDumpSys = collectTelecomDumpSys;
-        }
-
         public boolean isTelephonyDumpSysCollectionEnabled() {
             return mCollectTelephonyDumpsys;
         }
 
-        public void setTelephonyDumpSysCollection(boolean collectTelephonyDumpsys) {
-            mCollectTelephonyDumpsys = collectTelephonyDumpsys;
-        }
-
         public boolean isLogcatCollectionEnabled() {
             return mCollectLogcat;
         }
 
-        public long getLogcatStartTime()
+        public long getLogcatCollectionStartTimeMillis()
         {
             return mLogcatStartTimeMillis;
         }
 
-        public void setLogcatCollection(boolean collectLogcat, long startTimeMillis) {
-            mCollectLogcat = collectLogcat;
-            if(mCollectLogcat)
-            {
-                mLogcatStartTimeMillis = startTimeMillis;
-            }
-        }
-
         @Override
         public String toString() {
             return "EmergencyCallDiagnosticParams{" +
@@ -18774,11 +18817,12 @@
      * Request telephony to persist state for debugging emergency call failures.
      *
      * @param dropboxTag Tag to use when persisting data to dropbox service.
-     *
-     * @see params Parameters controlling what is collected
+     * @param params Parameters controlling what is collected.
      *
      * @hide
      */
+    @SystemApi
+    @FlaggedApi(com.android.server.telecom.flags.Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
     @RequiresPermission(android.Manifest.permission.DUMP)
     public void persistEmergencyCallDiagnosticData(@NonNull String dropboxTag,
             @NonNull EmergencyCallDiagnosticParams params) {
@@ -18791,7 +18835,7 @@
             if (telephony != null) {
                 telephony.persistEmergencyCallDiagnosticData(dropboxTag,
                         params.isLogcatCollectionEnabled(),
-                        params.getLogcatStartTime(),
+                        params.getLogcatCollectionStartTimeMillis(),
                         params.isTelecomDumpSysCollectionEnabled(),
                         params.isTelephonyDumpSysCollectionEnabled());
             }
diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
index 8e79ca5..9aaa986 100644
--- a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
@@ -28,7 +28,7 @@
 /**
  * A callback class for listening to satellite datagrams.
  * {@link SatelliteDatagramCallback} is registered to telephony when an app which invokes
- * {@link SatelliteManager#registerForSatelliteDatagram(Executor, SatelliteDatagramCallback)},
+ * {@link SatelliteManager#registerForIncomingDatagram(Executor, SatelliteDatagramCallback)},
  * and {@link #onSatelliteDatagramReceived(long, SatelliteDatagram, int, Consumer)} will be invoked
  * when a new datagram is received from satellite.
  *
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index a1ac477..b97822a 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -146,7 +146,7 @@
 
     /**
      * Bundle key to get the response from
-     * {@link #requestIsSatelliteEnabled(Executor, OutcomeReceiver)}.
+     * {@link #requestIsEnabled(Executor, OutcomeReceiver)}.
      * @hide
      */
 
@@ -162,7 +162,7 @@
 
     /**
      * Bundle key to get the response from
-     * {@link #requestIsSatelliteSupported(Executor, OutcomeReceiver)}.
+     * {@link #requestIsSupported(Executor, OutcomeReceiver)}.
      * @hide
      */
 
@@ -170,7 +170,7 @@
 
     /**
      * Bundle key to get the response from
-     * {@link #requestSatelliteCapabilities(Executor, OutcomeReceiver)}.
+     * {@link #requestCapabilities(Executor, OutcomeReceiver)}.
      * @hide
      */
 
@@ -178,7 +178,7 @@
 
     /**
      * Bundle key to get the response from
-     * {@link #requestIsSatelliteProvisioned(Executor, OutcomeReceiver)}.
+     * {@link #requestIsProvisioned(Executor, OutcomeReceiver)}.
      * @hide
      */
 
@@ -186,7 +186,7 @@
 
     /**
      * Bundle key to get the response from
-     * {@link #requestIsSatelliteCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
+     * {@link #requestIsCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
      * @hide
      */
 
@@ -493,7 +493,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
+    public void requestEnabled(boolean enableSatellite, boolean enableDemoMode,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
@@ -535,7 +535,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void requestIsSatelliteEnabled(@NonNull @CallbackExecutor Executor executor,
+    public void requestIsEnabled(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(callback);
@@ -647,7 +647,7 @@
      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      */
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void requestIsSatelliteSupported(@NonNull @CallbackExecutor Executor executor,
+    public void requestIsSupported(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(callback);
@@ -701,7 +701,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void requestSatelliteCapabilities(@NonNull @CallbackExecutor Executor executor,
+    public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(callback);
@@ -967,7 +967,8 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void startSatelliteTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
+    @SuppressWarnings("SamShouldBeLast")
+    public void startTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener,
             @NonNull SatelliteTransmissionUpdateCallback callback) {
         Objects.requireNonNull(executor);
@@ -1029,7 +1030,7 @@
      * {@link #SATELLITE_RESULT_SUCCESS}. All other results that this operation failed.
      *
      * @param callback The callback that was passed to {@link
-     * #startSatelliteTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
+     * #startTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
      * @param executor The executor on which the error code listener will be called.
      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
@@ -1037,13 +1038,14 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void stopSatelliteTransmissionUpdates(
-            @NonNull SatelliteTransmissionUpdateCallback callback,
-            @NonNull @CallbackExecutor Executor executor,
-            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+    public void stopTransmissionUpdates(@NonNull SatelliteTransmissionUpdateCallback callback,
+            @SuppressWarnings("ListenerLast") @NonNull @CallbackExecutor Executor executor,
+            @SuppressWarnings("ListenerLast") @SatelliteResult @NonNull
+            Consumer<Integer> resultListener) {
         Objects.requireNonNull(callback);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
+
         ISatelliteTransmissionUpdateCallback internalCallback =
                 sSatelliteTransmissionUpdateCallbackMap.remove(callback);
 
@@ -1094,7 +1096,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
+    public void provisionService(@NonNull String token, @NonNull byte[] provisionData,
             @Nullable CancellationSignal cancellationSignal,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1135,11 +1137,11 @@
      * {@link SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean)}
      * should report as deprovisioned.
      * For provisioning satellite service, refer to
-     * {@link #provisionSatelliteService(String, byte[], CancellationSignal, Executor, Consumer)}
+     * {@link #provisionService(String, byte[], CancellationSignal, Executor, Consumer)}
      *
      * @param token The token of the device/subscription to be deprovisioned.
      *              This should match with the token passed as input in
-     *              {@link #provisionSatelliteService(String, byte[], CancellationSignal, Executor,
+     *              {@link #provisionService(String, byte[], CancellationSignal, Executor,
      *              Consumer)}
      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
@@ -1147,7 +1149,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void deprovisionSatelliteService(@NonNull String token,
+    public void deprovisionService(@NonNull String token,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(token);
@@ -1188,7 +1190,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    @SatelliteResult public int registerForSatelliteProvisionStateChanged(
+    @SatelliteResult public int registerForProvisionStateChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteProvisionStateCallback callback) {
         Objects.requireNonNull(executor);
@@ -1224,14 +1226,14 @@
      * If callback was not registered before, the request will be ignored.
      *
      * @param callback The callback that was passed to
-     * {@link #registerForSatelliteProvisionStateChanged(Executor, SatelliteProvisionStateCallback)}
+     * {@link #registerForProvisionStateChanged(Executor, SatelliteProvisionStateCallback)}
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void unregisterForSatelliteProvisionStateChanged(
+    public void unregisterForProvisionStateChanged(
             @NonNull SatelliteProvisionStateCallback callback) {
         Objects.requireNonNull(callback);
         ISatelliteProvisionStateCallback internalCallback =
@@ -1243,13 +1245,13 @@
                 if (internalCallback != null) {
                     telephony.unregisterForSatelliteProvisionStateChanged(mSubId, internalCallback);
                 } else {
-                    loge("unregisterForSatelliteProvisionStateChanged: No internal callback.");
+                    loge("unregisterForProvisionStateChanged: No internal callback.");
                 }
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("unregisterForSatelliteProvisionStateChanged() RemoteException: " + ex);
+            loge("unregisterForProvisionStateChanged() RemoteException: " + ex);
             ex.rethrowAsRuntimeException();
         }
     }
@@ -1269,7 +1271,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void requestIsSatelliteProvisioned(@NonNull @CallbackExecutor Executor executor,
+    public void requestIsProvisioned(@NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(callback);
@@ -1322,7 +1324,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    @SatelliteResult public int registerForSatelliteModemStateChanged(
+    @SatelliteResult public int registerForModemStateChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteModemStateCallback callback) {
         Objects.requireNonNull(executor);
@@ -1356,14 +1358,14 @@
      * If callback was not registered before, the request will be ignored.
      *
      * @param callback The callback that was passed to
-     * {@link #registerForSatelliteModemStateChanged(Executor, SatelliteModemStateCallback)}.
+     * {@link #registerForModemStateChanged(Executor, SatelliteModemStateCallback)}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void unregisterForSatelliteModemStateChanged(
+    public void unregisterForModemStateChanged(
             @NonNull SatelliteModemStateCallback callback) {
         Objects.requireNonNull(callback);
         ISatelliteModemStateCallback internalCallback = sSatelliteModemStateCallbackMap.remove(
@@ -1373,15 +1375,15 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 if (internalCallback != null) {
-                    telephony.unregisterForSatelliteModemStateChanged(mSubId, internalCallback);
+                    telephony.unregisterForModemStateChanged(mSubId, internalCallback);
                 } else {
-                    loge("unregisterForSatelliteModemStateChanged: No internal callback.");
+                    loge("unregisterForModemStateChanged: No internal callback.");
                 }
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("unregisterForSatelliteModemStateChanged() RemoteException:" + ex);
+            loge("unregisterForModemStateChanged() RemoteException:" + ex);
             ex.rethrowAsRuntimeException();
         }
     }
@@ -1390,7 +1392,7 @@
      * Register to receive incoming datagrams over satellite.
      *
      * To poll for pending satellite datagrams, refer to
-     * {@link #pollPendingSatelliteDatagrams(Executor, Consumer)}
+     * {@link #pollPendingDatagrams(Executor, Consumer)}
      *
      * @param executor The executor on which the callback will be called.
      * @param callback The callback to handle incoming datagrams over satellite.
@@ -1403,7 +1405,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    @SatelliteResult public int registerForSatelliteDatagram(
+    @SatelliteResult public int registerForIncomingDatagram(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteDatagramCallback callback) {
         Objects.requireNonNull(executor);
@@ -1436,12 +1438,12 @@
                             }
                         };
                 sSatelliteDatagramCallbackMap.put(callback, internalCallback);
-                return telephony.registerForSatelliteDatagram(mSubId, internalCallback);
+                return telephony.registerForIncomingDatagram(mSubId, internalCallback);
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("registerForSatelliteDatagram() RemoteException:" + ex);
+            loge("registerForIncomingDatagram() RemoteException:" + ex);
             ex.rethrowAsRuntimeException();
         }
         return SATELLITE_RESULT_REQUEST_FAILED;
@@ -1452,14 +1454,14 @@
      * If callback was not registered before, the request will be ignored.
      *
      * @param callback The callback that was passed to
-     * {@link #registerForSatelliteDatagram(Executor, SatelliteDatagramCallback)}.
+     * {@link #registerForIncomingDatagram(Executor, SatelliteDatagramCallback)}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void unregisterForSatelliteDatagram(@NonNull SatelliteDatagramCallback callback) {
+    public void unregisterForIncomingDatagram(@NonNull SatelliteDatagramCallback callback) {
         Objects.requireNonNull(callback);
         ISatelliteDatagramCallback internalCallback =
                 sSatelliteDatagramCallbackMap.remove(callback);
@@ -1468,15 +1470,15 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 if (internalCallback != null) {
-                    telephony.unregisterForSatelliteDatagram(mSubId, internalCallback);
+                    telephony.unregisterForIncomingDatagram(mSubId, internalCallback);
                 } else {
-                    loge("unregisterForSatelliteDatagram: No internal callback.");
+                    loge("unregisterForIncomingDatagram: No internal callback.");
                 }
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("unregisterForSatelliteDatagram() RemoteException:" + ex);
+            loge("unregisterForIncomingDatagram() RemoteException:" + ex);
             ex.rethrowAsRuntimeException();
         }
     }
@@ -1497,7 +1499,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void pollPendingSatelliteDatagrams(@NonNull @CallbackExecutor Executor executor,
+    public void pollPendingDatagrams(@NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -1512,13 +1514,13 @@
                                 () -> resultListener.accept(result)));
                     }
                 };
-                telephony.pollPendingSatelliteDatagrams(mSubId, internalCallback);
+                telephony.pollPendingDatagrams(mSubId, internalCallback);
             } else {
                 executor.execute(() -> Binder.withCleanCallingIdentity(
                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
             }
         } catch (RemoteException ex) {
-            loge("pollPendingSatelliteDatagrams() RemoteException:" + ex);
+            loge("pollPendingDatagrams() RemoteException:" + ex);
             ex.rethrowAsRuntimeException();
         }
     }
@@ -1550,7 +1552,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void sendSatelliteDatagram(@DatagramType int datagramType,
+    public void sendDatagram(@DatagramType int datagramType,
             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1568,14 +1570,14 @@
                                 () -> resultListener.accept(result)));
                     }
                 };
-                telephony.sendSatelliteDatagram(mSubId, datagramType, datagram,
+                telephony.sendDatagram(mSubId, datagramType, datagram,
                         needFullScreenPointingUI, internalCallback);
             } else {
                 executor.execute(() -> Binder.withCleanCallingIdentity(
                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
             }
         } catch (RemoteException ex) {
-            loge("sendSatelliteDatagram() RemoteException:" + ex);
+            loge("sendDatagram() RemoteException:" + ex);
             ex.rethrowAsRuntimeException();
         }
     }
@@ -1596,7 +1598,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
+    public void requestIsCommunicationAllowedForCurrentLocation(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
@@ -1626,14 +1628,14 @@
                         }
                     }
                 };
-                telephony.requestIsSatelliteCommunicationAllowedForCurrentLocation(mSubId,
+                telephony.requestIsCommunicationAllowedForCurrentLocation(mSubId,
                         receiver);
             } else {
                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
             }
         } catch (RemoteException ex) {
-            loge("requestIsSatelliteCommunicationAllowedForCurrentLocation() RemoteException: "
+            loge("requestIsCommunicationAllowedForCurrentLocation() RemoteException: "
                     + ex);
             ex.rethrowAsRuntimeException();
         }
@@ -1733,7 +1735,7 @@
      * <ul>
      * <li>Users want to enable it.</li>
      * <li>There is no satellite communication restriction, which is added by
-     * {@link #addSatelliteAttachRestrictionForCarrier(int, int, Executor, Consumer)}</li>
+     * {@link #addAttachRestrictionForCarrier(int, int, Executor, Consumer)}</li>
      * <li>The carrier config {@link
      * android.telephony.CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to
      * {@code true}.</li>
@@ -1749,17 +1751,17 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
-    public void requestSatelliteAttachEnabledForCarrier(int subId, boolean enableSatellite,
+    public void requestAttachEnabledForCarrier(int subId, boolean enableSatellite,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
 
         if (enableSatellite) {
-            removeSatelliteAttachRestrictionForCarrier(subId,
+            removeAttachRestrictionForCarrier(subId,
                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
         } else {
-            addSatelliteAttachRestrictionForCarrier(subId,
+            addAttachRestrictionForCarrier(subId,
                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
         }
     }
@@ -1783,13 +1785,13 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
-    public void requestIsSatelliteAttachEnabledForCarrier(int subId,
+    public void requestIsAttachEnabledForCarrier(int subId,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(callback);
 
-        Set<Integer> restrictionReason = getSatelliteAttachRestrictionReasonsForCarrier(subId);
+        Set<Integer> restrictionReason = getAttachRestrictionReasonsForCarrier(subId);
         executor.execute(() -> callback.onResult(
                 !restrictionReason.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)));
     }
@@ -1808,7 +1810,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
-    public void addSatelliteAttachRestrictionForCarrier(int subId,
+    public void addAttachRestrictionForCarrier(int subId,
             @SatelliteCommunicationRestrictionReason int reason,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1826,13 +1828,13 @@
                                 () -> resultListener.accept(result)));
                     }
                 };
-                telephony.addSatelliteAttachRestrictionForCarrier(subId, reason, errorCallback);
+                telephony.addAttachRestrictionForCarrier(subId, reason, errorCallback);
             } else {
                 executor.execute(() -> Binder.withCleanCallingIdentity(
                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
             }
         } catch (RemoteException ex) {
-            loge("addSatelliteAttachRestrictionForCarrier() RemoteException:" + ex);
+            loge("addAttachRestrictionForCarrier() RemoteException:" + ex);
             ex.rethrowAsRuntimeException();
         }
     }
@@ -1851,7 +1853,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
-    public void removeSatelliteAttachRestrictionForCarrier(int subId,
+    public void removeAttachRestrictionForCarrier(int subId,
             @SatelliteCommunicationRestrictionReason int reason,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1869,20 +1871,20 @@
                                 () -> resultListener.accept(result)));
                     }
                 };
-                telephony.removeSatelliteAttachRestrictionForCarrier(subId, reason, errorCallback);
+                telephony.removeAttachRestrictionForCarrier(subId, reason, errorCallback);
             } else {
                 executor.execute(() -> Binder.withCleanCallingIdentity(
                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
             }
         } catch (RemoteException ex) {
-            loge("removeSatelliteAttachRestrictionForCarrier() RemoteException:" + ex);
+            loge("removeAttachRestrictionForCarrier() RemoteException:" + ex);
             ex.rethrowAsRuntimeException();
         }
     }
 
     /**
      * Get reasons for disallowing satellite attach, as requested by
-     * {@link #addSatelliteAttachRestrictionForCarrier(int, int, Executor, Consumer)}
+     * {@link #addAttachRestrictionForCarrier(int, int, Executor, Consumer)}
      *
      * @param subId The subscription ID of the carrier.
      * @return Set of reasons for disallowing satellite communication.
@@ -1894,7 +1896,7 @@
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @SatelliteCommunicationRestrictionReason
     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
-    @NonNull public Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier(int subId) {
+    @NonNull public Set<Integer> getAttachRestrictionReasonsForCarrier(int subId) {
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             throw new IllegalArgumentException("Invalid subscription ID");
         }
@@ -1903,7 +1905,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 int[] receivedArray =
-                        telephony.getSatelliteAttachRestrictionReasonsForCarrier(subId);
+                        telephony.getAttachRestrictionReasonsForCarrier(subId);
                 if (receivedArray.length == 0) {
                     logd("receivedArray is empty, create empty set");
                     return new HashSet<>();
@@ -1914,7 +1916,7 @@
                 throw new IllegalStateException("Telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("getSatelliteAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
+            loge("getAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
             ex.rethrowAsRuntimeException();
         }
         return new HashSet<>();
@@ -2090,7 +2092,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    @SatelliteResult public int registerForSatelliteCapabilitiesChanged(
+    @SatelliteResult public int registerForCapabilitiesChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteCapabilitiesCallback callback) {
         Objects.requireNonNull(executor);
@@ -2110,12 +2112,12 @@
                             }
                         };
                 sSatelliteCapabilitiesCallbackMap.put(callback, internalCallback);
-                return telephony.registerForSatelliteCapabilitiesChanged(mSubId, internalCallback);
+                return telephony.registerForCapabilitiesChanged(mSubId, internalCallback);
             } else {
                 throw new IllegalStateException("Telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("registerForSatelliteCapabilitiesChanged() RemoteException: " + ex);
+            loge("registerForCapabilitiesChanged() RemoteException: " + ex);
             ex.rethrowAsRuntimeException();
         }
         return SATELLITE_RESULT_REQUEST_FAILED;
@@ -2126,14 +2128,14 @@
      * If callback was not registered before, the request will be ignored.
      *
      * @param callback The callback that was passed to.
-     * {@link #registerForSatelliteCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
+     * {@link #registerForCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    public void unregisterForSatelliteCapabilitiesChanged(
+    public void unregisterForCapabilitiesChanged(
             @NonNull SatelliteCapabilitiesCallback callback) {
         Objects.requireNonNull(callback);
         ISatelliteCapabilitiesCallback internalCallback =
@@ -2143,15 +2145,15 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 if (internalCallback != null) {
-                    telephony.unregisterForSatelliteCapabilitiesChanged(mSubId, internalCallback);
+                    telephony.unregisterForCapabilitiesChanged(mSubId, internalCallback);
                 } else {
-                    loge("unregisterForSatelliteCapabilitiesChanged: No internal callback.");
+                    loge("unregisterForCapabilitiesChanged: No internal callback.");
                 }
             } else {
                 throw new IllegalStateException("Telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("unregisterForSatelliteCapabilitiesChanged() RemoteException: " + ex);
+            loge("unregisterForCapabilitiesChanged() RemoteException: " + ex);
             ex.rethrowAsRuntimeException();
         }
     }
@@ -2166,7 +2168,7 @@
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
-    @NonNull public List<String> getAllSatellitePlmnsForCarrier(int subId) {
+    @NonNull public List<String> getSatellitePlmnsForCarrier(int subId) {
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             throw new IllegalArgumentException("Invalid subscription ID");
         }
@@ -2174,12 +2176,12 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getAllSatellitePlmnsForCarrier(subId);
+                return telephony.getSatellitePlmnsForCarrier(subId);
             } else {
                 throw new IllegalStateException("Telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("getAllSatellitePlmnsForCarrier() RemoteException: " + ex);
+            loge("getSatellitePlmnsForCarrier() RemoteException: " + ex);
             ex.rethrowAsRuntimeException();
         }
         return new ArrayList<>();
diff --git a/telephony/java/android/telephony/satellite/stub/INtnSignalStrengthConsumer.aidl b/telephony/java/android/telephony/satellite/stub/INtnSignalStrengthConsumer.aidl
index b7712bd..655da740 100644
--- a/telephony/java/android/telephony/satellite/stub/INtnSignalStrengthConsumer.aidl
+++ b/telephony/java/android/telephony/satellite/stub/INtnSignalStrengthConsumer.aidl
@@ -16,7 +16,7 @@
 
 package android.telephony.satellite.stub;
 
-import android.telephony.satellite.NtnSignalStrength;
+import android.telephony.satellite.stub.NtnSignalStrength;
 
 /**
  * Consumer pattern for a request that receives the signal strength of non-terrestrial network from
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
index c0d0830..abacd15 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
@@ -181,7 +181,7 @@
             executeMethodAsync(
                     () -> SatelliteImplBase.this
                             .sendSatelliteDatagram(datagram, isEmergency, resultCallback),
-                    "sendSatelliteDatagram");
+                    "sendDatagram");
         }
 
         @Override
@@ -201,7 +201,7 @@
                     () -> SatelliteImplBase.this
                             .requestIsSatelliteCommunicationAllowedForCurrentLocation(
                                     resultCallback, callback),
-                    "requestIsSatelliteCommunicationAllowedForCurrentLocation");
+                    "requestIsCommunicationAllowedForCurrentLocation");
         }
 
         @Override
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 780ef85..a1fc064 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2907,7 +2907,7 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void unregisterForSatelliteModemStateChanged(int subId, ISatelliteModemStateCallback callback);
+    void unregisterForModemStateChanged(int subId, ISatelliteModemStateCallback callback);
 
    /**
      * Register to receive incoming datagrams over satellite.
@@ -2919,18 +2919,18 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    int registerForSatelliteDatagram(int subId, ISatelliteDatagramCallback callback);
+    int registerForIncomingDatagram(int subId, ISatelliteDatagramCallback callback);
 
    /**
      * Unregister to stop receiving incoming datagrams over satellite.
      * If callback was not registered before, the request will be ignored.
      *
      * @param subId The subId of the subscription to unregister for incoming satellite datagrams.
-     * @param callback The callback that was passed to registerForSatelliteDatagram.
+     * @param callback The callback that was passed to registerForIncomingDatagram.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void unregisterForSatelliteDatagram(int subId, ISatelliteDatagramCallback callback);
+    void unregisterForIncomingDatagram(int subId, ISatelliteDatagramCallback callback);
 
    /**
     * Poll pending satellite datagrams over satellite.
@@ -2940,7 +2940,7 @@
     */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
                 + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void pollPendingSatelliteDatagrams(int subId, IIntegerConsumer callback);
+    void pollPendingDatagrams(int subId, IIntegerConsumer callback);
 
    /**
     * Send datagram over satellite.
@@ -2954,9 +2954,8 @@
     */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void sendSatelliteDatagram(int subId, int datagramType,
-             in SatelliteDatagram datagram, in boolean needFullScreenPointingUI,
-             IIntegerConsumer callback);
+    void sendDatagram(int subId, int datagramType, in SatelliteDatagram datagram,
+            in boolean needFullScreenPointingUI, IIntegerConsumer callback);
 
     /**
      * Request to get whether satellite communication is allowed for the current location.
@@ -2968,8 +2967,7 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
-            in ResultReceiver receiver);
+    void requestIsCommunicationAllowedForCurrentLocation(int subId, in ResultReceiver receiver);
 
     /**
      * Request to get the time after which the satellite will be visible.
@@ -3104,8 +3102,7 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void addSatelliteAttachRestrictionForCarrier(int subId, int reason,
-            in IIntegerConsumer callback);
+    void addAttachRestrictionForCarrier(int subId, int reason, in IIntegerConsumer callback);
 
     /**
      * Remove a restriction reason for disallowing satellite communication.
@@ -3117,12 +3114,11 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void removeSatelliteAttachRestrictionForCarrier(int subId, int reason,
-            in IIntegerConsumer callback);
+    void removeAttachRestrictionForCarrier(int subId, int reason, in IIntegerConsumer callback);
 
     /**
      * Get reasons for disallowing satellite communication, as requested by
-     * {@link #addSatelliteAttachRestrictionForCarrier(int, int)}.
+     * {@link #addAttachRestrictionForCarrier(int, int)}.
      *
      * @param subId The subId of the subscription to request for.
      *
@@ -3130,7 +3126,7 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    int[] getSatelliteAttachRestrictionReasonsForCarrier(int subId);
+    int[] getAttachRestrictionReasonsForCarrier(int subId);
 
     /**
      * Request to get the signal strength of the satellite connection.
@@ -3170,8 +3166,7 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void unregisterForNtnSignalStrengthChanged(int subId,
-            in INtnSignalStrengthCallback callback);
+    void unregisterForNtnSignalStrengthChanged(int subId, in INtnSignalStrengthCallback callback);
 
     /**
      * Registers for satellite capabilities change event from the satellite service.
@@ -3181,19 +3176,18 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    int registerForSatelliteCapabilitiesChanged(int subId,
-            in ISatelliteCapabilitiesCallback callback);
+    int registerForCapabilitiesChanged(int subId, in ISatelliteCapabilitiesCallback callback);
 
     /**
      * Unregisters for satellite capabilities change 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 #registerForSatelliteCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
+     * {@link #registerForCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void unregisterForSatelliteCapabilitiesChanged(int subId,
+    void unregisterForCapabilitiesChanged(int subId,
             in ISatelliteCapabilitiesCallback callback);
 
     /**
@@ -3280,5 +3274,5 @@
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    List<String> getAllSatellitePlmnsForCarrier(int subId);
+    List<String> getSatellitePlmnsForCarrier(int subId);
 }
diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index 256a469..566e51a 100644
--- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -24,6 +24,7 @@
 import android.hardware.input.InputManagerGlobal
 import android.os.test.TestLooper
 import android.platform.test.annotations.Presubmit
+import android.platform.test.flag.junit.SetFlagsRule
 import android.provider.Settings
 import android.test.mock.MockContentResolver
 import android.view.Display
@@ -72,6 +73,9 @@
     @get:Rule
     val fakeSettingsProviderRule = FakeSettingsProvider.rule()!!
 
+    @get:Rule
+    val setFlagsRule = SetFlagsRule()
+
     @Mock
     private lateinit var native: NativeInputManagerService
 
@@ -170,6 +174,8 @@
 
     @Test
     fun testSetVirtualMousePointerDisplayId() {
+        setFlagsRule.disableFlags(com.android.input.flags.Flags.FLAG_ENABLE_POINTER_CHOREOGRAPHER)
+
         // Set the virtual mouse pointer displayId, and ensure that the calling thread is blocked
         // until the native callback happens.
         var countDownLatch = CountDownLatch(1)
@@ -221,6 +227,8 @@
 
     @Test
     fun testSetVirtualMousePointerDisplayId_unsuccessfulUpdate() {
+        setFlagsRule.disableFlags(com.android.input.flags.Flags.FLAG_ENABLE_POINTER_CHOREOGRAPHER)
+
         // Set the virtual mouse pointer displayId, and ensure that the calling thread is blocked
         // until the native callback happens.
         val countDownLatch = CountDownLatch(1)
@@ -246,6 +254,8 @@
 
     @Test
     fun testSetVirtualMousePointerDisplayId_competingRequests() {
+        setFlagsRule.disableFlags(com.android.input.flags.Flags.FLAG_ENABLE_POINTER_CHOREOGRAPHER)
+
         val firstRequestSyncLatch = CountDownLatch(1)
         doAnswer {
             firstRequestSyncLatch.countDown()
@@ -289,6 +299,8 @@
 
     @Test
     fun onDisplayRemoved_resetAllAdditionalInputProperties() {
+        setFlagsRule.disableFlags(com.android.input.flags.Flags.FLAG_ENABLE_POINTER_CHOREOGRAPHER)
+
         setVirtualMousePointerDisplayIdAndVerify(10)
 
         localService.setPointerIconVisible(false, 10)
@@ -313,6 +325,8 @@
 
     @Test
     fun updateAdditionalInputPropertiesForOverrideDisplay() {
+        setFlagsRule.disableFlags(com.android.input.flags.Flags.FLAG_ENABLE_POINTER_CHOREOGRAPHER)
+
         setVirtualMousePointerDisplayIdAndVerify(10)
 
         localService.setPointerIconVisible(false, 10)
@@ -341,6 +355,8 @@
 
     @Test
     fun setAdditionalInputPropertiesBeforeOverride() {
+        setFlagsRule.disableFlags(com.android.input.flags.Flags.FLAG_ENABLE_POINTER_CHOREOGRAPHER)
+
         localService.setPointerIconVisible(false, 10)
         localService.setMousePointerAccelerationEnabled(false, 10)
 
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
index 5aaf30a..14230fe 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
@@ -134,7 +134,7 @@
                 c.drawText("Remote", 250, 250, paint);
                 surface.unlockCanvasAndPost(c);
                 WindowManager wm = getSystemService(WindowManager.class);
-                mInputToken = wm.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
+                wm.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
                         mSurfaceControl,
                         Choreographer.getInstance(), event -> {
                             Log.d(TAG, "onInputEvent-remote " + event);
@@ -147,11 +147,9 @@
         @Override
         public void tearDownEmbeddedSurfaceControl() {
             if (mSurfaceControl != null) {
-                new SurfaceControl.Transaction().remove(mSurfaceControl);
-            }
-            if (mInputToken != null) {
                 WindowManager wm = getSystemService(WindowManager.class);
-                wm.unregisterSurfaceControlInputReceiver(mInputToken);
+                wm.unregisterSurfaceControlInputReceiver(mSurfaceControl);
+                new SurfaceControl.Transaction().remove(mSurfaceControl).apply();
             }
         }
     }
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
index e5f8f47..7330ec1 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
@@ -50,10 +50,11 @@
     private static final String TAG = "SurfaceInputTestActivity";
     private SurfaceView mLocalSurfaceView;
     private SurfaceView mRemoteSurfaceView;
-    private IBinder mInputToken;
     private IAttachEmbeddedWindow mIAttachEmbeddedWindow;
     private SurfaceControl mParentSurfaceControl;
 
+    private SurfaceControl mLocalSurfaceControl;
+
     private final ServiceConnection mConnection = new ServiceConnection() {
         // Called when the connection with the service is established
         public void onServiceConnected(ComponentName className, IBinder service) {
@@ -112,30 +113,33 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        getWindowManager().unregisterSurfaceControlInputReceiver(mInputToken);
+        if (mLocalSurfaceControl != null) {
+            getWindowManager().unregisterSurfaceControlInputReceiver(mLocalSurfaceControl);
+            new SurfaceControl.Transaction().remove(mLocalSurfaceControl).apply();
+        }
     }
 
     private void addLocalChildSurfaceControl(AttachedSurfaceControl attachedSurfaceControl) {
-        SurfaceControl surfaceControl = new SurfaceControl.Builder().setName("LocalSC")
+        mLocalSurfaceControl = new SurfaceControl.Builder().setName("LocalSC")
                 .setBufferSize(100, 100).build();
-        attachedSurfaceControl.buildReparentTransaction(surfaceControl)
-                .setVisibility(surfaceControl, true)
-                .setCrop(surfaceControl, new Rect(0, 0, 100, 100))
-                .setPosition(surfaceControl, 250, 1000)
-                .setLayer(surfaceControl, 1).apply();
+        attachedSurfaceControl.buildReparentTransaction(mLocalSurfaceControl)
+                .setVisibility(mLocalSurfaceControl, true)
+                .setCrop(mLocalSurfaceControl, new Rect(0, 0, 100, 100))
+                .setPosition(mLocalSurfaceControl, 250, 1000)
+                .setLayer(mLocalSurfaceControl, 1).apply();
 
         Paint paint = new Paint();
         paint.setColor(Color.WHITE);
         paint.setTextSize(20);
 
-        Surface surface = new Surface(surfaceControl);
+        Surface surface = new Surface(mLocalSurfaceControl);
         Canvas c = surface.lockCanvas(null);
         c.drawColor(Color.GREEN);
         c.drawText("Local SC", 0, 0, paint);
         surface.unlockCanvasAndPost(c);
         WindowManager wm = getSystemService(WindowManager.class);
-        mInputToken = wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
-                attachedSurfaceControl.getHostToken(), surfaceControl,
+        wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
+                attachedSurfaceControl.getHostToken(), mLocalSurfaceControl,
                 Choreographer.getInstance(), event -> {
                     Log.d(TAG, "onInputEvent-sc " + event);
                     return false;
@@ -143,8 +147,6 @@
     }
 
     private final SurfaceHolder.Callback mLocalSurfaceViewCallback = new SurfaceHolder.Callback() {
-        private IBinder mInputToken;
-
         @Override
         public void surfaceCreated(@NonNull SurfaceHolder holder) {
             Paint paint = new Paint();
@@ -157,7 +159,7 @@
             holder.unlockCanvasAndPost(c);
 
             WindowManager wm = getSystemService(WindowManager.class);
-            mInputToken = wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
+            wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
                     mLocalSurfaceView.getHostToken(), mLocalSurfaceView.getSurfaceControl(),
                     Choreographer.getInstance(), event -> {
                         Log.d(TAG, "onInputEvent-local " + event);
@@ -173,9 +175,8 @@
 
         @Override
         public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
-            if (mInputToken != null) {
-                getWindowManager().unregisterSurfaceControlInputReceiver(mInputToken);
-            }
+            getWindowManager().unregisterSurfaceControlInputReceiver(
+                    mLocalSurfaceView.getSurfaceControl());
         }
     };
 
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index f3f1838..642a561 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1988,6 +1988,8 @@
     context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()});
     context_->SetSplitNameDependencies(app_info_.split_name_dependencies);
 
+    std::unique_ptr<xml::XmlResource> pre_flags_filter_manifest_xml = manifest_xml->Clone();
+
     FeatureFlagsFilterOptions flags_filter_options;
     if (context_->GetMinSdkVersion() > SDK_UPSIDE_DOWN_CAKE) {
       // For API version > U, PackageManager will dynamically read the flag values and disable
@@ -2297,7 +2299,12 @@
         }
 
         if (options_.generate_java_class_path) {
-          if (!WriteManifestJavaFile(manifest_xml.get())) {
+          // The FeatureFlagsFilter may remove <permission> and <permission-group> elements that
+          // generate constants in the Manifest Java file. While we want those permissions and
+          // permission groups removed in the SDK (i.e., if a feature flag is disabled), the
+          // constants should still remain so that code referencing it (e.g., within a feature
+          // flag check) will still compile. Therefore we use the manifest XML before the filter.
+          if (!WriteManifestJavaFile(pre_flags_filter_manifest_xml.get())) {
             error = true;
           }
         }
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 9323f3b..6cc42f1 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -1021,9 +1021,11 @@
                           .AddContents(manifest_contents)
                           .Build();
 
+  const std::string app_java = GetTestPath("app-java");
   auto app_link_args = LinkCommandBuilder(this)
                            .SetManifestFile(app_manifest)
                            .AddParameter("-I", android_apk)
+                           .AddParameter("--java", app_java)
                            .AddParameter("--feature-flags", "flag=false");
 
   const std::string app_apk = GetTestPath("app.apk");
@@ -1038,6 +1040,12 @@
   ASSERT_THAT(root, NotNull());
   auto maybe_removed = root->FindChild({}, "permission");
   ASSERT_THAT(maybe_removed, IsNull());
+
+  // Code for the permission should be generated even if the element is removed
+  const std::string manifest_java = app_java + "/com/example/app/Manifest.java";
+  std::string manifest_java_contents;
+  ASSERT_TRUE(android::base::ReadFileToString(manifest_java, &manifest_java_contents));
+  EXPECT_THAT(manifest_java_contents, HasSubstr(" public static final String FOO=\"FOO\";"));
 }
 
 TEST_F(LinkTest, FeatureFlagEnabled_SdkAtMostUDC) {
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 0b16e2c..d03f97e 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -415,6 +415,8 @@
   intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
   intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
   intent_filter_action["data"];
+  intent_filter_action["uri-relative-filter-group"];
+  intent_filter_action["uri-relative-filter-group"]["data"];
 
   // Common <meta-data> actions.
   xml::XmlNodeAction meta_data_action;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
index 2e47d48..65da4a1 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
@@ -28,6 +28,7 @@
 
     private final Object mPoller = new Object();
     private volatile boolean mPolling;
+    private volatile boolean mPendingWake;
 
     private void validate() {
         if (mDeleted) {
@@ -62,7 +63,9 @@
         synchronized (q.mPoller) {
             q.mPolling = true;
             try {
-                if (timeoutMillis == 0) {
+                if (q.mPendingWake) {
+                    // Calling with pending wake returns immediately
+                } else if (timeoutMillis == 0) {
                     // Calling epoll_wait() with 0 returns immediately
                 } else if (timeoutMillis == -1) {
                     q.mPoller.wait();
@@ -72,6 +75,8 @@
             } catch (InterruptedException e) {
                 Thread.currentThread().interrupt();
             }
+            // Any reason for returning counts as a "wake", so clear pending
+            q.mPendingWake = false;
             q.mPolling = false;
         }
     }
@@ -79,6 +84,7 @@
     public static void nativeWake(long ptr) {
         var q = getInstance(ptr);
         synchronized (q.mPoller) {
+            q.mPendingWake = true;
             q.mPoller.notifyAll();
         }
     }