Merge "Sandbox more input-related configs instead of fontScale with SCM" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 4e05cbc..2dd16de 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -73,6 +73,7 @@
         "android.service.dreams.flags-aconfig-java",
         "android.service.notification.flags-aconfig-java",
         "android.service.quickaccesswallet.flags-aconfig-java",
+        "android.service.selinux.flags-aconfig-java",
         "android.service.voice.flags-aconfig-java",
         "android.speech.flags-aconfig-java",
         "android.systemserver.flags-aconfig-java",
@@ -1943,3 +1944,19 @@
     aconfig_declarations: "android.service.quickaccesswallet.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// SELinux log collector
+aconfig_declarations {
+    name: "android.service.selinux.flags-aconfig",
+    package: "com.android.server.selinux.flags",
+    container: "system",
+    srcs: [
+        "services/core/java/com/android/server/selinux/*.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "android.service.selinux.flags-aconfig-java",
+    aconfig_declarations: "android.service.selinux.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Android.bp b/Android.bp
index 303fa2c..127556f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -103,10 +103,10 @@
         ":android.hardware.gnss-V2-java-source",
         ":android.hardware.graphics.common-V3-java-source",
         ":android.hardware.keymaster-V4-java-source",
-        ":android.hardware.radio-V4-java-source",
-        ":android.hardware.radio.data-V4-java-source",
-        ":android.hardware.radio.network-V4-java-source",
-        ":android.hardware.radio.voice-V4-java-source",
+        ":android.hardware.radio-V5-java-source",
+        ":android.hardware.radio.data-V5-java-source",
+        ":android.hardware.radio.network-V5-java-source",
+        ":android.hardware.radio.voice-V5-java-source",
         ":android.hardware.security.secureclock-V1-java-source",
         ":android.hardware.thermal-V3-java-source",
         ":android.hardware.tv.tuner-V3-java-source",
@@ -232,13 +232,13 @@
         "android.hardware.gnss-V2.1-java",
         "android.hardware.health-V1.0-java-constants",
         "android.hardware.radio-V1.6-java",
-        "android.hardware.radio.data-V4-java",
-        "android.hardware.radio.ims-V3-java",
-        "android.hardware.radio.messaging-V4-java",
-        "android.hardware.radio.modem-V4-java",
-        "android.hardware.radio.network-V4-java",
-        "android.hardware.radio.sim-V4-java",
-        "android.hardware.radio.voice-V4-java",
+        "android.hardware.radio.data-V5-java",
+        "android.hardware.radio.ims-V4-java",
+        "android.hardware.radio.messaging-V5-java",
+        "android.hardware.radio.modem-V5-java",
+        "android.hardware.radio.network-V5-java",
+        "android.hardware.radio.sim-V5-java",
+        "android.hardware.radio.voice-V5-java",
         "android.hardware.thermal-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java",
         "android.hardware.thermal-V1.1-java",
@@ -415,6 +415,7 @@
         "mimemap",
         "av-types-aidl-java",
         "tv_tuner_resource_manager_aidl_interface-java",
+        "media_quality_aidl_interface-java",
         "soundtrigger_middleware-aidl-java",
         "modules-utils-binary-xml",
         "modules-utils-build",
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index cc2d104..d48af2c 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -810,7 +810,7 @@
 
     /**
      * <p class="caution"><strong>Note:</strong> Beginning with
-     * {@link android.os.Build.VERSION_CODES#B}, this flag will be ignored and no longer
+     * {@link android.os.Build.VERSION_CODES#BAKLAVA}, this flag will be ignored and no longer
      * function effectively, regardless of the calling app's target SDK version.
      * Calling this method will always return {@code false}.
      *
@@ -2137,9 +2137,9 @@
          * Jobs marked as important-while-foreground are given {@link #PRIORITY_HIGH} by default.
          *
          * <p class="caution"><strong>Note:</strong> Beginning with
-         * {@link android.os.Build.VERSION_CODES#B}, this flag will be ignored and no longer
+         * {@link android.os.Build.VERSION_CODES#BAKLAVA}, this flag will be ignored and no longer
          * function effectively, regardless of the calling app's target SDK version.
-         * {link #isImportantWhileForeground()} will always return {@code false}.
+         * {@link #isImportantWhileForeground()} will always return {@code false}.
          * Apps should use {link #setExpedited(boolean)} with {@code true} to indicate
          * that this job is important and needs to run as soon as possible.
          *
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index abec170..d52bbc2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
+import android.annotation.NonNull;
 import android.app.job.JobInfo;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -28,6 +29,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
@@ -56,7 +58,10 @@
     private static final boolean DEBUG = JobSchedulerService.DEBUG
             || Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final long BACKGROUND_JOBS_DELAY = 3000;
+    /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */
+    private static final String DIJC_CONSTANT_PREFIX = "dijc_";
+    private static final String KEY_BACKGROUND_JOBS_DELAY_MS =
+            DIJC_CONSTANT_PREFIX + "background_jobs_delay_ms";
 
     static final int PROCESS_BACKGROUND_JOBS = 1;
 
@@ -78,6 +83,8 @@
     private int[] mDeviceIdleWhitelistAppIds;
     private int[] mPowerSaveTempWhitelistAppIds;
 
+    private long mBackgroundJobsDelay;
+
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -128,6 +135,9 @@
     public DeviceIdleJobsController(JobSchedulerService service) {
         super(service);
 
+        mBackgroundJobsDelay = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_jobSchedulerBackgroundJobsDelay);
+
         mHandler = new DeviceIdleJobsDelayHandler(AppSchedulingModuleThread.get().getLooper());
         // Register for device idle mode changes
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -165,7 +175,7 @@
                 // When coming out of doze, process all foreground uids and EJs immediately,
                 // while others will be processed after a delay of 3 seconds.
                 mService.getJobStore().forEachJob(mShouldRushEvaluation, mDeviceIdleUpdateFunctor);
-                mHandler.sendEmptyMessageDelayed(PROCESS_BACKGROUND_JOBS, BACKGROUND_JOBS_DELAY);
+                mHandler.sendEmptyMessageDelayed(PROCESS_BACKGROUND_JOBS, mBackgroundJobsDelay);
             }
         }
         // Inform the job scheduler service about idle mode changes
@@ -237,6 +247,26 @@
     }
 
     @Override
+    public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
+            @NonNull String key) {
+        switch (key) {
+            case KEY_BACKGROUND_JOBS_DELAY_MS:
+                mBackgroundJobsDelay = Math.max(0, properties.getLong(key, mBackgroundJobsDelay));
+                break;
+        }
+    }
+
+    @Override
+    public void dumpConstants(IndentingPrintWriter pw) {
+        pw.println();
+        pw.print(DeviceIdleJobsController.class.getSimpleName());
+        pw.println(":");
+        pw.increaseIndent();
+        pw.print(KEY_BACKGROUND_JOBS_DELAY_MS, mBackgroundJobsDelay).println();
+        pw.decreaseIndent();
+    }
+
+    @Override
     public void dumpControllerStateLocked(final IndentingPrintWriter pw,
             final Predicate<JobStatus> predicate) {
         pw.println("Idle mode: " + mDeviceIdleMode);
diff --git a/boot/boot-image-profile-extra.txt b/boot/boot-image-profile-extra.txt
index ce99bfe..cc02c8ae3 100644
--- a/boot/boot-image-profile-extra.txt
+++ b/boot/boot-image-profile-extra.txt
@@ -70,3 +70,10 @@
 HSPLandroid/os/PerfettoTrackEventExtra$FieldNested;->*
 HSPLandroid/os/PerfettoTrackEventExtra$Pool;->*
 HSPLandroid/os/PerfettoTrackEventExtra$RingBuffer;->*
+
+# While the SystemFeaturesMetadata static cache isn't heavyweight, ensure it's
+# pre-initialized in the boot image to avoid redundant per-process overhead.
+# TODO(b/326623529): Consider removing this after the feature has fully ramped
+# and is captured with the boot image profiling pipeline.
+HSPLcom/android/internal/pm/SystemFeaturesMetadata;->*
+Lcom/android/internal/pm/SystemFeaturesMetadata;
diff --git a/boot/preloaded-classes b/boot/preloaded-classes
index f87828e..7f4b324 100644
--- a/boot/preloaded-classes
+++ b/boot/preloaded-classes
@@ -11885,6 +11885,7 @@
 com.android.internal.os.ZygoteServer
 com.android.internal.os.logging.MetricsLoggerWrapper
 com.android.internal.pm.RoSystemFeatures
+com.android.internal.pm.SystemFeaturesMetadata
 com.android.internal.pm.parsing.PackageParser2$Callback
 com.android.internal.pm.parsing.PackageParserException
 com.android.internal.pm.pkg.component.flags.FeatureFlags
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 4147fd7..707acb0 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -11921,6 +11921,7 @@
 com.android.internal.os.ZygoteServer
 com.android.internal.os.logging.MetricsLoggerWrapper
 com.android.internal.pm.RoSystemFeatures
+com.android.internal.pm.SystemFeaturesMetadata
 com.android.internal.pm.parsing.PackageParser2$Callback
 com.android.internal.pm.parsing.PackageParserException
 com.android.internal.pm.pkg.component.flags.FeatureFlags
diff --git a/core/api/current.txt b/core/api/current.txt
index 3da5a5c..1630d80 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -56108,6 +56108,17 @@
     method @NonNull public android.view.WindowInsets getWindowInsets();
   }
 
+  @FlaggedApi("android.xr.xr_manifest_entries") public final class XrWindowProperties {
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String PROPERTY_XR_ACTIVITY_START_MODE = "android.window.PROPERTY_XR_ACTIVITY_START_MODE";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED = "android.window.PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED = "XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED = "XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_ACTIVITY_START_MODE_HOME_SPACE = "XR_ACTIVITY_START_MODE_HOME_SPACE";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_ACTIVITY_START_MODE_UNDEFINED = "XR_ACTIVITY_START_MODE_UNDEFINED";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_BOUNDARY_TYPE_LARGE = "XR_BOUNDARY_TYPE_LARGE";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_BOUNDARY_TYPE_NO_RECOMMENDATION = "XR_BOUNDARY_TYPE_NO_RECOMMENDATION";
+  }
+
 }
 
 package android.view.accessibility {
@@ -58276,7 +58287,9 @@
   }
 
   public final class WindowInspector {
+    method @FlaggedApi("android.view.flags.root_view_changed_listener") public static void addGlobalWindowViewsListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.view.View>>);
     method @NonNull public static java.util.List<android.view.View> getGlobalWindowViews();
+    method @FlaggedApi("android.view.flags.root_view_changed_listener") public static void removeGlobalWindowViewsListener(@NonNull java.util.function.Consumer<java.util.List<android.view.View>>);
   }
 
 }
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 526a213..132c65c 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -410,6 +410,7 @@
     method public void invalidateCache();
     method public static void invalidateCache(@NonNull String, @NonNull String);
     method @Nullable public Result query(@NonNull Query);
+    method @FlaggedApi("android.os.ipc_data_cache_test_apis") public static void setTestMode(boolean);
     field public static final String MODULE_BLUETOOTH = "bluetooth";
   }
 
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 984bc68..32b170a 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -11725,6 +11725,7 @@
     field public static final String USER_TYPE_FULL_GUEST = "android.os.usertype.full.GUEST";
     field public static final String USER_TYPE_FULL_SECONDARY = "android.os.usertype.full.SECONDARY";
     field public static final String USER_TYPE_FULL_SYSTEM = "android.os.usertype.full.SYSTEM";
+    field @FlaggedApi("android.multiuser.allow_supervising_profile") public static final String USER_TYPE_PROFILE_SUPERVISING = "android.os.usertype.profile.SUPERVISING";
     field public static final String USER_TYPE_SYSTEM_HEADLESS = "android.os.usertype.system.HEADLESS";
   }
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d651010..bb023f2 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1199,6 +1199,7 @@
     method public boolean isProfile();
     method public boolean isQuietModeEnabled();
     method public boolean isRestricted();
+    method @FlaggedApi("android.multiuser.allow_supervising_profile") public boolean isSupervisingProfile();
     method public boolean supportsSwitchTo();
     method @Deprecated public boolean supportsSwitchToByUser();
     method public void writeToParcel(android.os.Parcel, int);
@@ -2459,7 +2460,7 @@
     method public static void invalidateCache(@NonNull String, @NonNull String);
     method public final boolean isDisabled();
     method @Nullable public Result query(@NonNull Query);
-    method public static void setTestMode(boolean);
+    method @FlaggedApi("android.os.ipc_data_cache_test_apis") public static void setTestMode(boolean);
     field public static final String MODULE_BLUETOOTH = "bluetooth";
     field public static final String MODULE_SYSTEM = "system_server";
     field public static final String MODULE_TEST = "test";
diff --git a/core/java/android/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java
index d84a4c1..5f57a41 100644
--- a/core/java/android/animation/AnimationHandler.java
+++ b/core/java/android/animation/AnimationHandler.java
@@ -110,7 +110,8 @@
         }
     };
 
-    public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
+    public static final ThreadLocal<AnimationHandler> sAnimatorHandler =
+            ThreadLocal.withInitial(AnimationHandler::new);
     private static AnimationHandler sTestHandler = null;
     private boolean mListDirty = false;
 
@@ -118,9 +119,6 @@
         if (sTestHandler != null) {
             return sTestHandler;
         }
-        if (sAnimatorHandler.get() == null) {
-            sAnimatorHandler.set(new AnimationHandler());
-        }
         return sAnimatorHandler.get();
     }
 
@@ -384,6 +382,12 @@
         });
     }
 
+    void removePendingEndAnimationCallback(Runnable notifyEndAnimation) {
+        if (mPendingEndAnimationListeners != null) {
+            mPendingEndAnimationListeners.remove(notifyEndAnimation);
+        }
+    }
+
     private void doAnimationFrame(long frameTime) {
         long currentTime = SystemClock.uptimeMillis();
         final int size = mAnimationCallbacks.size();
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 4bf87f91..e62cd556a 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -82,6 +82,12 @@
     static boolean sPostNotifyEndListenerEnabled;
 
     /**
+     * If {@link #sPostNotifyEndListenerEnabled} is enabled, it will be set when the end callback
+     * is scheduled. It is cleared when it runs or finishes immediately, e.g. cancel.
+     */
+    private Runnable mPendingEndCallback;
+
+    /**
      * A cache of the values in a list. Used so that when calling the list, we have a copy
      * of it in case the list is modified while iterating. The array can be reused to avoid
      * allocation on every notification.
@@ -660,10 +666,33 @@
         }
     }
 
+    /**
+     * This is called when the animator needs to finish immediately. This is usually no-op unless
+     * {@link #sPostNotifyEndListenerEnabled} is enabled and a finish request calls around the last
+     * animation frame.
+     *
+     * @param notifyListeners Whether to invoke {@link AnimatorListener#onAnimationEnd}.
+     * @return {@code true} if the pending listeners are removed.
+     */
+    boolean consumePendingEndListeners(boolean notifyListeners) {
+        if (mPendingEndCallback == null) {
+            return false;
+        }
+        AnimationHandler.getInstance().removePendingEndAnimationCallback(mPendingEndCallback);
+        mPendingEndCallback = null;
+        if (notifyListeners) {
+            notifyEndListeners(false /* isReversing */);
+        }
+        return true;
+    }
+
     void notifyEndListenersFromEndAnimation(boolean isReversing, boolean postNotifyEndListener) {
         if (postNotifyEndListener) {
-            AnimationHandler.getInstance().postEndAnimationCallback(
-                    () -> completeEndAnimation(isReversing, "postNotifyAnimEnd"));
+            mPendingEndCallback = () -> {
+                completeEndAnimation(isReversing, "postNotifyAnimEnd");
+                mPendingEndCallback = null;
+            };
+            AnimationHandler.getInstance().postEndAnimationCallback(mPendingEndCallback);
         } else {
             completeEndAnimation(isReversing, "notifyAnimEnd");
         }
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 78566d2..4a07de0 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -423,6 +423,13 @@
             notifyListeners(AnimatorCaller.ON_CANCEL, false);
             callOnPlayingSet(Animator::cancel);
             mPlayingSet.clear();
+            // If the end callback is pending, invoke the end callbacks of the animator nodes before
+            // ending this set. Pass notifyListeners=false because this endAnimation will do that.
+            if (consumePendingEndListeners(false /* notifyListeners */)) {
+                for (int i = mNodeMap.size() - 1; i >= 0; i--) {
+                    mNodeMap.keyAt(i).consumePendingEndListeners(true /* notifyListeners */);
+                }
+            }
             endAnimation();
         }
     }
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 492c2ff..fbcc73e 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1182,6 +1182,7 @@
         // If end has already been requested, through a previous end() or cancel() call, no-op
         // until animation starts again.
         if (mAnimationEndRequested) {
+            consumePendingEndListeners(true /* notifyListeners */);
             return;
         }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 248f191..1864d4a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -18,7 +18,6 @@
 
 
 import static android.location.flags.Flags.FLAG_LOCATION_BYPASS;
-import static android.media.audio.Flags.roForegroundAudioControl;
 import static android.permission.flags.Flags.FLAG_OP_ENABLE_MOBILE_DATA_BY_USER;
 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
 import static android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED;
@@ -3481,6 +3480,16 @@
     }
 
     /**
+     * Whether an app op is backed by a runtime permission or not.
+     * @hide
+     */
+    public static boolean opIsRuntimePermission(int op) {
+        if (op == OP_NONE) return false;
+
+        return ArrayUtils.contains(RUNTIME_PERMISSION_OPS, op);
+    }
+
+    /**
      * Retrieve the user restriction associated with an operation, or null if there is not one.
      * @hide
      */
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cc72d8f..127a08b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3266,7 +3266,6 @@
         final Class<? extends Style> notificationStyle = getNotificationStyle();
 
         return notificationStyle == null
-                || BigPictureStyle.class.equals(notificationStyle)
                 || BigTextStyle.class.equals(notificationStyle)
                 || CallStyle.class.equals(notificationStyle)
                 || ProgressStyle.class.equals(notificationStyle);
@@ -6144,6 +6143,20 @@
                 result.mTitleMarginSet.applyToView(contentView, p.mTextViewId);
                 contentView.setInt(p.mTextViewId, "setNumIndentLines", p.hasTitle() ? 0 : 1);
             }
+            // The expand button uses paddings rather than margins, so we'll adjust it
+            // separately.
+            adjustExpandButtonPadding(contentView, result.mRightIconVisible);
+        }
+
+        private void adjustExpandButtonPadding(RemoteViews contentView, boolean rightIconVisible) {
+            if (notificationsRedesignTemplates()) {
+                final Resources res = mContext.getResources();
+                int normalPadding = res.getDimensionPixelSize(R.dimen.notification_2025_margin);
+                int iconSpacing = res.getDimensionPixelSize(
+                        R.dimen.notification_2025_expand_button_right_icon_spacing);
+                contentView.setInt(R.id.expand_button, "setStartPadding",
+                        rightIconVisible ? iconSpacing : normalPadding);
+            }
         }
 
         // This code is executed on behalf of other apps' notifications, sometimes even by 3p apps,
@@ -6155,12 +6168,21 @@
                 @NonNull TemplateBindResult result) {
             final Resources resources = mContext.getResources();
             final float density = resources.getDisplayMetrics().density;
-            final float iconMarginDp = resources.getDimension(
-                    R.dimen.notification_right_icon_content_margin) / density;
+            int iconMarginId = notificationsRedesignTemplates()
+                    ? R.dimen.notification_2025_right_icon_content_margin
+                    : R.dimen.notification_right_icon_content_margin;
+            final float iconMarginDp = resources.getDimension(iconMarginId) / density;
             final float contentMarginDp = resources.getDimension(
                     R.dimen.notification_content_margin_end) / density;
-            final float expanderSizeDp = resources.getDimension(
-                    R.dimen.notification_header_expand_icon_size) / density - contentMarginDp;
+            float spaceForExpanderDp;
+            if (notificationsRedesignTemplates()) {
+                spaceForExpanderDp = resources.getDimension(
+                        R.dimen.notification_2025_right_icon_expanded_margin_end) / density
+                        - contentMarginDp;
+            } else {
+                spaceForExpanderDp = resources.getDimension(
+                        R.dimen.notification_header_expand_icon_size) / density - contentMarginDp;
+            }
             final float viewHeightDp = resources.getDimension(
                     R.dimen.notification_right_icon_size) / density;
             float viewWidthDp = viewHeightDp;  // icons are 1:1 by default
@@ -6177,9 +6199,10 @@
                     }
                 }
             }
+            // Margin needed for the header to accommodate the icon when shown
             final float extraMarginEndDpIfVisible = viewWidthDp + iconMarginDp;
             result.setRightIconState(rightIcon != null /* visible */, viewWidthDp,
-                    viewHeightDp, extraMarginEndDpIfVisible, expanderSizeDp);
+                    viewHeightDp, extraMarginEndDpIfVisible, spaceForExpanderDp);
         }
 
         /**
@@ -14659,13 +14682,19 @@
         public final MarginSet mTitleMarginSet = new MarginSet();
 
         public void setRightIconState(boolean visible, float widthDp, float heightDp,
-                float marginEndDpIfVisible, float expanderSizeDp) {
+                float marginEndDpIfVisible, float spaceForExpanderDp) {
             mRightIconVisible = visible;
             mRightIconWidthDp = widthDp;
             mRightIconHeightDp = heightDp;
-            mHeadingExtraMarginSet.setValues(0, marginEndDpIfVisible);
-            mHeadingFullMarginSet.setValues(expanderSizeDp, marginEndDpIfVisible + expanderSizeDp);
-            mTitleMarginSet.setValues(0, marginEndDpIfVisible + expanderSizeDp);
+            mHeadingExtraMarginSet.setValues(
+                    /* valueIfGone = */ 0,
+                    /* valueIfVisible = */ marginEndDpIfVisible);
+            mHeadingFullMarginSet.setValues(
+                    /* valueIfGone = */ spaceForExpanderDp,
+                    /* valueIfVisible = */ marginEndDpIfVisible + spaceForExpanderDp);
+            mTitleMarginSet.setValues(
+                    /* valueIfGone = */ 0,
+                    /* valueIfVisible = */ marginEndDpIfVisible + spaceForExpanderDp);
         }
 
         /**
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 38141cf..6e49576 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -1417,7 +1417,36 @@
     }
 
     /**
-     * Enable or disable testing.  The protocol requires that the mode toggle: for instance, it is
+     * Throw if the current process is not allowed to use test APIs.
+     */
+    @android.ravenwood.annotation.RavenwoodReplace
+    private static void throwIfNotTest() {
+        final ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread == null) {
+            // Only tests can reach here.
+            return;
+        }
+        final Instrumentation instrumentation = activityThread.getInstrumentation();
+        if (instrumentation == null) {
+            // Only tests can reach here.
+            return;
+        }
+        if (instrumentation.isInstrumenting()) {
+            return;
+        }
+        if (Flags.enforcePicTestmodeProtocol()) {
+            throw new IllegalStateException("Test-only API called not from a test.");
+        }
+    }
+
+    /**
+     * Do not throw if running under ravenwood.
+     */
+    private static void throwIfNotTest$ravenwood() {
+    }
+
+    /**
+     * Enable or disable test mode.  The protocol requires that the mode toggle: for instance, it is
      * illegal to clear the test mode if the test mode is already off.  Enabling test mode puts
      * all caches in the process into test mode; all nonces are initialized to UNSET and
      * subsequent reads and writes are to process memory.  This has the effect of disabling all
@@ -1425,10 +1454,12 @@
      * operation.
      * @param mode The desired test mode.
      * @throws IllegalStateException if the supplied mode is already set.
+     * @throws IllegalStateException if the process is not running an instrumentation test.
      * @hide
      */
     @VisibleForTesting
     public static void setTestMode(boolean mode) {
+        throwIfNotTest();
         synchronized (sGlobalLock) {
             if (sTestMode == mode) {
                 final String msg = "cannot set test mode redundantly: mode=" + mode;
@@ -1464,9 +1495,11 @@
      * for which it would not otherwise have permission.  Caches in test mode do NOT write their
      * values to the system properties.  The effect is local to the current process.  Test mode
      * must be true when this method is called.
+     * @throws IllegalStateException if the process is not running an instrumentation test.
      * @hide
      */
     public void testPropertyName() {
+        throwIfNotTest();
         synchronized (sGlobalLock) {
             if (sTestMode == false) {
                 throw new IllegalStateException("cannot test property name with test mode off");
@@ -1777,10 +1810,12 @@
      * When multiple caches share a single property value, using an instance method on one of
      * the cache objects to invalidate all of the cache objects becomes confusing and you should
      * just use the static version of this function.
+     * @throws IllegalStateException if the process is not running an instrumentation test.
      * @hide
      */
     @VisibleForTesting
     public void disableSystemWide() {
+        throwIfNotTest();
         disableSystemWide(mPropertyName);
     }
 
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index cb2b8ad..8a8877f 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -558,6 +558,11 @@
     }
 
     public void dump(Printer pw, String prefix) {
+        pw.println("mVisible: " + mVisible);
+        pw.println("mUsesPolicies: " + mUsesPolicies);
+        pw.println("mSupportsTransferOwnership: " + mSupportsTransferOwnership);
+        pw.println("mHeadlessDeviceOwnerMode: " + mHeadlessDeviceOwnerMode);
+
         pw.println(prefix + "Receiver:");
         mActivityInfo.dump(pw, prefix + "  ");
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5359ba4..73de1b6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8269,6 +8269,7 @@
      *
      * @throws SecurityException if the caller is not a device owner, a profile owner or
      *         delegated certificate chooser.
+     * @throws IllegalArgumentException if {@code alias} does not correspond to an existing key
      * @see #grantKeyPairToWifiAuth
      */
     public boolean isKeyPairGrantedToWifiAuth(@NonNull String alias) {
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 0ecd275..572bffe 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -402,3 +402,13 @@
   description: "Add new API for secondary lockscreen"
   bug: "336297680"
 }
+
+flag {
+  name: "remove_managed_esim_on_work_profile_deletion"
+  namespace: "enterprise"
+  description: "Remove managed eSIM when work profile is deleted"
+  bug: "347925470"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 8e6b88c..5c267c9 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -255,6 +255,16 @@
 }
 
 flag {
+  name: "redaction_on_lockscreen_metrics"
+  namespace: "systemui"
+  description: "enables metrics when redacting notifications on the lockscreen"
+  bug: "343631648"
+    metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "api_rich_ongoing"
   is_exported: true
   namespace: "systemui"
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index 0085e4f..4fb3982 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -150,3 +150,11 @@
     description: "Settings override for virtual devices"
     bug: "371801645"
 }
+
+flag {
+    namespace: "virtual_devices"
+    name: "viewconfiguration_apis"
+    description: "APIs for settings ViewConfiguration attributes on virtual devices"
+    bug: "370720522"
+    is_exported: true
+}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 582a1a9..53203eb 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -410,6 +410,11 @@
         return UserManager.isUserTypePrivateProfile(userType);
     }
 
+    @FlaggedApi(android.multiuser.Flags.FLAG_ALLOW_SUPERVISING_PROFILE)
+    public boolean isSupervisingProfile() {
+        return UserManager.isUserTypeSupervisingProfile(userType);
+    }
+
     /** See {@link #FLAG_DISABLED}*/
     @UnsupportedAppUsage
     public boolean isEnabled() {
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 5c904c1..7f57f5dbf0 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -617,8 +617,8 @@
 }
 
 flag {
-     namespace: "multi_user"
      name: "logout_user_api"
+     namespace: "multiuser"
      description: "Add API to logout user"
      bug: "350045389"
 }
@@ -629,3 +629,10 @@
     description: "Enable moving content into the Private Space"
     bug: "360066001"
 }
+
+flag {
+    name: "allow_supervising_profile"
+    namespace: "supervision"
+    description: "Enables support for new supervising user type"
+    bug: "389712089"
+}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index e43a5fc..040dcfd 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -183,11 +183,6 @@
     private static native long nativeChanges(long connectionPtr);
     private static native long nativeTotalChanges(long connectionPtr);
 
-    // This method is deprecated and should be removed when it is no longer needed by the
-    // robolectric tests.  It should not be called from any frameworks java code.
-    @Deprecated
-    private static native void nativeClose(long connectionPtr);
-
     private SQLiteConnection(SQLiteConnectionPool pool,
             SQLiteDatabaseConfiguration configuration,
             int connectionId, boolean primaryConnection) {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 343e4b5..0c8a9ed 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -476,6 +476,16 @@
     public abstract boolean isDisplayReadyForMirroring(int displayId);
 
     /**
+     * Called by {@link com.android.server.wm.WindowManagerService} to notify whether a display
+     * should be in the topology.
+     * @param displayId The logical ID of the display
+     * @param inTopology Whether the display should be in the topology. This being true does not
+     *                   guarantee that the display will be in the topology - Display Manager might
+     *                   also check other parameters.
+     */
+    public abstract void onDisplayBelongToTopologyChanged(int displayId, boolean inTopology);
+
+    /**
      * Called by {@link  com.android.server.display.DisplayBackupHelper} when backup files were
      * restored and are ready to be reloaded.
      */
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/core/java/android/hardware/usb/IUsbManagerInternal.aidl
similarity index 63%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to core/java/android/hardware/usb/IUsbManagerInternal.aidl
index 6b8161c..32479d4 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/core/java/android/hardware/usb/IUsbManagerInternal.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,6 +14,13 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package android.hardware.usb;
 
-parcelable SoundProfileHandle;
+import android.hardware.usb.IUsbOperationInternal;
+
+/** @hide */
+interface IUsbManagerInternal {
+
+    /* Disable/enable USB data on a port for System Service callers. */
+    boolean enableUsbDataSignal(boolean enable, int disableReason);
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7b47efd4..894b068 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -527,22 +527,13 @@
     public static final int IME_ACTIVE = 1 << 0;
 
     /**
-     * The IME is perceptibly visible to the user.
+     * The IME is visible.
      *
      * @hide
      */
     public static final int IME_VISIBLE = 1 << 1;
 
     /**
-     * The IME is visible, but not yet perceptible to the user (e.g. fading in)
-     * by {@link android.view.WindowInsetsController}.
-     *
-     * @see InputMethodManager#reportPerceptible
-     * @hide
-     */
-    public static final int IME_VISIBLE_IMPERCEPTIBLE = 1 << 2;
-
-    /**
      * The IME window visibility state.
      *
      * @hide
@@ -550,7 +541,6 @@
     @IntDef(flag = true, prefix = { "IME_" }, value = {
             IME_ACTIVE,
             IME_VISIBLE,
-            IME_VISIBLE_IMPERCEPTIBLE,
     })
     public @interface ImeWindowVisibility {}
 
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index 0964cde..c3ec96d 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -145,8 +145,17 @@
         }
 
         if (Flags.forceConcurrentMessageQueue()) {
-            sIsProcessAllowedToUseConcurrent = true;
-            return;
+            // b/379472827: Robolectric tests use reflection to access MessageQueue.mMessages.
+            // This is a hack to allow Robolectric tests to use the legacy implementation.
+            try {
+                Class.forName("org.robolectric.Robolectric");
+            } catch (ClassNotFoundException e) {
+                // This is not a Robolectric test.
+                sIsProcessAllowedToUseConcurrent = true;
+                return;
+            }
+            // This is a Robolectric test.
+            // Continue to the following checks.
         }
 
         final String processName = Process.myProcessName();
diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java
index 3aad0fd..70a17ab 100644
--- a/core/java/android/os/ExternalVibration.java
+++ b/core/java/android/os/ExternalVibration.java
@@ -87,8 +87,12 @@
         int capturePreset = in.readInt();
         int flags = in.readInt();
         AudioAttributes.Builder builder = new AudioAttributes.Builder();
-        return builder.setUsage(usage)
-                .setContentType(contentType)
+        if (AudioAttributes.isSystemUsage(usage)) {
+            builder.setSystemUsage(usage);
+        } else {
+            builder.setUsage(usage);
+        }
+        return builder.setContentType(contentType)
                 .setCapturePreset(capturePreset)
                 .setFlags(flags)
                 .build();
@@ -196,7 +200,9 @@
     }
 
     private static void writeAudioAttributes(AudioAttributes attrs, Parcel out) {
-        out.writeInt(attrs.getUsage());
+        // Since we allow audio system usages, must use getSystemUsage() instead of getUsage() for
+        // all usages.
+        out.writeInt(attrs.getSystemUsage());
         out.writeInt(attrs.getContentType());
         out.writeInt(attrs.getCapturePreset());
         out.writeInt(attrs.getAllFlags());
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index 2e7c3be..e888f52 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -718,7 +718,7 @@
     }
 
     /**
-     * Enable or disable testing.  The protocol requires that the mode toggle: for instance, it is
+     * Enable or disable test mode.  The protocol requires that the mode toggle: for instance, it is
      * illegal to clear the test mode if the test mode is already off.  Enabling test mode puts
      * all caches in the process into test mode; all nonces are initialized to UNSET and
      * subsequent reads and writes are to process memory.  This has the effect of disabling all
@@ -726,8 +726,11 @@
      * operation.
      * @param mode The desired test mode.
      * @throws IllegalStateException if the supplied mode is already set.
+     * @throws IllegalStateException if the process is not running an instrumentation test.
      * @hide
      */
+    @FlaggedApi(android.os.Flags.FLAG_IPC_DATA_CACHE_TEST_APIS)
+    @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
     @TestApi
     public static void setTestMode(boolean mode) {
         PropertyInvalidatedCache.setTestMode(mode);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 767019d..c01c3cd 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -209,6 +209,23 @@
     public static final String USER_TYPE_PROFILE_COMMUNAL = "android.os.usertype.profile.COMMUNAL";
 
     /**
+     * User type representing a user who manages supervision on the device.
+     * When any full user on the device is supervised, the credentials for this profile will be
+     * required in order to perform certain actions for that user (i.e. those controlled by
+     * {@link android.app.supervision.SupervisionManager} or the
+     * {@link android.app.role.RoleManager#ROLE_SYSTEM_SUPERVISION supervision role holder}).
+     * There can only be one supervising profile per device, and the credentials set for that
+     * profile will be used to authorize actions for any supervised user on the device. This is
+     * distinct from a managed profile in that it functions only to authorize certain supervised
+     * actions; it does not represent the user to which restriction or management is applied.
+     * @hide
+     */
+    @FlaggedApi(android.multiuser.Flags.FLAG_ALLOW_SUPERVISING_PROFILE)
+    @SystemApi
+    public static final String USER_TYPE_PROFILE_SUPERVISING =
+            "android.os.usertype.profile.SUPERVISING";
+
+    /**
      * User type representing a {@link UserHandle#USER_SYSTEM system} user that is <b>not</b> a
      * human user.
      * This type of user cannot be created; it can only pre-exist on first boot.
@@ -3226,6 +3243,18 @@
     }
 
     /**
+     * Returns whether the user type is a
+     * {@link UserManager#USER_TYPE_PROFILE_SUPERVISING supervising profile}.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.multiuser.Flags.FLAG_ALLOW_SUPERVISING_PROFILE)
+    @android.ravenwood.annotation.RavenwoodKeep
+    public static boolean isUserTypeSupervisingProfile(@Nullable String userType) {
+        return USER_TYPE_PROFILE_SUPERVISING.equals(userType);
+    }
+
+    /**
      * @hide
      * @deprecated Use {@link #isRestrictedProfile()}
      */
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 86acb2b..5d80119 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -227,6 +227,14 @@
 }
 
 flag {
+     name: "ipc_data_cache_test_apis"
+     namespace: "system_performance"
+     description: "Expose IpcDataCache test apis to mainline modules."
+     bug: "396173886"
+     is_exported: true
+}
+
+flag {
      name: "mainline_vcn_platform_api"
      namespace: "vcn"
      description: "Expose platform APIs to mainline VCN"
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index a8a22f6..b82f278 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -216,7 +216,7 @@
     /**
      * Gets the maximum number of TIDs this device supports for getting CPU headroom.
      * <p>
-     * See {@link CpuHeadroomParams#setTids(int...)}.
+     * See {@link CpuHeadroomParams.Builder#setTids(int...)}.
      *
      * @return the maximum size of TIDs supported
      * @throws UnsupportedOperationException if the CPU headroom API is unsupported.
@@ -288,9 +288,7 @@
     /**
      * Gets the range of the calculation window size for CPU headroom.
      * <p>
-     * In API version 36, the range will be a superset of [50, 10000].
-     * <p>
-     * See {@link CpuHeadroomParams#setCalculationWindowMillis(int)}.
+     * See {@link CpuHeadroomParams.Builder#setCalculationWindowMillis(int)}.
      *
      * @return the range of the calculation window size supported in milliseconds.
      * @throws UnsupportedOperationException if the CPU headroom API is unsupported.
@@ -310,9 +308,7 @@
     /**
      * Gets the range of the calculation window size for GPU headroom.
      * <p>
-     * In API version 36, the range will be a superset of [50, 10000].
-     * <p>
-     * See {@link GpuHeadroomParams#setCalculationWindowMillis(int)}.
+     * See {@link GpuHeadroomParams.Builder#setCalculationWindowMillis(int)}.
      *
      * @return the range of the calculation window size supported in milliseconds.
      * @throws UnsupportedOperationException if the GPU headroom API is unsupported.
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 0476f62..34272b1 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -71,6 +71,19 @@
 }
 
 flag {
+    name: "unknown_call_setting_blocked_logging_enabled"
+    is_exported: true
+    is_fixed_read_only: true
+    namespace: "permissions"
+    description: "enable the metrics when blocking certain app installs during an unknown call"
+    bug: "364535720"
+
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "op_enable_mobile_data_by_user"
     is_exported: true
     namespace: "permissions"
@@ -372,6 +385,15 @@
 }
 
 flag {
+    name: "record_all_runtime_appops_sqlite"
+    is_fixed_read_only: true
+    is_exported: true
+    namespace: "permissions"
+    description: "Enables recording of all runtime app ops into SQlite"
+    bug: "377584611"
+}
+
+flag {
     name: "ranging_permission_enabled"
     is_fixed_read_only: true
     is_exported: true
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b97c9b5..da4709b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8651,6 +8651,34 @@
         public static final String DOCKED_CLOCK_FACE = "docked_clock_face";
 
         /**
+         * Setting to indicate that content filters should be enabled on web browsers.
+         *
+         * <ul>
+         *   <li>0 = Allow all sites
+         *   <li>1 = Try to block explicit sites
+         * </ul>
+         *
+         * @hide
+         */
+        @Readable
+        public static final String BROWSER_CONTENT_FILTERS_ENABLED =
+                "browser_content_filters_enabled";
+
+        /**
+         * Setting to indicate that content filters should be enabled in web search engines.
+         *
+         * <ul>
+         *   <li>0 = Off
+         *   <li>1 = Filter
+         * </ul>
+         *
+         * @hide
+         */
+        @Readable
+        public static final String SEARCH_CONTENT_FILTERS_ENABLED =
+                "search_content_filters_enabled";
+
+        /**
          * Set by the system to track if the user needs to see the call to action for
          * the lockscreen notification policy.
          * @hide
@@ -10589,6 +10617,57 @@
         public static final String GLANCEABLE_HUB_ENABLED = "glanceable_hub_enabled";
 
         /**
+         * Indicates that glanceable hub should never be started automatically.
+         *
+         * @hide
+         */
+        public static final int GLANCEABLE_HUB_START_NEVER = 0;
+
+        /**
+         * Indicates that glanceable hub should be started when charging.
+         *
+         * @hide
+         */
+        public static final int GLANCEABLE_HUB_START_CHARGING = 1;
+
+        /**
+         * Indicates that glanceable hub should be started when charging and upright.
+         *
+         * @hide
+         */
+        public static final int GLANCEABLE_HUB_START_CHARGING_UPRIGHT = 2;
+
+        /**
+         * Indicates that glanceable hub should be started when docked.
+         *
+         * @hide
+         */
+        public static final int GLANCEABLE_HUB_START_DOCKED = 3;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef({
+                GLANCEABLE_HUB_START_NEVER,
+                GLANCEABLE_HUB_START_CHARGING,
+                GLANCEABLE_HUB_START_CHARGING_UPRIGHT,
+                GLANCEABLE_HUB_START_DOCKED,
+        })
+        public @interface WhenToStartGlanceableHub {
+        }
+
+        /**
+         * Indicates when to start glanceable hub. Possible values are:
+         * 0: Never
+         * 1: While charging always
+         * 2: While upright and charging
+         * 3: While docked
+         *
+         * @hide
+         */
+        public static final String WHEN_TO_START_GLANCEABLE_HUB =
+                "when_to_start_glanceable_hub";
+
+        /**
          * Whether home controls are enabled to be shown over the screensaver by the user.
          *
          * @hide
@@ -11132,6 +11211,12 @@
         public static final String DOUBLE_TAP_TO_WAKE = "double_tap_to_wake";
 
         /**
+         * Controls whether double tap to sleep is enabled.
+         * @hide
+         */
+        public static final String DOUBLE_TAP_TO_SLEEP = "double_tap_to_sleep";
+
+        /**
          * The current assistant component. It could be a voice interaction service,
          * or an activity that handles ACTION_ASSIST, or empty which means using the default
          * handling.
@@ -12499,6 +12584,48 @@
                 "accessibility_magnification_always_on_enabled";
 
         /**
+         * Controls how the magnification follows the cursor.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE =
+                "accessibility_magnification_cursor_following_mode";
+
+        /**
+         * Magnification cursor following mode value for the continuous mode.
+         *
+         * @hide
+         */
+        public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CONTINUOUS = 0;
+
+        /**
+         * Magnification cursor following mode value for the center mode.
+         *
+         * @hide
+         */
+        public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CENTER = 1;
+
+        /**
+         * Magnification cursor following mode value for the edge mode.
+         *
+         * @hide
+         */
+        public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_EDGE = 2;
+
+        /**
+         * Different cursor following settings that can be used as values with
+         * {@link #ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE}.
+         * @hide
+         */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = { "ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_" },
+                value = {
+                        ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CONTINUOUS,
+                        ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CENTER,
+                        ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_EDGE})
+        public @interface AccessibilityMagnificationCursorFollowingMode {}
+
+        /**
          * Whether the following typing focus feature for magnification is enabled.
          * @hide
          */
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f7f4eec..7d70876 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4988,6 +4988,66 @@
         public static final String COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM =
                 "is_satellite_provisioned_for_non_ip_datagram";
 
+        /**
+         * TelephonyProvider column name for satellite entitlement barred plmns list separated by
+         * comma [,]. The value of this column is set based on entitlement query result for
+         * satellite configuration. Ex : 31026,302820,40445
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS =
+                "satellite_entitlement_barred_plmns";
+
+
+        /**
+         * TelephonyProvider column name for satellite entitlement data plan for plmns which is
+         * built in Json format in Key:Value pair. The value  of this column is set based on
+         * entitlement query result for satellite configuration.
+         * Ex : {"302820":0,"31026":1, "40445":0}
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS =
+                "satellite_entitlement_data_plan_plmns";
+
+        /**
+         * TelephonyProvider column name for satellite entitlement service type map which is
+         * built in Json format in Key:Value pair. The value of this column is set based on
+         * entitlement query result for satellite configuration.
+         * Ex : {"302820":[1,3],"31026":[2,3],"40445":[1,3]}
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP =
+                "satellite_entitlement_service_type_map";
+
+        /**
+         * TelephonyProvider column name for satellite entitlement data service policy type map
+         * which is built in Json format in Key:Value pair. The value of this column is set based
+         * on entitlement query result for satellite configuration.
+         * Ex : {"302820":2, "31026":1}
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY =
+                "satellite_entitlement_data_service_policy";
+
+        /**
+         * TelephonyProvider column name for satellite entitlement voice service policy  type map
+         * which is built in Json format in Key:Value pair. The value of this column is set
+         * based on entitlement query result for satellite configuration.
+         * Ex : {"302820":2, "31026":1}.
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY =
+                "satellite_entitlement_voice_service_policy";
+
         /** All columns in {@link SimInfo} table. */
         private static final List<String> ALL_COLUMNS = List.of(
                 COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
@@ -5065,7 +5125,12 @@
                 COLUMN_SATELLITE_ENTITLEMENT_STATUS,
                 COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
                 COLUMN_SATELLITE_ESOS_SUPPORTED,
-                COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM
+                COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM,
+                COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS,
+                COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS,
+                COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP,
+                COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY,
+                COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY
         );
 
         /**
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
index 770e234..0b2239a 100644
--- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
@@ -57,6 +57,7 @@
 @SystemService(Context.ADVANCED_PROTECTION_SERVICE)
 public final class AdvancedProtectionManager {
     private static final String TAG = "AdvancedProtectionMgr";
+    private static final String PKG_SETTINGS = "com.android.settings";
 
     //TODO(b/378931989): Switch to android.app.admin.DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY
     //when the appropriate flag is launched.
@@ -343,6 +344,7 @@
         }
 
         Intent intent = new Intent(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG);
+        intent.setPackage(PKG_SETTINGS);
         intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
         intent.putExtra(EXTRA_SUPPORT_DIALOG_FEATURE, featureId);
         intent.putExtra(EXTRA_SUPPORT_DIALOG_TYPE, type);
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index ce31e1e..f026614 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -455,7 +455,7 @@
 
                         // Simply wake up in the case the device is not locked.
                         if (!keyguardManager.isKeyguardLocked()) {
-                            wakeUp();
+                            wakeUp(false);
                             return true;
                         }
 
@@ -477,11 +477,11 @@
 
         if (!mInteractive) {
             if (mDebug) Slog.v(mTag, "Waking up on keyEvent");
-            wakeUp();
+            wakeUp(false);
             return true;
         } else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
             if (mDebug) Slog.v(mTag, "Waking up on back key");
-            wakeUp();
+            wakeUp(false);
             return true;
         }
         return mWindow.superDispatchKeyEvent(event);
@@ -492,7 +492,7 @@
     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
         if (!mInteractive) {
             if (mDebug) Slog.v(mTag, "Waking up on keyShortcutEvent");
-            wakeUp();
+            wakeUp(false);
             return true;
         }
         return mWindow.superDispatchKeyShortcutEvent(event);
@@ -505,7 +505,7 @@
         // but finish()es on any other kind of activity
         if (!mInteractive && event.getActionMasked() == MotionEvent.ACTION_UP) {
             if (mDebug) Slog.v(mTag, "Waking up on touchEvent");
-            wakeUp();
+            wakeUp(false);
             return true;
         }
         return mWindow.superDispatchTouchEvent(event);
@@ -516,7 +516,7 @@
     public boolean dispatchTrackballEvent(MotionEvent event) {
         if (!mInteractive) {
             if (mDebug) Slog.v(mTag, "Waking up on trackballEvent");
-            wakeUp();
+            wakeUp(false);
             return true;
         }
         return mWindow.superDispatchTrackballEvent(event);
@@ -527,7 +527,7 @@
     public boolean dispatchGenericMotionEvent(MotionEvent event) {
         if (!mInteractive) {
             if (mDebug) Slog.v(mTag, "Waking up on genericMotionEvent");
-            wakeUp();
+            wakeUp(false);
             return true;
         }
         return mWindow.superDispatchGenericMotionEvent(event);
@@ -925,32 +925,37 @@
         }
     }
 
-    private synchronized void updateDoze() {
-        if (mDreamToken == null) {
-            Slog.w(mTag, "Updating doze without a dream token.");
-            return;
-        }
-
-        if (mDozing) {
-            try {
-                Slog.v(mTag, "UpdateDoze mDozeScreenState=" + mDozeScreenState
-                        + " mDozeScreenBrightness=" + mDozeScreenBrightness
-                        + " mDozeScreenBrightnessFloat=" + mDozeScreenBrightnessFloat);
-                if (startAndStopDozingInBackground()) {
-                    mDreamManager.startDozingOneway(
-                            mDreamToken, mDozeScreenState, mDozeScreenStateReason,
-                            mDozeScreenBrightnessFloat, mDozeScreenBrightness,
-                            mUseNormalBrightnessForDoze);
-                } else {
-                    mDreamManager.startDozing(
-                            mDreamToken, mDozeScreenState, mDozeScreenStateReason,
-                            mDozeScreenBrightnessFloat, mDozeScreenBrightness,
-                            mUseNormalBrightnessForDoze);
-                }
-            } catch (RemoteException ex) {
-                // system server died
+    /**
+     * Updates doze state. Note that this must be called on the mHandler.
+     */
+    private void updateDoze() {
+        mHandler.post(() -> {
+            if (mDreamToken == null) {
+                Slog.w(mTag, "Updating doze without a dream token.");
+                return;
             }
-        }
+
+            if (mDozing) {
+                try {
+                    Slog.v(mTag, "UpdateDoze mDozeScreenState=" + mDozeScreenState
+                            + " mDozeScreenBrightness=" + mDozeScreenBrightness
+                            + " mDozeScreenBrightnessFloat=" + mDozeScreenBrightnessFloat);
+                    if (startAndStopDozingInBackground()) {
+                        mDreamManager.startDozingOneway(
+                                mDreamToken, mDozeScreenState, mDozeScreenStateReason,
+                                mDozeScreenBrightnessFloat, mDozeScreenBrightness,
+                                mUseNormalBrightnessForDoze);
+                    } else {
+                        mDreamManager.startDozing(
+                                mDreamToken, mDozeScreenState, mDozeScreenStateReason,
+                                mDozeScreenBrightnessFloat, mDozeScreenBrightness,
+                                mUseNormalBrightnessForDoze);
+                    }
+                } catch (RemoteException ex) {
+                    // system server died
+                }
+            }
+        });
     }
 
     /**
@@ -966,14 +971,16 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void stopDozing() {
-        if (mDozing) {
-            mDozing = false;
-            try {
-                mDreamManager.stopDozing(mDreamToken);
-            } catch (RemoteException ex) {
-                // system server died
+        mHandler.post(() -> {
+            if (mDozing) {
+                mDozing = false;
+                try {
+                    mDreamManager.stopDozing(mDreamToken);
+                } catch (RemoteException ex) {
+                    // system server died
+                }
             }
-        }
+        });
     }
 
     /**
@@ -1201,7 +1208,7 @@
             @Override
             public void onExitRequested() {
                 // Simply finish dream when exit is requested.
-                mHandler.post(() -> finish());
+                mHandler.post(() -> finishInternal());
             }
 
             @Override
@@ -1299,9 +1306,13 @@
      * </p>
      */
     public final void finish() {
+        mHandler.post(this::finishInternal);
+    }
+
+    private void finishInternal() {
         // If there is an active overlay connection, signal that the dream is ending before
-        // continuing. Note that the overlay cannot rely on the unbound state, since another dream
-        // might have bound to it in the meantime.
+        // continuing. Note that the overlay cannot rely on the unbound state, since another
+        // dream might have bound to it in the meantime.
         if (mOverlayConnection != null) {
             mOverlayConnection.addConsumer(overlay -> {
                 try {
@@ -1357,7 +1368,7 @@
      * </p>
      */
     public final void wakeUp() {
-        wakeUp(false);
+        mHandler.post(()-> wakeUp(false));
     }
 
     /**
@@ -1559,7 +1570,7 @@
         if (mActivity != null && !mActivity.isFinishing()) {
             mActivity.finishAndRemoveTask();
         } else {
-            finish();
+            finishInternal();
         }
 
         mDreamToken = null;
@@ -1719,7 +1730,7 @@
                             // the window reference in order to fully release the DreamActivity.
                             mWindow = null;
                             mActivity = null;
-                            finish();
+                            finishInternal();
                         }
 
                         if (mOverlayConnection != null && mDreamStartOverlayConsumer != null) {
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
index e1dc6f6..e9ddfc3 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
@@ -96,6 +96,10 @@
             defaultAppPackageName = defaultPaymentApp.getPackageName();
         }
 
+        if (defaultAppPackageName == null || defaultAppUser < 0) {
+            return null;
+        }
+
         ServiceInfo serviceInfo = getWalletServiceInfo(context, defaultAppPackageName,
                 defaultAppUser);
         if (serviceInfo == null) {
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index 937aecc..0ace808 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -230,8 +230,8 @@
         }
 
         @Override
-        public void ping(IRemoteCallback callback) throws RemoteException {
-            callback.sendResult(null);
+        public void ping(IPingMe callback) throws RemoteException {
+            callback.onPing();
         }
 
         @Override
diff --git a/core/java/android/service/voice/ISandboxedDetectionService.aidl b/core/java/android/service/voice/ISandboxedDetectionService.aidl
index c76ac28..5c4503c 100644
--- a/core/java/android/service/voice/ISandboxedDetectionService.aidl
+++ b/core/java/android/service/voice/ISandboxedDetectionService.aidl
@@ -65,11 +65,15 @@
     void updateRecognitionServiceManager(
         in IRecognitionServiceManager recognitionServiceManager);
 
+    interface IPingMe {
+        void onPing();
+    }
+
     /**
      * Simply requests the service to trigger the callback, so that the system can check its
      * identity.
      */
-    void ping(in IRemoteCallback callback);
+    void ping(in IPingMe callback);
 
     void stopDetection();
 
diff --git a/core/java/android/service/voice/VisualQueryDetectionService.java b/core/java/android/service/voice/VisualQueryDetectionService.java
index 8c9731d..5dcaa3e 100644
--- a/core/java/android/service/voice/VisualQueryDetectionService.java
+++ b/core/java/android/service/voice/VisualQueryDetectionService.java
@@ -122,8 +122,8 @@
         }
 
         @Override
-        public void ping(IRemoteCallback callback) throws RemoteException {
-            callback.sendResult(null);
+        public void ping(IPingMe callback) throws RemoteException {
+            callback.onPing();
         }
 
         @Override
diff --git a/core/java/android/util/MapCollections.java b/core/java/android/util/MapCollections.java
index cce3a0e..e7ceaae 100644
--- a/core/java/android/util/MapCollections.java
+++ b/core/java/android/util/MapCollections.java
@@ -355,7 +355,12 @@
             }
             return result;
         }
-    };
+
+        @Override
+        public String toString() {
+            return toStringHelper(0, this, "KeySet");
+        }
+    }
 
     final class ValuesCollection implements Collection<V> {
 
@@ -456,7 +461,12 @@
         public <T> T[] toArray(T[] array) {
             return toArrayHelper(array, 1);
         }
-    };
+
+        @Override
+        public String toString() {
+            return toStringHelper(1, this, "ValuesCollection");
+        }
+    }
 
     public static <K, V> boolean containsAllHelper(Map<K, V> map, Collection<?> collection) {
         Iterator<?> it = collection.iterator();
@@ -513,6 +523,29 @@
         return array;
     }
 
+    private String toStringHelper(int offset, Object thing, String thingName) {
+        int size = colGetSize();
+        if (size == 0) {
+            return "[]";
+        }
+
+        StringBuilder buffer = new StringBuilder(size * 14);
+        buffer.append('[');
+        for (int i = 0; i < size; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            Object entry = colGetEntry(i, offset);
+            if (entry != thing) {
+                buffer.append(entry);
+            } else {
+                buffer.append("(this ").append(thingName).append(")");
+            }
+        }
+        buffer.append(']');
+        return buffer.toString();
+    }
+
     public static <T> boolean equalsSetHelper(Set<T> set, Object object) {
         if (set == object) {
             return true;
diff --git a/core/java/android/view/ListenerWrapper.java b/core/java/android/view/ListenerWrapper.java
new file mode 100644
index 0000000..fcf3fdb
--- /dev/null
+++ b/core/java/android/view/ListenerWrapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.view;
+
+import android.annotation.NonNull;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * A utilty class to bundle a {@link Consumer} and an {@link Executor}
+ * @param <T> the type of value to be reported.
+ * @hide
+ */
+public class ListenerWrapper<T> {
+
+    @NonNull
+    private final Consumer<T> mConsumer;
+    @NonNull
+    private final Executor mExecutor;
+
+    public ListenerWrapper(@NonNull Executor executor, @NonNull Consumer<T> consumer) {
+        mExecutor = Objects.requireNonNull(executor);
+        mConsumer = Objects.requireNonNull(consumer);
+    }
+
+    /**
+     * Relays the new value to the {@link Consumer} using the {@link  Executor}
+     */
+    public void accept(@NonNull T value) {
+        mExecutor.execute(() -> mConsumer.accept(value));
+    }
+
+    /**
+     * Returns {@code true} if the consumer matches the one provided in the constructor,
+     * {@code false} otherwise.
+     */
+    public boolean isConsumerSame(@NonNull Consumer<T> consumer) {
+        return mConsumer.equals(consumer);
+    }
+}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 98e6cdd..7dc96f2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1836,6 +1836,7 @@
                         eventsToBeRegistered,
                         mBasePackageName);
 
+        // LINT.IfChange(fi_cb)
         if (forceInvertColor()) {
             if (mForceInvertObserver == null) {
                 mForceInvertObserver = new ContentObserver(mHandler) {
@@ -1844,7 +1845,6 @@
                         updateForceDarkMode();
                     }
                 };
-
                 final Uri[] urisToObserve = {
                     Settings.Secure.getUriFor(
                         Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED),
@@ -1859,6 +1859,7 @@
                 }
             }
         }
+        // LINT.ThenChange(/services/core/java/com/android/server/UiModeManagerService.java:fi_cb)
     }
 
     /**
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index a5da0c3..6242167 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -44,6 +44,7 @@
 import android.util.Pair;
 import android.util.SparseArray;
 import android.view.inputmethod.InputMethodManager;
+import android.view.translation.ListenerGroup;
 import android.window.ITrustedPresentationListener;
 import android.window.InputTransferToken;
 import android.window.TrustedPresentationThresholds;
@@ -58,6 +59,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.WeakHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -147,6 +149,12 @@
 
     @UnsupportedAppUsage
     private final ArrayList<View> mViews = new ArrayList<View>();
+    /**
+     * The {@link ListenerGroup} that is associated to {@link #mViews}.
+     * @hide
+     */
+    @GuardedBy("mLock")
+    private final ListenerGroup<List<View>> mWindowViewsListenerGroup = new ListenerGroup<>();
     @UnsupportedAppUsage
     private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
     @UnsupportedAppUsage
@@ -319,6 +327,29 @@
         }
     }
 
+    /**
+     * Adds a listener that will be notified whenever {@link #getWindowViews()} changes. The
+     * current value is provided immediately. If it was registered previously then this is ano op.
+     */
+    public void addWindowViewsListener(@NonNull Executor executor,
+            @NonNull Consumer<List<View>> consumer) {
+        synchronized (mLock) {
+            mWindowViewsListenerGroup.addListener(executor, consumer);
+            mWindowViewsListenerGroup.accept(getWindowViews());
+        }
+    }
+
+    /**
+     * Removes a listener that was registered in
+     * {@link #addWindowViewsListener(Executor, Consumer)}. If it was not registered previously,
+     * then this is a no op.
+     */
+    public void removeWindowViewsListener(@NonNull Consumer<List<View>> consumer) {
+        synchronized (mLock) {
+            mWindowViewsListenerGroup.removeListener(consumer);
+        }
+    }
+
     public View getWindowView(IBinder windowToken) {
         synchronized (mLock) {
             final int numViews = mViews.size();
@@ -454,6 +485,7 @@
             // do this last because it fires off messages to start doing things
             try {
                 root.setView(view, wparams, panelParentView, userId);
+                mWindowViewsListenerGroup.accept(getWindowViews());
             } catch (RuntimeException e) {
                 Log.e(TAG, "Couldn't add view: " + view, e);
                 final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
@@ -575,6 +607,7 @@
                 mDyingViews.remove(view);
             }
             allViewsRemoved = mRoots.isEmpty();
+            mWindowViewsListenerGroup.accept(getWindowViews());
         }
 
         // If we don't have any views anymore in our process, we no longer need the
diff --git a/core/java/android/view/XrWindowProperties.java b/core/java/android/view/XrWindowProperties.java
new file mode 100644
index 0000000..23021a5
--- /dev/null
+++ b/core/java/android/view/XrWindowProperties.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.view;
+
+import android.annotation.FlaggedApi;
+
+/**
+ * Class for XR-specific window properties to put in application manifests.
+ */
+@FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+public final class XrWindowProperties {
+    /** @hide */
+    private XrWindowProperties() {}
+
+    /**
+     * Both Application and activity level
+     * {@link android.content.pm.PackageManager.Property PackageManager.Property} for an app to
+     * inform the system of the activity launch mode in XR. When it is declared at the application
+     * level, all activities are set to the defined value, unless it is overridden at the activity
+     * level.
+     *
+     * <p>The default value is {@link #XR_ACTIVITY_START_MODE_UNDEFINED}.
+     *
+     * <p>The available values are:
+     * <ul>
+     *   <li>{@link #XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED}
+     *   <li>{@link #XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED}
+     *   <li>{@link #XR_ACTIVITY_START_MODE_HOME_SPACE}
+     *   <li>{@link #XR_ACTIVITY_START_MODE_UNDEFINED}
+     * </ul>
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_ACTIVITY_XR_START_MODE"
+     *     android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED|
+     *                    XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED|
+     *                    XR_ACTIVITY_START_MODE_HOME_SPACE|
+     *                    XR_ACTIVITY_START_MODE_UNDEFINED"/&gt;
+     * &lt;/application&gt;
+     * </pre>
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String PROPERTY_XR_ACTIVITY_START_MODE =
+            "android.window.PROPERTY_XR_ACTIVITY_START_MODE";
+
+    /**
+     * Defines the value to launch an activity in unmanaged full space mode in XR, where the
+     * activity itself is rendering the space and controls its own scene graph. This should be used
+     * for all activities that use OpenXR to render.
+     *
+     * @see #PROPERTY_XR_ACTIVITY_START_MODE
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED =
+            "XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED";
+
+    /**
+     * The default value if not specified. If used, the actual launching mode will be determined by
+     * the system based on the launching activity's current mode and the launching flags.  When
+     * {@link #PROPERTY_XR_ACTIVITY_START_MODE} is used at the application level, apps can use this
+     * value to reset at individual activity level.
+     *
+     * @see #PROPERTY_XR_ACTIVITY_START_MODE
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_ACTIVITY_START_MODE_UNDEFINED =
+            "XR_ACTIVITY_START_MODE_UNDEFINED";
+
+    /**
+     * Defines the value to launch an activity in
+     * <a href="https://developer.android.com/develop/xr/jetpack-xr-sdk/transition-home-space-to-full-space">managed
+     * full space mode</a> in XR, where the system is rendering the activity from a scene graph.
+     *
+     * @see #PROPERTY_XR_ACTIVITY_START_MODE
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED =
+            "XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED";
+
+    /**
+     * Defines the value to launch an activity in
+     * <a href="https://developer.android.com/develop/xr/jetpack-xr-sdk/transition-home-space-to-full-space">home
+     * space mode</a> in XR.
+     *
+     * @see #PROPERTY_XR_ACTIVITY_START_MODE
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_ACTIVITY_START_MODE_HOME_SPACE =
+            "XR_ACTIVITY_START_MODE_HOME_SPACE";
+
+    /**
+     * Both Application and activity level
+     * {@link android.content.pm.PackageManager.Property PackageManager.Property} for an app to
+     * inform the system of the type of safety boundary recommended for the activity. When it is
+     * declared at the application level, all activities are set to the defined value, unless it is
+     * overridden at the activity level. When not declared, the system will not enforce any
+     * recommendations for a type of safety boundary and will continue to use the type that is
+     * currently in use.
+     *
+     * <p>The default value is {@link #XR_BOUNDARY_TYPE_NO_RECOMMENDATION}.
+     *
+     * <p>The available values are:
+     * <ul>
+     *   <li>{@link #XR_BOUNDARY_TYPE_LARGE}
+     *   <li>{@link #XR_BOUNDARY_TYPE_NO_RECOMMENDATION}
+     * </ul>
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED"
+     *     android:value="XR_BOUNDARY_TYPE_LARGE|
+     *                    XR_BOUNDARY_TYPE_NO_RECOMMENDATION"/&gt;
+     * &lt;/application&gt;
+     * </pre>
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED =
+            "android.window.PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED";
+
+    /**
+     * Defines the value to launch an activity with no recommendations for the type of safety
+     * boundary. The system will continue to use the type of safety boundary that is currently
+     * in use.
+     *
+     * @see #PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_BOUNDARY_TYPE_NO_RECOMMENDATION =
+            "XR_BOUNDARY_TYPE_NO_RECOMMENDATION";
+
+    /**
+     * Defines the value to launch an activity with a large boundary recommended. This is useful for
+     * activities which expect users to be moving around. The system will ask the user to use a
+     * larger size for their safety boundary and check that their space is clear, if the larger
+     * size is not already in use. This larger size will be determined by the system.
+     *
+     * @see #PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_BOUNDARY_TYPE_LARGE = "XR_BOUNDARY_TYPE_LARGE";
+}
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index d06f885..d973104 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -159,3 +159,11 @@
     bug: "364653005"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "root_view_changed_listener"
+    namespace: "windowing_sdk"
+    description: "Implement listener pattern for WindowInspector#getGlobalWindowViews."
+    bug: "394397033"
+    is_fixed_read_only: false
+}
diff --git a/core/java/android/view/inspector/WindowInspector.java b/core/java/android/view/inspector/WindowInspector.java
index 69d004e..3ebca3c 100644
--- a/core/java/android/view/inspector/WindowInspector.java
+++ b/core/java/android/view/inspector/WindowInspector.java
@@ -16,11 +16,14 @@
 
 package android.view.inspector;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.view.View;
 import android.view.WindowManagerGlobal;
 
 import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Provides access to window inspection information.
@@ -37,4 +40,25 @@
     public static List<View> getGlobalWindowViews() {
         return WindowManagerGlobal.getInstance().getWindowViews();
     }
+
+    /**
+     * Adds a listener that is notified whenever the list of global window views changes. If a
+     * {@link Consumer} is already registered this method is a no op.
+     * @see #getGlobalWindowViews()
+     */
+    @FlaggedApi(android.view.flags.Flags.FLAG_ROOT_VIEW_CHANGED_LISTENER)
+    public static void addGlobalWindowViewsListener(@NonNull Executor executor,
+            @NonNull Consumer<List<View>> consumer) {
+        WindowManagerGlobal.getInstance().addWindowViewsListener(executor, consumer);
+    }
+
+    /**
+     * Removes a listener from getting notifications of global window views changes. If the
+     * {@link Consumer} is not registered this method is a no op.
+     * @see #addGlobalWindowViewsListener(Executor, Consumer)
+     */
+    @FlaggedApi(android.view.flags.Flags.FLAG_ROOT_VIEW_CHANGED_LISTENER)
+    public static void removeGlobalWindowViewsListener(@NonNull Consumer<List<View>> consumer) {
+        WindowManagerGlobal.getInstance().removeWindowViewsListener(consumer);
+    }
 }
diff --git a/core/java/android/view/translation/ListenerGroup.java b/core/java/android/view/translation/ListenerGroup.java
new file mode 100644
index 0000000..bf50681
--- /dev/null
+++ b/core/java/android/view/translation/ListenerGroup.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.view.translation;
+
+import android.annotation.NonNull;
+import android.view.ListenerWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * A utility class to manage a list of {@link ListenerWrapper}. This class is not thread safe.
+ * @param <T> the type of the value to be reported.
+ * @hide
+ */
+public class ListenerGroup<T> {
+    private final List<ListenerWrapper<T>> mListeners = new ArrayList<>();
+
+    /**
+     * Relays the value to all the registered {@link java.util.function.Consumer}
+     */
+    public void accept(@NonNull T value) {
+        Objects.requireNonNull(value);
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).accept(value);
+        }
+    }
+
+    /**
+     * Adds a {@link Consumer} to the group. If the {@link Consumer} is already present then this
+     * is a no op.
+     */
+    public void addListener(@NonNull Executor executor, @NonNull Consumer<T> consumer) {
+        if (isContained(consumer)) {
+            return;
+        }
+        mListeners.add(new ListenerWrapper<>(executor, consumer));
+    }
+
+    /**
+     * Removes a {@link Consumer} from the group. If the {@link Consumer} was not present then this
+     * is a no op.
+     */
+    public void removeListener(@NonNull Consumer<T> consumer) {
+        final int index = computeIndex(consumer);
+        if (index > -1) {
+            mListeners.remove(index);
+        }
+    }
+
+    /**
+     * Returns {@code true} if the {@link Consumer} is present in the list, {@code false}
+     * otherwise.
+     */
+    private boolean isContained(Consumer<T> consumer) {
+        return computeIndex(consumer) > -1;
+    }
+
+    /**
+     * Returns the index of the matching {@link ListenerWrapper} if present, {@code -1} otherwise.
+     */
+    private int computeIndex(Consumer<T> consumer) {
+        for (int i = 0; i < mListeners.size(); i++) {
+            if (mListeners.get(i).isConsumerSame(consumer)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+}
diff --git a/core/java/android/window/DesktopExperienceFlags.java b/core/java/android/window/DesktopExperienceFlags.java
index cf58217..0b52687 100644
--- a/core/java/android/window/DesktopExperienceFlags.java
+++ b/core/java/android/window/DesktopExperienceFlags.java
@@ -66,9 +66,11 @@
             false),
     ENABLE_PER_DISPLAY_PACKAGE_CONTEXT_CACHE_IN_STATUSBAR_NOTIF(
             Flags::enablePerDisplayPackageContextCacheInStatusbarNotif, false),
+    ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE(Flags::enableProjectedDisplayDesktopMode, false),
     ENABLE_TASKBAR_CONNECTED_DISPLAYS(Flags::enableTaskbarConnectedDisplays, false),
     ENTER_DESKTOP_BY_DEFAULT_ON_FREEFORM_DISPLAYS(Flags::enterDesktopByDefaultOnFreeformDisplays,
             false),
+    FORM_FACTOR_BASED_DESKTOP_FIRST_SWITCH(Flags::formFactorBasedDesktopFirstSwitch, false),
     REPARENT_WINDOW_TOKEN_API(Flags::reparentWindowTokenApi, true)
     // go/keep-sorted end
     ;
diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
index 00c7020..17165cd 100644
--- a/core/java/android/window/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -94,6 +94,7 @@
     ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES(
             Flags::enableDesktopWindowingMultiInstanceFeatures, true),
     ENABLE_DESKTOP_WINDOWING_PERSISTENCE(Flags::enableDesktopWindowingPersistence, true),
+    ENABLE_DESKTOP_WINDOWING_PIP(Flags::enableDesktopWindowingPip, false),
     ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH(Flags::enableDesktopWindowingQuickSwitch, true),
     ENABLE_DESKTOP_WINDOWING_SCVH_CACHE(Flags::enableDesktopWindowingScvhCacheBugFix, true),
     ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS(Flags::enableDesktopWindowingSizeConstraints, true),
@@ -108,6 +109,7 @@
     ENABLE_FULLY_IMMERSIVE_IN_DESKTOP(Flags::enableFullyImmersiveInDesktop, true),
     ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true),
     ENABLE_HOLD_TO_DRAG_APP_HANDLE(Flags::enableHoldToDragAppHandle, true),
+    ENABLE_INPUT_LAYER_TRANSITION_FIX(Flags::enableInputLayerTransitionFix, false),
     ENABLE_MINIMIZE_BUTTON(Flags::enableMinimizeButton, true),
     ENABLE_MODALS_FULLSCREEN_WITH_PERMISSIONS(Flags::enableModalsFullscreenWithPermission, false),
     ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS(
@@ -136,10 +138,14 @@
     ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS(
             Flags::enableWindowingTransitionHandlersObservers, false),
     EXCLUDE_CAPTION_FROM_APP_BOUNDS(Flags::excludeCaptionFromAppBounds, false),
+    FORCE_CLOSE_TOP_TRANSPARENT_FULLSCREEN_TASK(
+            Flags::forceCloseTopTransparentFullscreenTask, false),
     IGNORE_ASPECT_RATIO_RESTRICTIONS_FOR_RESIZEABLE_FREEFORM_ACTIVITIES(
             Flags::ignoreAspectRatioRestrictionsForResizeableFreeformActivities, true),
     INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC(
-            Flags::includeTopTransparentFullscreenTaskInDesktopHeuristic, true)
+            Flags::includeTopTransparentFullscreenTaskInDesktopHeuristic, true),
+    INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES(
+            Flags::inheritTaskBoundsForTrampolineTaskLaunches, false),
     // go/keep-sorted end
     ;
 
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 403577a..e706af9 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -27,6 +27,17 @@
 }
 
 flag {
+    name: "inherit_task_bounds_for_trampoline_task_launches"
+    namespace: "lse_desktop_experience"
+    description: "Forces trampoline task launches to inherit the bounds of the previous instance /n"
+                 "before is closes to prevent each task from cascading."
+    bug: "392815318"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "include_top_transparent_fullscreen_task_in_desktop_heuristic"
     namespace: "lse_desktop_experience"
     description: "Whether to include any top transparent fullscreen task launched in desktop /n"
@@ -50,6 +61,17 @@
 }
 
 flag {
+    name: "force_close_top_transparent_fullscreen_task"
+    namespace: "lse_desktop_experience"
+    description: "If a top transparent fullscreen task is on top of desktop mode, force it to /n"
+                 "close if another task is opened or brought to front."
+    bug: "395041610"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_windowing_dynamic_initial_bounds"
     namespace: "lse_desktop_experience"
     description: "Enables new initial bounds for desktop windowing which adjust depending on app constraints"
@@ -154,6 +176,16 @@
 }
 
 flag {
+    name: "enable_input_layer_transition_fix"
+    namespace: "lse_desktop_experience"
+    description: "Enables a bugfix for input layer disposal during certain transitions."
+    bug: "371473978"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_accessible_custom_headers"
     namespace: "lse_desktop_experience"
     description: "Enables a11y-friendly custom header input handling"
@@ -906,3 +938,10 @@
     description: "Enables the desktop-first mode switching logic based on its form factor."
     bug: "394736817"
 }
+
+flag {
+    name: "enable_restart_menu_for_connected_displays"
+    namespace: "lse_desktop_experience"
+    description: "Enable restart menu UI, which is shown when an app moves between displays."
+    bug: "397804287"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index f2ba16c..3927c71 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -51,6 +51,17 @@
 }
 
 flag {
+  name: "use_cached_insets_for_display_switch"
+  namespace: "windowing_frontend"
+  description: "Reduce intermediate insets changes for display switch"
+  bug: "266197298"
+  is_fixed_read_only: true
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "edge_to_edge_by_default"
   namespace: "windowing_frontend"
   description: "Make app go edge-to-edge by default when targeting SDK 35 or greater"
@@ -75,6 +86,14 @@
 }
 
 flag {
+  name: "action_mode_edge_to_edge"
+  namespace: "windowing_frontend"
+  description: "Make contextual action bar edge-to-edge"
+  bug: "379783298"
+  is_fixed_read_only: true
+}
+
+flag {
   name: "keyguard_going_away_timeout"
   namespace: "windowing_frontend"
   description: "Allow a maximum of 10 seconds with keyguardGoingAway=true before force-resetting"
@@ -490,6 +509,17 @@
     description: "Sets Launch powermode for activity launches earlier"
     bug: "399380676"
     is_fixed_read_only: true
+        metadata {
+            purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "scramble_snapshot_file_name"
+    namespace: "windowing_frontend"
+    description: "Scramble the file name of task snapshot."
+    bug: "293139053"
+    is_fixed_read_only: true
     metadata {
         purpose: PURPOSE_BUGFIX
     }
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index f2efa20..cbeaeda 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -81,6 +81,16 @@
 
 flag {
     namespace: "windowing_sdk"
+    name: "activity_embedding_delay_task_fragment_finish_for_activity_launch"
+    description: "Fixes a race condition that we finish the TaskFragment too early when there is a pending activity launch."
+    bug: "390452023"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    namespace: "windowing_sdk"
     name: "wlinfo_oncreate"
     description: "Makes WindowLayoutInfo accessible without racing in the Activity#onCreate()"
     bug: "337820752"
@@ -127,17 +137,6 @@
 
 flag {
     namespace: "windowing_sdk"
-    name: "use_self_sync_transaction_for_layer"
-    description: "Always use this.getSyncTransaction for assignLayer"
-    bug: "388127825"
-    is_fixed_read_only: true
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "windowing_sdk"
     name: "safe_region_letterboxing"
     description: "Enables letterboxing for a safe region"
     bug: "380132497"
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 81ca231..c6207f9 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -45,11 +45,13 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Queue;
 import java.util.concurrent.locks.ReentrantLock;
 
 /**
@@ -203,15 +205,6 @@
         BatteryHistoryFragment getLatestFragment();
 
         /**
-         * Given a fragment, returns the earliest fragment that follows it whose monotonic
-         * start time falls within the specified range. `startTimeMs` is inclusive, `endTimeMs`
-         * is exclusive.
-         */
-        @Nullable
-        BatteryHistoryFragment getNextFragment(BatteryHistoryFragment current, long startTimeMs,
-                long endTimeMs);
-
-        /**
          * Acquires a lock on the entire store.
          */
         void lock();
@@ -268,6 +261,60 @@
         void reset();
     }
 
+    class BatteryHistoryParcelContainer {
+        private boolean mParcelReadyForReading;
+        private Parcel mParcel;
+        private BatteryStatsHistory.BatteryHistoryFragment mFragment;
+        private long mMonotonicStartTime;
+
+        BatteryHistoryParcelContainer(@NonNull Parcel parcel, long monotonicStartTime) {
+            mParcel = parcel;
+            mMonotonicStartTime = monotonicStartTime;
+            mParcelReadyForReading = true;
+        }
+
+        BatteryHistoryParcelContainer(@NonNull BatteryHistoryFragment fragment) {
+            mFragment = fragment;
+            mMonotonicStartTime = fragment.monotonicTimeMs;
+            mParcelReadyForReading = false;
+        }
+
+        @Nullable
+        Parcel getParcel() {
+            if (mParcelReadyForReading) {
+                return mParcel;
+            }
+
+            Parcel parcel = Parcel.obtain();
+            if (readFragmentToParcel(parcel, mFragment)) {
+                parcel.readInt();       // skip buffer size
+                mParcel = parcel;
+            } else {
+                parcel.recycle();
+            }
+            mParcelReadyForReading = true;
+            return mParcel;
+        }
+
+        long getMonotonicStartTime() {
+            return mMonotonicStartTime;
+        }
+
+        /**
+         * Recycles the parcel (if appropriate). Should be called after the parcel has been
+         * processed by the iterator.
+         */
+        void close() {
+            if (mParcel != null && mFragment != null) {
+                mParcel.recycle();
+            }
+            // ParcelContainers are not meant to be reusable. To prevent any unintentional
+            // access to the parcel after it has been recycled, clear the references to it.
+            mParcel = null;
+            mFragment = null;
+        }
+    }
+
     private final Parcel mHistoryBuffer;
     private final HistoryStepDetailsCalculator mStepDetailsCalculator;
     private final Clock mClock;
@@ -447,6 +494,7 @@
         mWritableHistory = writableHistory;
         if (mWritableHistory != null) {
             mMutable = false;
+            mHistoryBufferStartTime = mWritableHistory.mHistoryBufferStartTime;
             mHistoryMonotonicEndTime = mWritableHistory.mHistoryMonotonicEndTime;
         }
 
@@ -689,95 +737,66 @@
     }
 
     /**
-     * When iterating history files and history buffer, always start from the lowest numbered
-     * history file, when reached the mActiveFile (highest numbered history file), do not read from
-     * mActiveFile, read from history buffer instead because the buffer has more updated data.
-     *
-     * @return The parcel that has next record. null if finished all history files and history
-     * buffer
+     * Returns all chunks of accumulated history that contain items within the range between
+     * `startTimeMs` (inclusive) and `endTimeMs` (exclusive)
      */
-    @Nullable
-    public Parcel getNextParcel(long startTimeMs, long endTimeMs) {
-        checkImmutable();
-
-        // First iterate through all records in current parcel.
-        if (mCurrentParcel != null) {
-            if (mCurrentParcel.dataPosition() < mCurrentParcelEnd) {
-                // There are more records in current parcel.
-                return mCurrentParcel;
-            } else if (mHistoryBuffer == mCurrentParcel) {
-                // finished iterate through all history files and history buffer.
-                return null;
-            } else if (mHistoryParcels == null
-                    || !mHistoryParcels.contains(mCurrentParcel)) {
-                // current parcel is from history file.
-                mCurrentParcel.recycle();
-            }
-        }
-
-        if (mStore != null) {
-            BatteryHistoryFragment next = mStore.getNextFragment(mCurrentFragment, startTimeMs,
-                    endTimeMs);
-            while (next != null) {
-                mCurrentParcel = null;
-                mCurrentParcelEnd = 0;
-                final Parcel p = Parcel.obtain();
-                if (readFragmentToParcel(p, next)) {
-                    int bufSize = p.readInt();
-                    int curPos = p.dataPosition();
-                    mCurrentParcelEnd = curPos + bufSize;
-                    mCurrentParcel = p;
-                    if (curPos < mCurrentParcelEnd) {
-                        mCurrentFragment = next;
-                        return mCurrentParcel;
-                    }
-                } else {
-                    p.recycle();
-                }
-                next = mStore.getNextFragment(next, startTimeMs, endTimeMs);
-            }
-        }
-
-        // mHistoryParcels is created when BatteryStatsImpl object is created from deserialization
-        // of a parcel, such as Settings app or checkin file.
-        if (mHistoryParcels != null) {
-            while (mParcelIndex < mHistoryParcels.size()) {
-                final Parcel p = mHistoryParcels.get(mParcelIndex++);
-                if (!verifyVersion(p)) {
-                    continue;
-                }
-                // skip monotonic time field.
-                p.readLong();
-                // skip monotonic end time field
-                p.readLong();
-                // skip monotonic size field
-                p.readLong();
-
-                final int bufSize = p.readInt();
-                final int curPos = p.dataPosition();
-                mCurrentParcelEnd = curPos + bufSize;
-                mCurrentParcel = p;
-                if (curPos < mCurrentParcelEnd) {
-                    return mCurrentParcel;
-                }
-            }
-        }
-
-        // finished iterator through history files (except the last one), now history buffer.
-        if (mHistoryBuffer.dataSize() <= 0) {
-            // buffer is empty.
-            return null;
-        }
-        mHistoryBuffer.setDataPosition(0);
-        mCurrentParcel = mHistoryBuffer;
-        mCurrentParcelEnd = mCurrentParcel.dataSize();
-        return mCurrentParcel;
-    }
-
-    private void checkImmutable() {
+    Queue<BatteryHistoryParcelContainer> getParcelContainers(long startTimeMs, long endTimeMs) {
         if (mMutable) {
             throw new IllegalStateException("Iterating over a mutable battery history");
         }
+
+        if (endTimeMs == MonotonicClock.UNDEFINED || endTimeMs == 0) {
+            endTimeMs = Long.MAX_VALUE;
+        }
+
+        Queue<BatteryHistoryParcelContainer> containers = new ArrayDeque<>();
+
+        if (mStore != null) {
+            List<BatteryHistoryFragment> fragments = mStore.getFragments();
+            for (int i = 0; i < fragments.size(); i++) {
+                BatteryHistoryFragment fragment = fragments.get(i);
+                if (fragment.monotonicTimeMs >= endTimeMs) {
+                    break;
+                }
+
+                if (fragment.monotonicTimeMs >= startTimeMs && fragment != mActiveFragment) {
+                    containers.add(new BatteryHistoryParcelContainer(fragment));
+                }
+            }
+        }
+
+        if (mHistoryParcels != null) {
+            for (int i = 0; i < mHistoryParcels.size(); i++) {
+                final Parcel p = mHistoryParcels.get(i);
+                if (!verifyVersion(p)) {
+                    continue;
+                }
+
+                long monotonicStartTime = p.readLong();
+                if (monotonicStartTime >= endTimeMs) {
+                    continue;
+                }
+
+                long monotonicEndTime = p.readLong();
+                if (monotonicEndTime < startTimeMs) {
+                    continue;
+                }
+
+                // skip monotonic size field
+                p.readLong();
+                // skip buffer size field
+                p.readInt();
+
+                containers.add(new BatteryHistoryParcelContainer(p, monotonicStartTime));
+            }
+        }
+
+        if (mHistoryBufferStartTime < endTimeMs) {
+            mHistoryBuffer.setDataPosition(0);
+            containers.add(
+                    new BatteryHistoryParcelContainer(mHistoryBuffer, mHistoryBufferStartTime));
+        }
+        return containers;
     }
 
     /**
@@ -818,21 +837,6 @@
     }
 
     /**
-     * Extracts the monotonic time, as per {@link MonotonicClock}, from the supplied battery history
-     * buffer.
-     */
-    public long getHistoryBufferStartTime(Parcel p) {
-        int pos = p.dataPosition();
-        p.setDataPosition(0);
-        p.readInt();        // Skip the version field
-        long monotonicTime = p.readLong();
-        p.readLong();       // Skip monotonic end time field
-        p.readLong();       // Skip monotonic size field
-        p.setDataPosition(pos);
-        return monotonicTime;
-    }
-
-    /**
      * Writes the battery history contents for persistence.
      */
     public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
index 38398b4..09f9b0bf 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -24,6 +24,7 @@
 import android.util.SparseArray;
 
 import java.util.Iterator;
+import java.util.Queue;
 
 /**
  * An iterator for {@link BatteryStats.HistoryItem}'s.
@@ -48,7 +49,10 @@
     private long mBaseMonotonicTime;
     private long mBaseTimeUtc;
     private int mItemIndex = 0;
-    private int mMaxHistoryItems;
+    private final int mMaxHistoryItems;
+    private int mParcelDataPosition;
+
+    private Queue<BatteryStatsHistory.BatteryHistoryParcelContainer> mParcelContainers;
 
     public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history, long startTimeMs,
             long endTimeMs) {
@@ -62,7 +66,11 @@
     @Override
     public boolean hasNext() {
         if (!mNextItemReady) {
-            advance();
+            if (!advance()) {
+                mHistoryItem = null;
+                close();
+            }
+            mNextItemReady = true;
         }
 
         return mHistoryItem != null;
@@ -75,35 +83,48 @@
     @Override
     public BatteryStats.HistoryItem next() {
         if (!mNextItemReady) {
-            advance();
+            if (!advance()) {
+                mHistoryItem = null;
+                close();
+            }
         }
         mNextItemReady = false;
         return mHistoryItem;
     }
 
-    private void advance() {
-        while (true) {
-            if (mItemIndex > mMaxHistoryItems) {
-                Slog.wtfStack(TAG, "Number of battery history items is too large: " + mItemIndex);
-                break;
-            }
+    private boolean advance() {
+        if (mParcelContainers == null) {
+            mParcelContainers = mBatteryStatsHistory.getParcelContainers(mStartTimeMs, mEndTimeMs);
+        }
 
-            Parcel p = mBatteryStatsHistory.getNextParcel(mStartTimeMs, mEndTimeMs);
-            if (p == null) {
-                break;
+        BatteryStatsHistory.BatteryHistoryParcelContainer container;
+        while ((container = mParcelContainers.peek()) != null) {
+            Parcel p = container.getParcel();
+            if (p == null || p.dataPosition() >= p.dataSize()) {
+                container.close();
+                mParcelContainers.remove();
+                mParcelDataPosition = 0;
+                continue;
             }
 
             if (!mTimeInitialized) {
-                mBaseMonotonicTime = mBatteryStatsHistory.getHistoryBufferStartTime(p);
+                mBaseMonotonicTime = container.getMonotonicStartTime();
                 mHistoryItem.time = mBaseMonotonicTime;
                 mTimeInitialized = true;
             }
 
             try {
                 readHistoryDelta(p, mHistoryItem);
+                int dataPosition = p.dataPosition();
+                if (dataPosition <= mParcelDataPosition) {
+                    Slog.wtf(TAG, "Corrupted battery history, parcel is not progressing: "
+                            + dataPosition + " of " + p.dataSize());
+                    return false;
+                }
+                mParcelDataPosition = dataPosition;
             } catch (Throwable t) {
                 Slog.wtf(TAG, "Corrupted battery history", t);
-                break;
+                return false;
             }
 
             if (mHistoryItem.cmd == BatteryStats.HistoryItem.CMD_CURRENT_TIME
@@ -111,21 +132,24 @@
                 mBaseTimeUtc = mHistoryItem.currentTime - (mHistoryItem.time - mBaseMonotonicTime);
             }
 
+            if (mHistoryItem.time < mStartTimeMs) {
+                continue;
+            }
+
+            if (mEndTimeMs != 0 && mEndTimeMs != MonotonicClock.UNDEFINED
+                    && mHistoryItem.time >= mEndTimeMs) {
+                return false;
+            }
+
+            if (mItemIndex++ > mMaxHistoryItems) {
+                Slog.wtfStack(TAG, "Number of battery history items is too large: " + mItemIndex);
+                return false;
+            }
+
             mHistoryItem.currentTime = mBaseTimeUtc + (mHistoryItem.time - mBaseMonotonicTime);
-
-            if (mEndTimeMs != 0 && mHistoryItem.time >= mEndTimeMs) {
-                break;
-            }
-            if (mHistoryItem.time >= mStartTimeMs) {
-                mItemIndex++;
-                mNextItemReady = true;
-                return;
-            }
+            return true;
         }
-
-        mHistoryItem = null;
-        mNextItemReady = true;
-        close();
+        return false;
     }
 
     private void readHistoryDelta(Parcel src, BatteryStats.HistoryItem cur) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index e20a52b..3d81e4f 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -120,6 +120,7 @@
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
+import com.android.window.flags.Flags;
 
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -1003,7 +1004,8 @@
     public void onWindowSystemUiVisibilityChanged(int visible) {
         updateColorViews(null /* insets */, true /* animate */);
 
-        if (mStatusGuard != null && mStatusGuard.getVisibility() == VISIBLE) {
+        if (!Flags.actionModeEdgeToEdge()
+                && mStatusGuard != null && mStatusGuard.getVisibility() == VISIBLE) {
             updateStatusGuardColor();
         }
     }
@@ -1040,7 +1042,7 @@
         }
         mFrameOffsets.set(insets.getSystemWindowInsetsAsRect());
         insets = updateColorViews(insets, true /* animate */);
-        insets = updateStatusGuard(insets);
+        insets = updateActionModeInsets(insets);
         if (getForeground() != null) {
             drawableChanged();
         }
@@ -1592,7 +1594,7 @@
         }
     }
 
-    private WindowInsets updateStatusGuard(WindowInsets insets) {
+    private WindowInsets updateActionModeInsets(WindowInsets insets) {
         boolean showStatusGuard = false;
         // Show the status guard when the non-overlay contextual action bar is showing
         if (mPrimaryActionModeView != null) {
@@ -1608,54 +1610,78 @@
                     final Rect rect = mTempRect;
 
                     // Apply the insets that have not been applied by the contentParent yet.
-                    WindowInsets innerInsets =
+                    final WindowInsets innerInsets =
                             mWindow.mContentParent.computeSystemWindowInsets(insets, rect);
-                    int newTopMargin = innerInsets.getSystemWindowInsetTop();
-                    int newLeftMargin = innerInsets.getSystemWindowInsetLeft();
-                    int newRightMargin = innerInsets.getSystemWindowInsetRight();
+                    final boolean consumesSystemWindowInsetsTop;
+                    if (Flags.actionModeEdgeToEdge()) {
+                        final Insets newPadding = innerInsets.getSystemWindowInsets();
+                        final Insets newMargin = innerInsets.getInsets(
+                                WindowInsets.Type.navigationBars());
 
-                    // Must use root window insets for the guard, because the color views consume
-                    // the navigation bar inset if the window does not request LAYOUT_HIDE_NAV - but
-                    // the status guard is attached at the root.
-                    WindowInsets rootInsets = getRootWindowInsets();
-                    int newGuardLeftMargin = rootInsets.getSystemWindowInsetLeft();
-                    int newGuardRightMargin = rootInsets.getSystemWindowInsetRight();
+                        // Don't extend into navigation bar area so the width can align with status
+                        // bar color view.
+                        if (mlp.leftMargin != newMargin.left
+                                || mlp.rightMargin != newMargin.right) {
+                            mlpChanged = true;
+                            mlp.leftMargin = newMargin.left;
+                            mlp.rightMargin = newMargin.right;
+                        }
 
-                    if (mlp.topMargin != newTopMargin || mlp.leftMargin != newLeftMargin
-                            || mlp.rightMargin != newRightMargin) {
-                        mlpChanged = true;
-                        mlp.topMargin = newTopMargin;
-                        mlp.leftMargin = newLeftMargin;
-                        mlp.rightMargin = newRightMargin;
-                    }
+                        mPrimaryActionModeView.setPadding(
+                                newPadding.left - newMargin.left,
+                                newPadding.top,
+                                newPadding.right - newMargin.right,
+                                0);
+                        consumesSystemWindowInsetsTop = newPadding.top > 0;
+                    } else {
+                        int newTopMargin = innerInsets.getSystemWindowInsetTop();
+                        int newLeftMargin = innerInsets.getSystemWindowInsetLeft();
+                        int newRightMargin = innerInsets.getSystemWindowInsetRight();
 
-                    if (newTopMargin > 0 && mStatusGuard == null) {
-                        mStatusGuard = new View(mContext);
-                        mStatusGuard.setVisibility(GONE);
-                        final LayoutParams lp = new LayoutParams(MATCH_PARENT,
-                                mlp.topMargin, Gravity.LEFT | Gravity.TOP);
-                        lp.leftMargin = newGuardLeftMargin;
-                        lp.rightMargin = newGuardRightMargin;
-                        addView(mStatusGuard, indexOfChild(mStatusColorViewState.view), lp);
-                    } else if (mStatusGuard != null) {
-                        final LayoutParams lp = (LayoutParams)
-                                mStatusGuard.getLayoutParams();
-                        if (lp.height != mlp.topMargin || lp.leftMargin != newGuardLeftMargin
-                                || lp.rightMargin != newGuardRightMargin) {
-                            lp.height = mlp.topMargin;
+                        // Must use root window insets for the guard, because the color views
+                        // consume the navigation bar inset if the window does not request
+                        // LAYOUT_HIDE_NAV - but the status guard is attached at the root.
+                        WindowInsets rootInsets = getRootWindowInsets();
+                        int newGuardLeftMargin = rootInsets.getSystemWindowInsetLeft();
+                        int newGuardRightMargin = rootInsets.getSystemWindowInsetRight();
+
+                        if (mlp.topMargin != newTopMargin || mlp.leftMargin != newLeftMargin
+                                || mlp.rightMargin != newRightMargin) {
+                            mlpChanged = true;
+                            mlp.topMargin = newTopMargin;
+                            mlp.leftMargin = newLeftMargin;
+                            mlp.rightMargin = newRightMargin;
+                        }
+
+                        if (newTopMargin > 0 && mStatusGuard == null) {
+                            mStatusGuard = new View(mContext);
+                            mStatusGuard.setVisibility(GONE);
+                            final LayoutParams lp = new LayoutParams(MATCH_PARENT,
+                                    mlp.topMargin, Gravity.LEFT | Gravity.TOP);
                             lp.leftMargin = newGuardLeftMargin;
                             lp.rightMargin = newGuardRightMargin;
-                            mStatusGuard.setLayoutParams(lp);
+                            addView(mStatusGuard, indexOfChild(mStatusColorViewState.view), lp);
+                        } else if (mStatusGuard != null) {
+                            final LayoutParams lp = (LayoutParams)
+                                    mStatusGuard.getLayoutParams();
+                            if (lp.height != mlp.topMargin || lp.leftMargin != newGuardLeftMargin
+                                    || lp.rightMargin != newGuardRightMargin) {
+                                lp.height = mlp.topMargin;
+                                lp.leftMargin = newGuardLeftMargin;
+                                lp.rightMargin = newGuardRightMargin;
+                                mStatusGuard.setLayoutParams(lp);
+                            }
                         }
-                    }
 
-                    // The action mode's theme may differ from the app, so
-                    // always show the status guard above it if we have one.
-                    showStatusGuard = mStatusGuard != null;
+                        // The action mode's theme may differ from the app, so
+                        // always show the status guard above it if we have one.
+                        showStatusGuard = mStatusGuard != null;
 
-                    if (showStatusGuard && mStatusGuard.getVisibility() != VISIBLE) {
-                        // If it wasn't previously shown, the color may be stale
-                        updateStatusGuardColor();
+                        if (showStatusGuard && mStatusGuard.getVisibility() != VISIBLE) {
+                            // If it wasn't previously shown, the color may be stale
+                            updateStatusGuardColor();
+                        }
+                        consumesSystemWindowInsetsTop = showStatusGuard;
                     }
 
                     // We only need to consume the insets if the action
@@ -1664,14 +1690,16 @@
                     // screen_simple_overlay_action_mode.xml).
                     final boolean nonOverlay = (mWindow.getLocalFeaturesPrivate()
                             & (1 << Window.FEATURE_ACTION_MODE_OVERLAY)) == 0;
-                    if (nonOverlay && showStatusGuard) {
+                    if (nonOverlay && consumesSystemWindowInsetsTop) {
                         insets = insets.inset(0, insets.getSystemWindowInsetTop(), 0, 0);
                     }
                 } else {
-                    // reset top margin
-                    if (mlp.topMargin != 0 || mlp.leftMargin != 0 || mlp.rightMargin != 0) {
-                        mlpChanged = true;
-                        mlp.topMargin = 0;
+                    if (!Flags.actionModeEdgeToEdge()) {
+                        // reset top margin
+                        if (mlp.topMargin != 0 || mlp.leftMargin != 0 || mlp.rightMargin != 0) {
+                            mlpChanged = true;
+                            mlp.topMargin = 0;
+                        }
                     }
                 }
                 if (mlpChanged) {
@@ -1679,7 +1707,7 @@
                 }
             }
         }
-        if (mStatusGuard != null) {
+        if (!Flags.actionModeEdgeToEdge() && mStatusGuard != null) {
             mStatusGuard.setVisibility(showStatusGuard ? VISIBLE : GONE);
         }
         return insets;
@@ -2183,7 +2211,7 @@
         for (int i = getChildCount() - 1; i >= 0; i--) {
             View v = getChildAt(i);
             if (v != mStatusColorViewState.view && v != mNavigationColorViewState.view
-                    && v != mStatusGuard) {
+                    && (Flags.actionModeEdgeToEdge() || v != mStatusGuard)) {
                 removeViewAt(i);
             }
         }
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index 2d98994..6f7e5ad 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -79,6 +79,7 @@
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.UUID;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -864,5 +865,24 @@
             throw new RuntimeException("Both mMessageString and mMessageHash should never be null");
         }
     }
+
+    /**
+     * This is only used by unit tests to wait until {@link #connectToConfigurationService} is
+     * done. Because unit tests are sensitive to concurrent accesses.
+     */
+    @VisibleForTesting
+    public static void waitForInitialization() {
+        final IProtoLog currentInstance = ProtoLog.getSingleInstance();
+        if (!(currentInstance instanceof PerfettoProtoLogImpl protoLog)) {
+            return;
+        }
+        try {
+            protoLog.mBackgroundLoggingService.submit(() -> {
+                Log.i(LOG_TAG, "Complete initialization");
+            }).get();
+        } catch (InterruptedException | ExecutionException e) {
+            Log.e(LOG_TAG, "Failed to wait for tracing service", e);
+        }
+    }
 }
 
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 80fc2188..d5bb511 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -34,6 +34,7 @@
 
 import com.android.internal.R;
 import com.android.internal.view.menu.MenuBuilder;
+import com.android.window.flags.Flags;
 
 /**
  * @hide
@@ -315,12 +316,14 @@
 
         final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
 
-        int maxHeight = mContentHeight > 0 ?
-                mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
+        final int maxHeight = !Flags.actionModeEdgeToEdge() && mContentHeight > 0
+                ? mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
 
         final int verticalPadding = getPaddingTop() + getPaddingBottom();
         int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
-        final int height = maxHeight - verticalPadding;
+        final int height = Flags.actionModeEdgeToEdge()
+                ? mContentHeight > 0 ? mContentHeight : maxHeight
+                : maxHeight - verticalPadding;
         final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
 
         if (mClose != null) {
@@ -376,7 +379,8 @@
             }
             setMeasuredDimension(contentWidth, measuredHeight);
         } else {
-            setMeasuredDimension(contentWidth, maxHeight);
+            setMeasuredDimension(contentWidth, Flags.actionModeEdgeToEdge()
+                    ? mContentHeight + verticalPadding : maxHeight);
         }
     }
 
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index ff57fd4..362b79d 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -294,54 +294,24 @@
         }
     }
 
-    private boolean applyInsets(View view, Rect insets, boolean toPadding,
-            boolean left, boolean top, boolean right, boolean bottom) {
-        boolean changed;
-        if (toPadding) {
-            changed = setMargin(view, EMPTY_RECT, left, top, right, bottom);
-            changed |= setPadding(view, insets, left, top, right, bottom);
-        } else {
-            changed = setPadding(view, EMPTY_RECT, left, top, right, bottom);
-            changed |= setMargin(view, insets, left, top, right, bottom);
-        }
-        return changed;
-    }
-
-    private boolean setPadding(View view, Rect insets,
-            boolean left, boolean top, boolean right, boolean bottom) {
-        if ((left && view.getPaddingLeft() != insets.left)
-                || (top && view.getPaddingTop() != insets.top)
-                || (right && view.getPaddingRight() != insets.right)
-                || (bottom && view.getPaddingBottom() != insets.bottom)) {
-            view.setPadding(
-                    left ? insets.left : view.getPaddingLeft(),
-                    top ? insets.top : view.getPaddingTop(),
-                    right ? insets.right : view.getPaddingRight(),
-                    bottom ? insets.bottom : view.getPaddingBottom());
-            return true;
-        }
-        return false;
-    }
-
-    private boolean setMargin(View view,  Rect insets,
-            boolean left, boolean top, boolean right, boolean bottom) {
+    private boolean setMargin(View view, int left, int top, int right, int bottom) {
         final LayoutParams lp = (LayoutParams) view.getLayoutParams();
         boolean changed = false;
-        if (left && lp.leftMargin != insets.left) {
+        if (lp.leftMargin != left) {
             changed = true;
-            lp.leftMargin = insets.left;
+            lp.leftMargin = left;
         }
-        if (top && lp.topMargin != insets.top) {
+        if (lp.topMargin != top) {
             changed = true;
-            lp.topMargin = insets.top;
+            lp.topMargin = top;
         }
-        if (right && lp.rightMargin != insets.right) {
+        if (lp.rightMargin != right) {
             changed = true;
-            lp.rightMargin = insets.right;
+            lp.rightMargin = right;
         }
-        if (bottom && lp.bottomMargin != insets.bottom) {
+        if (lp.bottomMargin != bottom) {
             changed = true;
-            lp.bottomMargin = insets.bottom;
+            lp.bottomMargin = bottom;
         }
         return changed;
     }
@@ -367,12 +337,30 @@
         final Insets sysInsets = insets.getSystemWindowInsets();
         mSystemInsets.set(sysInsets.left, sysInsets.top, sysInsets.right, sysInsets.bottom);
 
-        // The top and bottom action bars are always within the content area.
-        boolean changed = applyInsets(mActionBarTop, mSystemInsets,
-                mActionBarExtendsIntoSystemInsets, true, true, true, false);
-        if (mActionBarBottom != null) {
-            changed |= applyInsets(mActionBarBottom, mSystemInsets,
-                    mActionBarExtendsIntoSystemInsets, true, false, true, true);
+        boolean changed = false;
+        if (mActionBarExtendsIntoSystemInsets) {
+            // Don't extend into navigation bar area so the width can align with status bar
+            // color view.
+            final Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars());
+            final int paddingLeft = sysInsets.left - navBarInsets.left;
+            final int paddingRight = sysInsets.right - navBarInsets.right;
+            mActionBarTop.setPadding(paddingLeft, sysInsets.top, paddingRight, 0);
+            changed |= setMargin(
+                    mActionBarTop, navBarInsets.left, 0, navBarInsets.right, 0);
+            if (mActionBarBottom != null) {
+                mActionBarBottom.setPadding(paddingLeft, 0, paddingRight, sysInsets.bottom);
+                changed |= setMargin(
+                        mActionBarBottom, navBarInsets.left, 0, navBarInsets.right, 0);
+            }
+        } else {
+            mActionBarTop.setPadding(0, 0, 0, 0);
+            changed |= setMargin(
+                    mActionBarTop, sysInsets.left, sysInsets.top, sysInsets.right, 0);
+            if (mActionBarBottom != null) {
+                mActionBarBottom.setPadding(0, 0, 0, 0);
+                changed |= setMargin(
+                        mActionBarTop, sysInsets.left, 0, sysInsets.right, sysInsets.bottom);
+            }
         }
 
         // Cannot use the result of computeSystemWindowInsets, because that consumes the
@@ -521,7 +509,12 @@
                 );
             }
         }
-        setMargin(mContent, mContentInsets, true, true, true, true);
+        setMargin(
+                mContent,
+                mContentInsets.left,
+                mContentInsets.top,
+                mContentInsets.right,
+                mContentInsets.bottom);
 
         if (!mLastInnerInsets.equals(mInnerInsets)) {
             // If the inner insets have changed, we need to dispatch this down to
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 2cca3db..3da1922 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -1178,6 +1178,7 @@
             }
             newGroup.setShowingAvatar(!mIsOneToOne && !mIsCollapsed);
             newGroup.setSingleLine(mIsCollapsed && TextUtils.isEmpty(mSummarizedContent));
+            newGroup.setIsCollapsed(mIsCollapsed);
             newGroup.setSender(sender, nameOverride);
             newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
             mGroups.add(newGroup);
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index b31a200..21bb7a9 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -103,6 +103,7 @@
     private boolean mShowingAvatar = true;
     private CharSequence mSenderName;
     private boolean mSingleLine = false;
+    private boolean mIsCollapsed = false;
     private LinearLayout mContentContainer;
     private int mRequestedMaxDisplayedLines = Integer.MAX_VALUE;
     private int mSenderTextPaddingSingleLine;
@@ -451,7 +452,7 @@
     private void updateIconVisibility() {
         if (Flags.notificationsRedesignTemplates()) {
             // We don't show any icon (other than the app or person icon) in the collapsed form.
-            mMessagingIconContainer.setVisibility(mSingleLine ? GONE : VISIBLE);
+            mMessagingIconContainer.setVisibility(mIsCollapsed ? GONE : VISIBLE);
         }
     }
 
@@ -714,10 +715,18 @@
             updateMaxDisplayedLines();
             updateClipRect();
             updateSenderVisibility();
-            updateIconVisibility();
         }
     }
 
+    /**
+     * Sets whether this is in a collapsed layout or not. Certain elements like icons are not shown
+     * when the notification is collapsed.
+     */
+    public void setIsCollapsed(boolean isCollapsed) {
+        mIsCollapsed = isCollapsed;
+        updateIconVisibility();
+    }
+
     public boolean isSingleLine() {
         return mSingleLine;
     }
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 9fe2de8..4cc4b38 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -551,6 +551,7 @@
             }
             newGroup.setSingleLine(mIsCollapsed && TextUtils.isEmpty(mSummarizedContent));
             newGroup.setShowingAvatar(!mIsCollapsed);
+            newGroup.setIsCollapsed(mIsCollapsed);
             newGroup.setSender(sender, nameOverride);
             newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
             mGroups.add(newGroup);
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index dd12f69..42b1bdb 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -129,6 +129,16 @@
         updateExpandedState();
     }
 
+    /**
+     * Adjust the padding at the start of the view based on the layout direction (RTL/LTR).
+     * This is needed because RemoteViews don't have an equivalent for
+     * {@link this#setPaddingRelative}.
+     */
+    @RemotableViewMethod
+    public void setStartPadding(int startPadding) {
+        setPaddingRelative(startPadding, getPaddingTop(), getPaddingEnd(), getPaddingBottom());
+    }
+
     private void updateExpandedState() {
         int drawableId;
         int contentDescriptionId;
diff --git a/core/java/com/android/internal/widget/PeopleHelper.java b/core/java/com/android/internal/widget/PeopleHelper.java
index 3f5b4a0..3aa4c84 100644
--- a/core/java/com/android/internal/widget/PeopleHelper.java
+++ b/core/java/com/android/internal/widget/PeopleHelper.java
@@ -110,7 +110,7 @@
     @NonNull
     public Icon createAvatarSymbol(@NonNull CharSequence name, @NonNull String symbol,
             @ColorInt int layoutColor) {
-        if (symbol.isEmpty() || TextUtils.isDigitsOnly(symbol)
+        if (symbol == null || symbol.isEmpty() || TextUtils.isDigitsOnly(symbol)
                 || SPECIAL_CHAR_PATTERN.matcher(symbol).find()) {
             Icon avatarIcon = Icon.createWithResource(mContext, R.drawable.messaging_user);
             avatarIcon.setTint(findColor(name, layoutColor));
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index 36c08a5..95bab54 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -231,12 +231,6 @@
     }
 }
 
-// This method is deprecated and should be removed when it is no longer needed by the
-// robolectric tests.
-static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr) {
-    nativeClose(env, clazz, connectionPtr, false);
-}
-
 static void sqliteCustomScalarFunctionCallback(sqlite3_context *context,
         int argc, sqlite3_value **argv) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -974,8 +968,6 @@
             (void*)nativeOpen },
     { "nativeClose", "(JZ)V",
       (void*) static_cast<void(*)(JNIEnv*,jclass,jlong,jboolean)>(nativeClose) },
-    { "nativeClose", "(J)V",
-      (void*) static_cast<void(*)(JNIEnv*,jclass,jlong)>(nativeClose) },
     { "nativeRegisterCustomScalarFunction", "(JLjava/lang/String;Ljava/util/function/UnaryOperator;)V",
             (void*)nativeRegisterCustomScalarFunction },
     { "nativeRegisterCustomAggregateFunction", "(JLjava/lang/String;Ljava/util/function/BinaryOperator;)V",
diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp
index 48c92c8..886b9f1 100644
--- a/core/jni/com_android_internal_content_FileSystemUtils.cpp
+++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp
@@ -201,8 +201,8 @@
     return true;
 }
 
-bool getLoadSegmentPhdrs(const char *filePath, const uint64_t offset,
-                         std::vector<Elf64_Phdr> &programHeaders) {
+read_elf_status_t getLoadSegmentPhdrs(const char *filePath, const uint64_t offset,
+                                      std::vector<Elf64_Phdr> &programHeaders) {
     // Open Elf file
     Elf64_Ehdr ehdr;
     std::ifstream inputStream(filePath, std::ifstream::in);
@@ -212,13 +212,13 @@
     // read executable headers
     inputStream.read((char *)&ehdr, sizeof(ehdr));
     if (!inputStream.good()) {
-        return false;
+        return ELF_READ_ERROR;
     }
 
-    // only consider elf64 for punching holes
+    // only consider ELF64 files
     if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) {
         ALOGW("Provided file is not ELF64");
-        return false;
+        return ELF_IS_NOT_64_BIT;
     }
 
     // read the program headers from elf file
@@ -229,7 +229,7 @@
     uint64_t phOffset;
     if (__builtin_add_overflow(offset, programHeaderOffset, &phOffset)) {
         ALOGE("Overflow occurred when calculating phOffset");
-        return false;
+        return ELF_READ_ERROR;
     }
     inputStream.seekg(phOffset);
 
@@ -237,7 +237,7 @@
         Elf64_Phdr header;
         inputStream.read((char *)&header, sizeof(header));
         if (!inputStream.good()) {
-            return false;
+            return ELF_READ_ERROR;
         }
 
         if (header.p_type != PT_LOAD) {
@@ -246,13 +246,14 @@
         programHeaders.push_back(header);
     }
 
-    return true;
+    return ELF_READ_OK;
 }
 
 bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
     std::vector<Elf64_Phdr> programHeaders;
-    if (!getLoadSegmentPhdrs(filePath, offset, programHeaders)) {
-        ALOGE("Failed to read program headers from ELF file.");
+    read_elf_status_t status = getLoadSegmentPhdrs(filePath, offset, programHeaders);
+    if (status != ELF_READ_OK) {
+        ALOGE("Failed to read program headers from 64 bit ELF file.");
         return false;
     }
     return punchHoles(filePath, offset, programHeaders);
diff --git a/core/jni/com_android_internal_content_FileSystemUtils.h b/core/jni/com_android_internal_content_FileSystemUtils.h
index 4a95686c..c4dc111 100644
--- a/core/jni/com_android_internal_content_FileSystemUtils.h
+++ b/core/jni/com_android_internal_content_FileSystemUtils.h
@@ -22,6 +22,12 @@
 
 namespace android {
 
+enum read_elf_status_t {
+    ELF_IS_NOT_64_BIT = -2,
+    ELF_READ_ERROR = -1,
+    ELF_READ_OK = 0,
+};
+
 /*
  * This function deallocates space used by zero padding at the end of LOAD segments in given
  * uncompressed ELF file. Read ELF headers and find out the offset and sizes of LOAD segments.
@@ -39,10 +45,10 @@
 bool punchHolesInZip(const char* filePath, uint64_t offset, uint16_t extraFieldLen);
 
 /*
- * This function reads program headers from ELF file. ELF can be specified with file path directly
- * or it should be at offset inside Apk. Program headers passed to function is populated.
+ * This function reads program headers from 64 bit ELF file. ELF can be specified with file path
+ * directly or it should be at offset inside Apk. Program headers passed to function is populated.
  */
-bool getLoadSegmentPhdrs(const char* filePath, const uint64_t offset,
-                         std::vector<Elf64_Phdr>& programHeaders);
+read_elf_status_t getLoadSegmentPhdrs(const char* filePath, const uint64_t offset,
+                                      std::vector<Elf64_Phdr>& programHeaders);
 
 } // namespace android
\ No newline at end of file
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 14132e6..7cf523f 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -640,7 +640,17 @@
 
 static jint checkLoadSegmentAlignment(const char* fileName, off64_t offset) {
     std::vector<Elf64_Phdr> programHeaders;
-    if (!getLoadSegmentPhdrs(fileName, offset, programHeaders)) {
+    read_elf_status_t status = getLoadSegmentPhdrs(fileName, offset, programHeaders);
+    // Ignore the ELFs which are not 64 bit.
+    if (status == ELF_IS_NOT_64_BIT) {
+        ALOGW("ELF file is not 64 Bit");
+        // PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED is equivalent of skipping the current file.
+        // on return, flag is OR'ed with flags from other ELF files. If some app has 32 bit ELF in
+        // 64 bit directory, alignment of that ELF will be ignored.
+        return PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
+    }
+
+    if (status == ELF_READ_ERROR) {
         ALOGE("Failed to read program headers from ELF file.");
         return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
     }
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index 746740b..1e8da73 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -280,12 +280,18 @@
     return string(chars.c_str());
 }
 
-static void loadIcuData(string icuPath) {
+static void loadIcuData(JNIEnv* env, string icuPath) {
     void* addr = mmapFile(icuPath.c_str());
+    if (addr == nullptr) {
+        jniThrowRuntimeException(env, "Failed to map the ICU data file.");
+    }
     UErrorCode err = U_ZERO_ERROR;
     udata_setCommonData(addr, &err);
     if (err != U_ZERO_ERROR) {
-        ALOGE("Unable to load ICU data\n");
+        jniThrowRuntimeException(env,
+                                 format("udata_setCommonData failed with error code {}",
+                                        u_errorName(err))
+                                         .c_str());
     }
 }
 
@@ -296,12 +302,12 @@
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     string icuPath = base::GetProperty("ro.icu.data.path", "");
     if (!icuPath.empty()) {
-        loadIcuData(icuPath);
+        loadIcuData(env, icuPath);
     } else {
         // fallback to read from java.lang.System.getProperty
         string icuPathFromJava = getJavaProperty(env, "icu.data.path");
         if (!icuPathFromJava.empty()) {
-            loadIcuData(icuPathFromJava);
+            loadIcuData(env, icuPathFromJava);
         }
     }
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index ac4bac6..1caa9e7 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -112,7 +112,8 @@
         optional SettingProto autoclick_ignore_minor_cursor_movement = 63 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto autoclick_panel_position = 64 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto autoclick_revert_to_left_click = 65 [ (android.privacy).dest = DEST_AUTOMATIC ];
-
+        // Setting for accessibility magnification for cursor following mode.
+        optional SettingProto accessibility_magnification_cursor_following_mode = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 36b65ba..e16ce98 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -9292,9 +9292,6 @@
                 <action android:name="android.intent.action.UPDATE_PINS" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
             </intent-filter>
-            <intent-filter>
-                <action android:name="android.intent.action.BOOT_COMPLETED" />
-            </intent-filter>
         </receiver>
 
         <receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver"
diff --git a/core/res/res/drawable/accessibility_autoclick_scroll_down.xml b/core/res/res/drawable/accessibility_autoclick_scroll_down.xml
new file mode 100644
index 0000000..13f1ba0
--- /dev/null
+++ b/core/res/res/drawable/accessibility_autoclick_scroll_down.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@color/materialColorPrimary"
+        android:pathData="M12,20l8,-8h-5V4h-6v8H4z"/>
+</vector>
diff --git a/core/res/res/drawable/accessibility_autoclick_scroll_exit.xml b/core/res/res/drawable/accessibility_autoclick_scroll_exit.xml
new file mode 100644
index 0000000..e53301f
--- /dev/null
+++ b/core/res/res/drawable/accessibility_autoclick_scroll_exit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@color/materialColorPrimary"
+        android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+</vector>
diff --git a/core/res/res/drawable/accessibility_autoclick_scroll_left.xml b/core/res/res/drawable/accessibility_autoclick_scroll_left.xml
new file mode 100644
index 0000000..39475bc
--- /dev/null
+++ b/core/res/res/drawable/accessibility_autoclick_scroll_left.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@color/materialColorPrimary"
+        android:pathData="M4,12l8,8v-5h8v-6h-8V4z"/>
+</vector>
diff --git a/core/res/res/drawable/accessibility_autoclick_scroll_right.xml b/core/res/res/drawable/accessibility_autoclick_scroll_right.xml
new file mode 100644
index 0000000..bbd7b2a
--- /dev/null
+++ b/core/res/res/drawable/accessibility_autoclick_scroll_right.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@color/materialColorPrimary"
+        android:pathData="M20,12l-8,-8v5H4v6h8v5z"/>
+</vector>
diff --git a/core/res/res/drawable/accessibility_autoclick_scroll_up.xml b/core/res/res/drawable/accessibility_autoclick_scroll_up.xml
new file mode 100644
index 0000000..2e2c245
--- /dev/null
+++ b/core/res/res/drawable/accessibility_autoclick_scroll_up.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@color/materialColorPrimary"
+        android:pathData="M12,4L4,12h5v8h6v-8h5z"/>
+</vector>
diff --git a/core/res/res/layout/accessibility_autoclick_scroll_panel.xml b/core/res/res/layout/accessibility_autoclick_scroll_panel.xml
new file mode 100644
index 0000000..1e093bb
--- /dev/null
+++ b/core/res/res/layout/accessibility_autoclick_scroll_panel.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/accessibility_autoclick_scroll_panel"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"
+    android:background="@drawable/accessibility_autoclick_type_panel_rounded_background"
+    android:orientation="vertical"
+    android:padding="16dp">
+
+    <!-- Up arrow -->
+    <LinearLayout
+        android:id="@+id/scroll_up_layout"
+        style="@style/AccessibilityAutoclickScrollPanelButtonLayoutStyle"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginBottom="@dimen/accessibility_autoclick_type_panel_button_spacing">
+        <ImageButton
+            android:id="@+id/scroll_up"
+            style="@style/AccessibilityAutoclickScrollPanelImageButtonStyle"
+            android:contentDescription="@string/accessibility_autoclick_scroll_up"
+            android:src="@drawable/accessibility_autoclick_scroll_up" />
+    </LinearLayout>
+
+    <!-- Middle row: Left, Exit, Right -->
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal">
+
+        <LinearLayout
+            android:id="@+id/scroll_left_layout"
+            style="@style/AccessibilityAutoclickScrollPanelButtonLayoutStyle"
+            android:layout_marginEnd="@dimen/accessibility_autoclick_type_panel_button_spacing">
+            <ImageButton
+                android:id="@+id/scroll_left"
+                style="@style/AccessibilityAutoclickScrollPanelImageButtonStyle"
+                android:contentDescription="@string/accessibility_autoclick_scroll_left"
+                android:src="@drawable/accessibility_autoclick_scroll_left" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/scroll_exit_layout"
+            style="@style/AccessibilityAutoclickScrollPanelButtonLayoutStyle"
+            android:layout_marginEnd="@dimen/accessibility_autoclick_type_panel_button_spacing">
+            <ImageButton
+                android:id="@+id/scroll_exit"
+                style="@style/AccessibilityAutoclickScrollPanelImageButtonStyle"
+                android:contentDescription="@string/accessibility_autoclick_scroll_exit"
+                android:src="@drawable/ic_close" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/scroll_right_layout"
+            style="@style/AccessibilityAutoclickScrollPanelButtonLayoutStyle">
+            <ImageButton
+                android:id="@+id/scroll_right"
+                style="@style/AccessibilityAutoclickScrollPanelImageButtonStyle"
+                android:contentDescription="@string/accessibility_autoclick_scroll_right"
+                android:src="@drawable/accessibility_autoclick_scroll_right" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <!-- Down arrow -->
+    <LinearLayout
+        android:id="@+id/scroll_down_layout"
+        style="@style/AccessibilityAutoclickScrollPanelButtonLayoutStyle"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/accessibility_autoclick_type_panel_button_spacing">
+        <ImageButton
+            android:id="@+id/scroll_down"
+            style="@style/AccessibilityAutoclickScrollPanelImageButtonStyle"
+            android:contentDescription="@string/accessibility_autoclick_scroll_down"
+            android:src="@drawable/accessibility_autoclick_scroll_down" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/notification_2025_expand_button.xml b/core/res/res/layout/notification_2025_expand_button.xml
index 1c36754..8ba844a 100644
--- a/core/res/res/layout/notification_2025_expand_button.xml
+++ b/core/res/res/layout/notification_2025_expand_button.xml
@@ -15,6 +15,7 @@
   -->
 
 <!-- extends FrameLayout -->
+<!-- Note: The button's padding may be dynamically adjusted in code -->
 <com.android.internal.widget.NotificationExpandButton
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/expand_button"
diff --git a/core/res/res/layout/notification_2025_right_icon.xml b/core/res/res/layout/notification_2025_right_icon.xml
new file mode 100644
index 0000000..24d381d
--- /dev/null
+++ b/core/res/res/layout/notification_2025_right_icon.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<!-- Large icon to be used in expanded notification layouts. -->
+<com.android.internal.widget.CachingIconView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/right_icon"
+    android:layout_width="@dimen/notification_right_icon_size"
+    android:layout_height="@dimen/notification_right_icon_size"
+    android:layout_gravity="top|end"
+    android:layout_marginEnd="@dimen/notification_2025_right_icon_expanded_margin_end"
+    android:layout_marginVertical="@dimen/notification_2025_right_icon_vertical_margin"
+    android:background="@drawable/notification_large_icon_outline"
+    android:clipToOutline="true"
+    android:importantForAccessibility="no"
+    android:scaleType="centerCrop"
+    android:maxDrawableWidth="@dimen/notification_right_icon_size"
+    android:maxDrawableHeight="@dimen/notification_right_icon_size"
+    />
diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml
index d29b7af..63f32e3 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_base.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml
@@ -66,14 +66,17 @@
         android:orientation="horizontal"
         >
 
+        <!--
+        We use a smaller vertical margin than usual, to allow the content of custom views to
+        grow up to 48dp height when needed in collapsed notifications.
+        -->
         <LinearLayout
             android:id="@+id/notification_headerless_view_column"
             android:layout_width="0px"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
             android:layout_weight="1"
-            android:layout_marginBottom="@dimen/notification_2025_margin"
-            android:layout_marginTop="@dimen/notification_2025_margin"
+            android:layout_marginVertical="@dimen/notification_2025_reduced_margin"
             android:orientation="vertical"
             >
 
@@ -81,6 +84,7 @@
                 android:id="@+id/notification_top_line"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/notification_2025_additional_margin"
                 android:minHeight="@dimen/notification_2025_content_min_height"
                 android:clipChildren="false"
                 android:theme="@style/Theme.DeviceDefault.Notification"
@@ -118,17 +122,10 @@
                 <com.android.internal.widget.NotificationVanishingFrameLayout
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
+                    android:layout_marginBottom="@dimen/notification_2025_additional_margin"
                     android:minHeight="@dimen/notification_headerless_line_height"
                     >
-                    <!-- This is the simplest way to keep this text vertically centered without
-                     gravity="center_vertical" which causes jumpiness in expansion animations. -->
-                    <include
-                        layout="@layout/notification_2025_text"
-                        android:layout_width="match_parent"
-                        android:layout_height="@dimen/notification_text_height"
-                        android:layout_gravity="center_vertical"
-                        android:layout_marginTop="0dp"
-                        />
+                    <include layout="@layout/notification_2025_text" />
                 </com.android.internal.widget.NotificationVanishingFrameLayout>
 
                 <include
@@ -146,9 +143,8 @@
             android:layout_width="@dimen/notification_right_icon_size"
             android:layout_height="@dimen/notification_right_icon_size"
             android:layout_gravity="center_vertical|end"
-            android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-            android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-            android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+            android:layout_marginVertical="@dimen/notification_2025_right_icon_vertical_margin"
+            android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin"
             android:background="@drawable/notification_large_icon_outline"
             android:clipToOutline="true"
             android:importantForAccessibility="no"
diff --git a/core/res/res/layout/notification_2025_template_collapsed_call.xml b/core/res/res/layout/notification_2025_template_collapsed_call.xml
index ee691e4..fbea10d 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_call.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_call.xml
@@ -128,15 +128,7 @@
                             android:layout_height="wrap_content"
                             android:minHeight="@dimen/notification_headerless_line_height"
                             >
-                            <!-- This is the simplest way to keep this text vertically centered without
-                             gravity="center_vertical" which causes jumpiness in expansion animations. -->
-                            <include
-                                layout="@layout/notification_2025_text"
-                                android:layout_width="match_parent"
-                                android:layout_height="@dimen/notification_text_height"
-                                android:layout_gravity="center_vertical"
-                                android:layout_marginTop="0dp"
-                                />
+                            <include layout="@layout/notification_2025_text" />
                         </com.android.internal.widget.NotificationVanishingFrameLayout>
                     </LinearLayout>
 
@@ -147,9 +139,8 @@
                     android:layout_width="@dimen/notification_right_icon_size"
                     android:layout_height="@dimen/notification_right_icon_size"
                     android:layout_gravity="center_vertical|end"
-                    android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+                    android:layout_marginVertical="@dimen/notification_2025_right_icon_vertical_margin"
+                    android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin"
                     android:background="@drawable/notification_large_icon_outline"
                     android:clipToOutline="true"
                     android:importantForAccessibility="no"
diff --git a/core/res/res/layout/notification_2025_template_collapsed_conversation.xml b/core/res/res/layout/notification_2025_template_collapsed_conversation.xml
index f804111..a6fdcd9 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_conversation.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_conversation.xml
@@ -149,9 +149,9 @@
                     android:layout_width="@dimen/notification_right_icon_size"
                     android:layout_height="@dimen/notification_right_icon_size"
                     android:layout_gravity="center_vertical|end"
-                    android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+                    android:layout_marginTop="@dimen/notification_2025_margin"
+                    android:layout_marginBottom="@dimen/notification_2025_margin"
+                    android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin"
                     android:forceHasOverlappingRendering="false"
                     android:spacing="0dp"
                     android:clipChildren="false"
@@ -163,9 +163,8 @@
                     android:layout_width="@dimen/notification_right_icon_size"
                     android:layout_height="@dimen/notification_right_icon_size"
                     android:layout_gravity="center_vertical|end"
-                    android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+                    android:layout_marginVertical="@dimen/notification_2025_right_icon_vertical_margin"
+                    android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin"
                     android:background="@drawable/notification_large_icon_outline"
                     android:clipToOutline="true"
                     android:importantForAccessibility="no"
diff --git a/core/res/res/layout/notification_2025_template_collapsed_media.xml b/core/res/res/layout/notification_2025_template_collapsed_media.xml
index 5beab50..629af77 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_media.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_media.xml
@@ -68,14 +68,17 @@
         android:orientation="horizontal"
         >
 
+        <!--
+        We use a smaller vertical margin than usual, to allow the content of custom views to
+        grow up to 48dp height when needed in collapsed notifications.
+        -->
         <LinearLayout
             android:id="@+id/notification_headerless_view_column"
             android:layout_width="0px"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
             android:layout_weight="1"
-            android:layout_marginBottom="@dimen/notification_2025_margin"
-            android:layout_marginTop="@dimen/notification_2025_margin"
+            android:layout_marginVertical="@dimen/notification_2025_reduced_margin"
             android:orientation="vertical"
             >
 
@@ -83,6 +86,7 @@
                 android:id="@+id/notification_top_line"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/notification_2025_additional_margin"
                 android:minHeight="@dimen/notification_headerless_line_height"
                 android:clipChildren="false"
                 android:theme="@style/Theme.DeviceDefault.Notification"
@@ -119,17 +123,10 @@
 
                 <com.android.internal.widget.NotificationVanishingFrameLayout
                     android:layout_width="match_parent"
+                    android:layout_marginBottom="@dimen/notification_2025_additional_margin"
                     android:layout_height="@dimen/notification_headerless_line_height"
                     >
-                    <!-- This is the simplest way to keep this text vertically centered without
-                     gravity="center_vertical" which causes jumpiness in expansion animations. -->
-                    <include
-                        layout="@layout/notification_template_text"
-                        android:layout_width="match_parent"
-                        android:layout_height="@dimen/notification_text_height"
-                        android:layout_gravity="center_vertical"
-                        android:layout_marginTop="0dp"
-                        />
+                    <include layout="@layout/notification_2025_text" />
                 </com.android.internal.widget.NotificationVanishingFrameLayout>
 
                 <include
@@ -147,9 +144,8 @@
             android:layout_width="@dimen/notification_right_icon_size"
             android:layout_height="@dimen/notification_right_icon_size"
             android:layout_gravity="center_vertical|end"
-            android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-            android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-            android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+            android:layout_marginVertical="@dimen/notification_2025_right_icon_vertical_margin"
+            android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin"
             android:background="@drawable/notification_large_icon_outline"
             android:clipToOutline="true"
             android:importantForAccessibility="no"
diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
index d7c3263..3716fa6 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
@@ -159,9 +159,9 @@
                     android:layout_width="@dimen/notification_right_icon_size"
                     android:layout_height="@dimen/notification_right_icon_size"
                     android:layout_gravity="center_vertical|end"
-                    android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+                    android:layout_marginTop="@dimen/notification_2025_margin"
+                    android:layout_marginBottom="@dimen/notification_2025_margin"
+                    android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin"
                     android:forceHasOverlappingRendering="false"
                     android:spacing="0dp"
                     android:clipChildren="false"
@@ -173,9 +173,8 @@
                     android:layout_width="@dimen/notification_right_icon_size"
                     android:layout_height="@dimen/notification_right_icon_size"
                     android:layout_gravity="center_vertical|end"
-                    android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-                    android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+                    android:layout_marginVertical="@dimen/notification_2025_right_icon_vertical_margin"
+                    android:layout_marginStart="@dimen/notification_2025_right_icon_content_margin"
                     android:background="@drawable/notification_large_icon_outline"
                     android:clipToOutline="true"
                     android:importantForAccessibility="no"
diff --git a/core/res/res/layout/notification_2025_template_expanded_base.xml b/core/res/res/layout/notification_2025_template_expanded_base.xml
index e12db27..8d99e47 100644
--- a/core/res/res/layout/notification_2025_template_expanded_base.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_base.xml
@@ -63,7 +63,7 @@
                     />
             </LinearLayout>
 
-            <include layout="@layout/notification_template_right_icon" />
+            <include layout="@layout/notification_2025_right_icon" />
         </FrameLayout>
 
         <ViewStub
diff --git a/core/res/res/layout/notification_2025_template_expanded_big_picture.xml b/core/res/res/layout/notification_2025_template_expanded_big_picture.xml
index fac9d1c4..e8e460d 100644
--- a/core/res/res/layout/notification_2025_template_expanded_big_picture.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_big_picture.xml
@@ -25,7 +25,7 @@
 
     <include layout="@layout/notification_2025_template_header" />
 
-    <include layout="@layout/notification_template_right_icon" />
+    <include layout="@layout/notification_2025_right_icon" />
 
     <LinearLayout
         android:id="@+id/notification_action_list_margin_target"
diff --git a/core/res/res/layout/notification_2025_template_expanded_big_text.xml b/core/res/res/layout/notification_2025_template_expanded_big_text.xml
index 4a807cb..b68db7f 100644
--- a/core/res/res/layout/notification_2025_template_expanded_big_text.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_big_text.xml
@@ -91,5 +91,5 @@
         <include layout="@layout/notification_material_action_list" />
     </com.android.internal.widget.RemeasuringLinearLayout>
 
-    <include layout="@layout/notification_template_right_icon" />
+    <include layout="@layout/notification_2025_right_icon" />
 </FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_call.xml b/core/res/res/layout/notification_2025_template_expanded_call.xml
index bbc2966..7b45b55 100644
--- a/core/res/res/layout/notification_2025_template_expanded_call.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_call.xml
@@ -68,6 +68,6 @@
 
     </com.android.internal.widget.RemeasuringLinearLayout>
 
-    <include layout="@layout/notification_template_right_icon" />
+    <include layout="@layout/notification_2025_right_icon" />
 
 </com.android.internal.widget.CallLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_conversation.xml b/core/res/res/layout/notification_2025_template_expanded_conversation.xml
index d7e8bb3..592785d 100644
--- a/core/res/res/layout/notification_2025_template_expanded_conversation.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_conversation.xml
@@ -70,6 +70,6 @@
 
     </com.android.internal.widget.RemeasuringLinearLayout>
 
-    <include layout="@layout/notification_template_right_icon" />
+    <include layout="@layout/notification_2025_right_icon" />
 
 </com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_inbox.xml b/core/res/res/layout/notification_2025_template_expanded_inbox.xml
index ccab02e..6459e1e 100644
--- a/core/res/res/layout/notification_2025_template_expanded_inbox.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_inbox.xml
@@ -130,5 +130,5 @@
             android:layout_marginTop="@dimen/notification_content_margin" />
         <include layout="@layout/notification_material_action_list" />
     </LinearLayout>
-    <include layout="@layout/notification_template_right_icon" />
+    <include layout="@layout/notification_2025_right_icon" />
 </FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_media.xml b/core/res/res/layout/notification_2025_template_expanded_media.xml
index e90ab79..801e339 100644
--- a/core/res/res/layout/notification_2025_template_expanded_media.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_media.xml
@@ -99,6 +99,6 @@
 
     </LinearLayout>
 
-    <include layout="@layout/notification_template_right_icon" />
+    <include layout="@layout/notification_2025_right_icon" />
 
 </com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_2025_template_expanded_messaging.xml b/core/res/res/layout/notification_2025_template_expanded_messaging.xml
index 20abfee..82c7152 100644
--- a/core/res/res/layout/notification_2025_template_expanded_messaging.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_messaging.xml
@@ -70,6 +70,6 @@
 
     </com.android.internal.widget.RemeasuringLinearLayout>
 
-    <include layout="@layout/notification_template_right_icon" />
+    <include layout="@layout/notification_2025_right_icon" />
 
 </com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_progress.xml b/core/res/res/layout/notification_2025_template_expanded_progress.xml
index 87ded89..2ff2527 100644
--- a/core/res/res/layout/notification_2025_template_expanded_progress.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_progress.xml
@@ -99,7 +99,7 @@
                 </LinearLayout>
             </LinearLayout>
 
-            <include layout="@layout/notification_template_right_icon" />
+            <include layout="@layout/notification_2025_right_icon" />
         </FrameLayout>
 
         <ViewStub
diff --git a/core/res/res/layout/notification_2025_text.xml b/core/res/res/layout/notification_2025_text.xml
index 474f6d2..a725de4 100644
--- a/core/res/res/layout/notification_2025_text.xml
+++ b/core/res/res/layout/notification_2025_text.xml
@@ -13,14 +13,16 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
+<!-- Note that we prefer layout_gravity="center_vertical" over gravity="center_vertical", since the
+ latter can cause jumpiness in expansion animations. -->
 <com.android.internal.widget.ImageFloatingTextView
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/Widget.DeviceDefault.Notification.Text"
     android:id="@+id/text"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_text_height"
-    android:layout_gravity="top"
-    android:layout_marginTop="@dimen/notification_text_margin_top"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/notification_text_height"
+    android:layout_gravity="center_vertical"
     android:ellipsize="end"
     android:fadingEdge="horizontal"
     android:gravity="top"
diff --git a/core/res/res/layout/notification_template_notification_progress_bar.xml b/core/res/res/layout/notification_template_notification_progress_bar.xml
index 3574896..8511d38 100644
--- a/core/res/res/layout/notification_template_notification_progress_bar.xml
+++ b/core/res/res/layout/notification_template_notification_progress_bar.xml
@@ -20,4 +20,5 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/notification_progress_tracker_height"
     style="@style/Widget.Material.Notification.NotificationProgressBar"
+    android:accessibilityLiveRegion="polite"
     />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index ae05666..9967209 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Eenhandmodus"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra donker"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Gehoortoestelle"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Outoklik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ontkoppel"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Gekoppel"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktief"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Vra ontsluitpatroon voordat jy ontspeld"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vra wagwoord voordat jy ontspeld"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Deur jou admin geïnstalleer.\nGaan na instellings om toegestaande toestemmings te sien"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Opgedateer deur jou administrateur"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Uitgevee deur jou administrateur"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte, sekere kenmerke en sommige netwerkverbindings af"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 19be04e..bdaf5a1 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"የአንድ እጅ ሁነታ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ተጨማሪ ደብዛዛ"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"የመስሚያ መሣሪያዎች"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ራስ-ሰር ጠቅ ማድረግ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ግንኙነት ተቋርጧል"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ተገናኝቷል"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ገቢር"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ከመንቀል በፊት የማስከፈቻ ሥርዓተ-ጥለት ጠይቅ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ከመንቀል በፊት የይለፍ ቃል ጠይቅ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"በአስተዳዳሪዎ ተጭኗል።\nየተፈቀዱ ፍቃዶችን ለማየት ወደ ቅንብሮች ይሂዱ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"እሺ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ባትሪ ቆጣቢ ጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ ዕይታዊ ውጤቶችን፣ አንዳንድ ባህሪዎችን፣ እና አንዳንድ የአውታረ መረብ ግንኙነቶችን ይገድባል ወይም ያጠፋል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 66192cb..3b0e78d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1807,8 +1807,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"وضع \"التصفح بيد واحدة\""</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"زيادة تعتيم الشاشة"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعات الأذن الطبية"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"النقر التلقائي"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"غير متّصل"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"متّصل"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"متّصل حاليًا"</string>
@@ -1970,7 +1969,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"طلب إدخال نقش فتح القفل قبل إزالة التثبيت"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"طلب إدخال كلمة المرور قبل إزالة التثبيت"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"تم التثبيت من قِبل المشرف.\nانتقِل إلى الإعدادات للاطّلاع على الأذونات الممنوحة"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة وبعض اتصالات الشبكات."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index b85be47..5d93b65 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এখন হাতেৰে ব্যৱহাৰ কৰাৰ ম’ড"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিৰিক্তভাৱে পোহৰ কমোৱাৰ সুবিধা"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"শুনাৰ ডিভাইচ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"স্বয়ংক্ৰিয়ভাৱে ক্লিক কৰাৰ সুবিধা"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"সংযোগ বিচ্ছিন্ন হ’ল"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"সংযোগ কৰা হ’ল"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"সক্ৰিয় হৈ আছে"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"আনপিন কৰাৰ পূৰ্বে আনলক আৰ্হি দিবলৈ কওক"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"আনপিন কৰাৰ পূৰ্বে পাছৱৰ্ড দিবলৈ কওক"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"আপোনাৰ প্ৰশাসকে ইনষ্টল কৰিছে।\nপ্ৰদান কৰা অনুমতিসমূহ চাবলৈ ছেটিঙলৈ যাওক"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"আপোনাৰ প্ৰশাসকে মচিছে"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট, নিৰ্দিষ্ট কিছুমান সুবিধা আৰু নেটৱৰ্কৰ সংযোগ সীমিত অথবা অফ কৰে।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index b9bd543..c6a0ade 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Birəlli rejim"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Əlavə tündləşmə"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Eşitmə cihazları"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Avtomatik klikləmə"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Bağlantı kəsildi"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Qoşuldu"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivdir"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Qrafik açar istənilsin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ayırmadan öncə parol istənilsin"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Admin quraşdırıb.\nVerilən icazələrə baxmaq üçün ayarlara keçin"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Admin tərəfindən yeniləndi"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Admin tərəfindən silindi"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Enerjiyə Qənaət rejimi Tünd temanı aktivləşdirir, habelə arxa fon fəaliyyətini, bəzi vizual effektləri, müəyyən xüsusiyyətləri və bəzi şəbəkə bağlantılarını məhdudlaşdırır, yaxud söndürür."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index a558de3..2b4dc57 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1966,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži šablon za otključavanje pre otkačinjanja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži lozinku pre otkačinjanja"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalirao je administrator.\nIdite u podešavanja da biste videli odobrene dozvole"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Potvrdi"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte, određene funkcije i neke mrežne veze."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 113be9d..8230b1c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Рэжым кіравання адной рукой"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дадатковае памяншэнне яркасці"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слыхавыя апараты"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Аўтанацісканне"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Адключана"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Падключана"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Актыўная"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запытваць узор разблакіроўкі перад адмацаваннем"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запытваць пароль перад адмацаваннем"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Усталявана адміністратарам.\nКаб паглядзець дадзеныя дазволы, перайдзіце ў налады"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Абноўлены вашым адміністратарам"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Выдалены вашым адміністратарам"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"У рэжыме энергазберажэння ўключаецца цёмная тэма і выключаюцца ці абмяжоўваюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты, пэўныя функцыі і падключэнні да сетак."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index c36940f..1b0477f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Работа с една ръка"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Допълнително затъмняване"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слухови апарати"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автоматично кликване"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Няма връзка"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Свързано"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запитване за фигура за отключване преди освобождаване"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запитване за парола преди освобождаване"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Инсталирано от администратора ви.\nОтворете настройките, за да прегледате предоставените разрешения"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Актуализирано от администратора ви"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Изтрито от администратора ви"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти, определени функции и някои връзки с мрежата."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index b79c1d7..2461a70 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এক হাতে ব্যবহার করার মোড"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিরিক্ত কম উজ্জ্বলতা"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"হিয়ারিং ডিভাইস"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"অটোক্লিক"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ডিসকানেক্ট হয়ে গেছে"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"কানেক্ট করা হয়েছে"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"অ্যাক্টিভ"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"আনপিন করার আগে আনলক প্যাটার্ন চান"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"আনপিন করার আগে পাসওয়ার্ড চান"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"আপনার অ্যাডমিন ইনস্টল করেছেন।\nঅনুমোদন করা অনুমতি দেখতে সেটিংসে যান"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"আপনার প্রশাসক আপডেট করেছেন"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, নির্দিষ্ট ফিচার ও কয়েকটি নেটওয়ার্ক কানেকশনের ব্যবহার সীমিত করে বা বন্ধ করে দেয়।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index a995746..b8d3283 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Način rada jednom rukom"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamnjenje"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni aparati"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatski klik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nije povezano"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži uzorak za otključavanje prije poništavanja kačenja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži lozinku prije nego se otkači"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalirao je vaš administrator.\nIdite u postavke da pregledate data odobrenja"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je vaš administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 62f59f2..cbfa521 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode d\'una mà"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuació extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Audiòfons"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automàtic"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconnectat"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connectat"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Actiu"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Sol·licita el patró de desbloqueig per deixar de fixar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demana la contrasenya per deixar de fixar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instal·lat per l\'administrador.\nVes a la configuració per veure els permisos concedits."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualitzat per l\'administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Suprimit per l\'administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"D\'acord"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals, determinades funcions i algunes connexions de xarxa."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 5e7a8aa..356cdc7 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jedné ruky"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Velmi tmavé zobrazení"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Naslouchátka"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatické kliknutí"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Odpojeno"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Připojeno"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivní"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Před uvolněním požádat o bezpečnostní gesto"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Před odepnutím požádat o heslo"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Nainstalováno administrátorem.\nUdělená oprávnění si můžete prohlédnout v nastavení."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizováno administrátorem"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Smazáno administrátorem"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Spořič baterie zapíná tmavý motiv a omezuje či vypíná aktivitu na pozadí, některé vizuální efekty, některé funkce a připojení k některým sítím."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ab73394..efe3e10 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndstilstand"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dæmpet belysning"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Høreapparater"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoklik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ikke forbundet"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Forbundet"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Bed om oplåsningsmønster ved deaktivering"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Bed om adgangskode inden frigørelse"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installeret af din administrator.\nGå til Indstillinger for at se de tilladelser, der er blevet givet"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Opdateret af din administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet af din administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterisparefunktionen aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden og visse visuelle effekter, funktioner og netværksforbindelser."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8bff350..fc0e9ed 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhandmodus"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradunkel"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörgeräte"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatischer Klick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nicht verbunden"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Verbunden"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Vor dem Beenden nach Entsperrungsmuster fragen"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vor dem Beenden nach Passwort fragen"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Von deinem Administrator installiert.\nRufe die Einstellungen auf, um gewährte Berechtigungen anzusehen."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Von deinem Administrator aktualisiert"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Von deinem Administrator gelöscht"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Der Energiesparmodus aktiviert das dunkle Design. Hintergrundaktivitäten, einige Funktionen und optische Effekte und manche Netzwerkverbindungen werden eingeschränkt oder deaktiviert."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0e968bd..58f5d9d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Λειτουργία ενός χεριού"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Επιπλέον μείωση φωτεινότητας"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Συσκευές ακοής"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Αυτόματο κλικ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Αποσυνδέθηκε"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Συνδέθηκε"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ενεργή"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Να γίνεται ερώτηση για το μοτίβο ξεκλειδώματος, πριν από το ξεκαρφίτσωμα"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Να γίνεται ερώτηση για τον κωδικό πρόσβασης, πριν από το ξεκαρφίτσωμα"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Εγκαταστάθηκε από τον διαχειριστή σας.\nΜεταβείτε στις ρυθμίσεις για να δείτε τις άδειες που έχουν εκχωρηθεί"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ενημερώθηκε από τον διαχειριστή σας"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Διαγράφηκε από τον διαχειριστή σας"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα και περιορίζει ή απενεργοποιεί τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ, συγκεκριμένες λειτουργίες και κάποιες συνδέσεις δικτύου."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 6c43f9a..320e639 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoclick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 99abe8b..85471d8 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1965,7 +1965,7 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to settings to view granted permissions"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
+    <string name="package_updated_device_owner" msgid="7770195449213776218">"Updated by your admin.\nGo to settings to view granted permissions"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features, and some network connections."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 99040f3..730dd3b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoclick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index cb1e92ed..a9654e5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoclick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 18cbfaa..036ecfc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo de una mano"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicitar desbloqueo para quitar fijación"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar contraseña para quitar fijación"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Tu administrador realizó la instalación.\nVe a la configuración para ver los permisos otorgados"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Tu administrador actualizó este paquete"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Tu administrador borró este paquete"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales, algunas conexiones de red y otras funciones determinadas."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 8523473..3553aea 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo Una mano"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Audífonos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir patrón de desbloqueo para dejar de fijar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar contraseña para desactivar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado por tu administrador.\nVe a Ajustes para ver los permisos concedidos."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales, ciertas funciones y algunas conexiones de red."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index a1ddf81..abecc1a 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Ühekäerežiim"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Eriti tume"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Kuuldeseadmed"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automaatklikk"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ühendus katkestatud"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ühendatud"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiivne"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Enne vabastamist küsi avamismustrit"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Enne vabastamist küsi parooli"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installis teie administraator.\nAntud õiguste vaatamiseks avage seaded"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akusäästja lülitab sisse tumeda teema ja lülitab välja taustategevused, mõned visuaalsed efektid, teatud funktsioonid ja võrguühendused või piirab neid."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index c63cfe6..64dc730 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Esku bakarreko modua"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Are ilunago"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Entzumen-gailuak"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatikoki klik egiteko eginbidea"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Deskonektatuta"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Konektatuta"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktibo"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Eskatu pasahitza aingura kendu aurretik"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Administratzaileak instalatu du.\nEmandako baimenak ikusteko, joan ezarpenetara."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Administratzaileak eguneratu du"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratzaileak ezabatu du"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Ados"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Bateria-aurreztaileak gai iluna aktibatzen du, eta atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk mugatzen edo desaktibatzen ditu."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 5e1caad..13083d0 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"حالت یک‌دستی"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"بسیار کم‌نور"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"دستگاه‌های کمک‌شنوایی"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"کلیک خودکار"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"متصل نیست"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"وصل شد"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"فعال"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"درخواست الگوی بازگشایی قفل قبل‌از برداشتن سنجاق"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"درخواست گذرواژه قبل از برداشتن سنجاق"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"سرپرست شما آن را نصب کرده است.\nبرای مشاهده اجازه‌های اعطاشده به تنظیمات بروید"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم به‌روزرسانی شد"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"«بهینه‌سازی باتری» «زمینه تاریک» را روشن می‌کند و فعالیت پس‌زمینه، برخی از جلوه‌های بصری، ویژگی‌هایی خاص، و برخی از اتصال‌های شبکه را محدود یا خاموش می‌کند."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f7115eb..145c5ee 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Yhden käden moodi"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Erittäin himmeä"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Kuulolaitteet"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automaattinen klikkaus"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Yhteys katkaistu"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Yhdistetty"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiivinen"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pyydä lukituksenpoistokuvio ennen irrotusta"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pyydä salasana ennen irrotusta"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Järjestelmänvalvojan asentama.\nTarkista myönnetyt luvat asetuksista."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Järjestelmänvalvoja päivitti tämän."</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Järjestelmänvalvoja poisti tämän."</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Virransäästö laittaa tumman teeman päälle ja rajoittaa tai laittaa pois päältä taustatoimintoja, tiettyjä ominaisuuksia sekä joitakin visuaalisia tehosteita ja verkkoyhteyksiä."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 56623a2..0ee4112 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode Une main"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Très sombre"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Appareils auditifs"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automatique"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Déconnecté"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connecté"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Actif"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installé par votre administrateur.\nAccédez aux paramètres pour consulter les autorisations accordées"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Mise à jour par votre administrateur"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Le mode Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels, certaines fonctionnalités et certaines connexions réseau."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 90a0f44..a5b6f9a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode une main"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Luminosité ultra-réduite"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Appareils auditifs"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automatique"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Déconnecté"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connecté"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Actif"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Demander le schéma de déverrouillage avant de retirer l\'épingle"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demander le mot de passe avant de retirer l\'épingle"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installé par votre administrateur.\nAllez dans les paramètres pour consulter les autorisations accordées."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Mis à jour par votre administrateur"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"L\'économiseur de batterie active le thème sombre et limite ou désactive l\'activité en arrière-plan ainsi que certains effets visuels, fonctionnalités et connexions réseau."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index a2b5381..332387a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo dunha soa man"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrón de desbloqueo antes de soltar a fixación"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir contrasinal antes de soltar a fixación"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pola persoa administradora.\nVai á configuración para ver os permisos concedidos"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado polo teu administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado polo teu administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Coa función Aforro de batería, actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e determinadas funcións e conexións de rede."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 9d57bde..7a39d63 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1966,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"અનપિન કરતા પહેલાં અનલૉક પૅટર્ન માટે પૂછો"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"અનપિન કરતાં પહેલાં પાસવર્ડ માટે પૂછો"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"તમારા ઍડમિન દ્વારા ઇન્સ્ટૉલ કરવામાં આવ્યું છે.\nઆપેલી પરવાનગીઓ જોવા માટે સેટિંગ પર જાઓ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ઓકે"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ, અમુક સુવિધાઓ અને કેટલાક નેટવર્ક કનેક્શન મર્યાદિત કે બંધ કરે છે."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 563b724..2c43996 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"वन-हैंडेड मोड"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"कान की मशीन"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"अपने-आप क्लिक होने की सुविधा"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिसकनेक्ट हो गया"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट हो गया"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"चालू है"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन करने से पहले लॉक खोलने के पैटर्न के लिए पूछें"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"अनपिन करने से पहले पासवर्ड के लिए पूछें"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"इसे आपके एडमिन ने इंस्टॉल किया है.\nजिन अनुमतियों को मंज़ूरी मिली है उन्हें देखने के लिए, सेटिंग में जाएं"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, इस मोड में बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ खास सुविधाएं कम या बंद हो जाती हैं. कुछ इंटरनेट कनेक्शन भी पूरी तरह काम नहीं करते."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index fec624d..d870a1d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Način rada jednom rukom"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Još tamnije"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušna pomagala"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatski klik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nije povezano"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži uzorak za otključavanje radi otkvačivanja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži zaporku radi otkvačivanja"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalirao vaš administrator.\nOtvorite postavke da biste pregledali dodijeljena dopuštenja"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"U redu"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte, određene značajke i neke mrežne veze."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 7871aba..350d51d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Egykezes mód"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extrasötét"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hallásjavító eszközök"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatikus kattintás"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Leválasztva"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Csatlakozva"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktív"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Feloldási minta kérése a kitűzés feloldásához"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Jelszó kérése a rögzítés feloldásához"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"A rendszergazda által telepítve.\nLépjen a beállításokhoz a megadott engedélyek megtekintéséhez."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"A rendszergazda által frissítve"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"A rendszergazda által törölve"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, és korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, valamint bizonyos vizuális effekteket, funkciókat és hálózati kapcsolatokat."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 01e5110..655af93 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Մեկ ձեռքի ռեժիմ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Հավելյալ խամրեցում"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Լսողական սարքեր"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Ավտոմատ սեղմում"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Անջատված է"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Միացված է"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ակտիվ է"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Հարցնել ապակողպող նախշը"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Հարցնել գաղտնաբառը"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Տեղադրվել է ադմինիստրատորի կողմից։\nԱնցեք կարգավորումներ՝ տրամադրված թույլտվությունները դիտելու համար"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, ցանցային միացումներ և այլ գործառույթներ։"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index df42e47..305d23a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode satu tangan"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra redup"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Alat bantu dengar"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Klik otomatis"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Tidak terhubung"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Terhubung"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktif"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Meminta pola pembukaan kunci sebelum melepas sematan"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Meminta sandi sebelum melepas sematan"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Diinstal oleh admin Anda.\nBuka setelan untuk melihat izin yang diberikan"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Diupdate oleh admin Anda"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dihapus oleh admin Anda"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Oke"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Penghemat Baterai akan mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas latar belakang, beberapa efek visual, fitur tertentu, dan beberapa koneksi jaringan."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 40d642d..cdf89ad 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhent stilling"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mjög dökkt"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Heyrnartæki"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Sjálfvirkur smellur"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Aftengt"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Tengt"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Virkt"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Biðja um opnunarmynstur til að losa"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Biðja um aðgangsorð til að losa"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Sett upp af stjórnanda.\nFarðu í stillingar til að sjá heimildir"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Kerfisstjóri uppfærði"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Kerfisstjóri eyddi"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Í lagi"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Rafhlöðusparnaður kveikir á dökku þema og takmarkar eða slekkur á bakgrunnsvirkni, sumum myndáhrifum, tilteknum eiginleikum og sumum nettengingum."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index e501c57..3b7d1ec 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1966,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Richiedi sequenza di sblocco prima di sbloccare"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Richiedi password prima di sbloccare"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installato dall\'amministratore.\nVai alle impostazioni per visualizzare le autorizzazioni concesse"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Ok"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Il risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, nonché alcuni effetti visivi, funzionalità e connessioni di rete."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index c9984e2..cf737486 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1967,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"צריך לבקש קו ביטול נעילה לפני ביטול הצמדה"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"יש לבקש סיסמה לפני ביטול הצמדה"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"החבילה הותקנה על ידי האדמין.\nצריך לעבור להגדרות כדי לראות את ההרשאות שניתנו"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"עודכנה על ידי מנהל המערכת"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"נמחקה על ידי מנהל המערכת"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"אישור"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה פעילות ברקע, חלק מהאפקטים החזותיים, תכונות מסוימות וחלק מהחיבורים לרשתות."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 7ab896e..f8bc241 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1965,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"画面固定を解除する前にロック解除パターンの入力を求める"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"オフライン再生を解除する前にパスワードの入力を求める"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"管理者によりインストールされています。\n付与された権限を確認するには、設定に移動してください"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"管理者により更新されています"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"バッテリー セーバーを ON にすると、ダークモードが ON になります。また、バックグラウンド アクティビティ、一部の視覚効果、特定の機能、一部のネットワーク接続が制限されるか OFF になります。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 4d634d4..8aa0af3 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ცალი ხელის რეჟიმი"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"დამატებითი დაბინდვა"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"სმენის აპარატები"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ავტოდაწკაპუნება"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"კავშირი გაწყვეტილია"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"დაკავშირებული"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"აქტიური"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ფიქსაციის მოხსნამდე განბლოკვის ნიმუშის მოთხოვნა"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ფიქსაციის მოხსნამდე პაროლის მოთხოვნა"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"დაინსტალირებულია თქვენი ადმინისტრატორის მიერ.\nდაშვებული ნებართვების სანახავად გადადით პარამეტრებზე"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"კარგი"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს, გარკვეულ ფუნქციებსა და ზოგიერთ ქსელთან კავშირს."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 8d54a32..3908427 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бір қолмен басқару режимі"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Экранды қарайту"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Есту аппараттары"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автоматты басу"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ажыратылды"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Қосылды"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Белсенді"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Босату алдында бекітпесін ашу өрнегін сұрау"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Босату алдында құпия сөзді сұрау"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Әкімшіңіз орнатты.\nБерілген рұқсаттарды көру үшін параметрлерге өтіңіз."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Әкімші жаңартқан"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Әкімші жойған"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Жарайды"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батареяны үнемдеу режимі қараңғы режимді іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлерге, белгілі бір функциялар мен кейбір желі байланыстарына шектеу қояды немесе оларды өшіреді."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index d7e0299..dee23f6 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"មុខងារប្រើដៃម្ខាង"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ងងឹតខ្លាំង"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ចុចស្វ័យប្រវត្តិ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"បាន​ផ្ដាច់"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"បានភ្ជាប់"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"សកម្ម"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"សួរ​រក​លំនាំ​ដោះ​សោ​មុន​ពេលដោះខ្ទាស់"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"សួរ​រក​ពាក្យ​សម្ងាត់​មុន​ពេល​ផ្ដាច់"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"បានដំឡើងដោយអ្នកគ្រប់គ្រងរបស់អ្នក។\nចូលទៅកាន់ការកំណត់ ដើម្បីមើលការ​អនុញ្ញាតដែលផ្ដល់ឱ្យ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ធ្វើ​បច្ចុប្បន្នភាព​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"លុប​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"យល់ព្រម"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"មុខងារ​សន្សំថ្មបើកទម្រង់រចនាងងឹត និងដាក់កំហិត ឬបិទសកម្មភាពផ្ទៃខាងក្រោយ បែបផែនរូបភាពមួយចំនួន មុខងារជាក់លាក់ និងការតភ្ជាប់បណ្ដាញមួយចំនួន។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 9771def..c1a70b0 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ಒಂದು ಕೈ ಮೋಡ್‌"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ಇನ್ನಷ್ಟು ಮಬ್ಬು"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ಆಟೋಕ್ಲಿಕ್"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ಡಿಸ್‌ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ಸಕ್ರಿಯವಾಗಿದೆ"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅನ್‌ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಕೇಳಿ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಪಾಸ್‌ವರ್ಡ್ ಕೇಳು"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿದ್ದಾರೆ.\nನೀಡಲಾದ ಅನುಮತಿಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್‌ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ಬ್ಯಾಟರಿ ಸೇವರ್, ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು, ಕೆಲವು ಫೀಚರ್‌ಗಳು ಮತ್ತು ಇತರ ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a39db4b..be4a284 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"한 손 모드"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"더 어둡게"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"청각 보조 기기"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"자동 클릭"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"연결 끊김"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"연결됨"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"활성"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"고정 해제 시 잠금 해제 패턴 요청"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"고정 해제 이전에 비밀번호 요청"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"관리자에 의해 설치되었습니다.\n부여된 권한을 확인하려면 설정으로 이동하세요."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"관리자에 의해 업데이트되었습니다."</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"관리자에 의해 삭제되었습니다."</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"확인"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"절전 모드는 어두운 테마를 사용하고 백그라운드 활동, 일부 시각 효과, 특정 기능 및 일부 네트워크 연결을 제한하거나 사용 중지합니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index fbc3afd..121908a 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бир кол режими"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Кошумча караңгылатуу"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Угуу түзмөктөрү"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Авточыкылдатуу"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ажыратылды"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Туташты"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Жигердүү"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Бошотуудан мурун графикалык ачкыч суралсын"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Бошотуудан мурун сырсөз суралсын"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Администраторуңуз орнотту.\nБерилген уруксаттарды көрүү үчүн параметрлерге өтүңүз"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Администраторуңуз жаңыртып койгон"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батареяны үнөмдөөчү режимде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер, белгилүү бир функциялар жана айрым тармакка туташуулар чектелип же өчүрүлөт."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index a0a6b38..ad62671 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ໂໝດມືດຽວ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ຫຼຸດແສງເປັນພິເສດ"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ອຸປະກອນຊ່ວຍຟັງ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ການຄລິກອັດຕະໂນມັດ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ນຳໃຊ້ຢູ່"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"​ຖາມ​ຫາ​ຮູບ​ແບບ​ປົດ​ລັອກ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"​ຖາມ​ຫາ​ລະ​ຫັດ​ຜ່ານ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ຕິດຕັ້ງໂດຍຜູ້ເບິ່ງແຍງຂອງທ່ານ.\nເຂົ້າໄປການຕັ້ງຄ່າເພື່ອເບິ່ງສິດທີ່ໄດ້ຮັບອະນຸຍາດ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ຖືກອັບໂຫລດໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ຖືກລຶບອອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ຕົກລົງ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບຈຳນວນໜຶ່ງ, ຄຸນສົມບັດບາງຢ່າງ ແລະ ການເຊື່ອມຕໍ່ເຄືອຂ່າຍບາງອັນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0b4967a..27a08c2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Vienos rankos režimas"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Itin blanku"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Klausos įrenginiai"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatinis paspaudimas"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Atjungta"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Prisijungta"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktyvus"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Prašyti atrakinimo piešinio prieš atsegant"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Prašyti slaptažodžio prieš atsegant"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Įdiegė administratorius.\nEikite į nustatymus ir peržiūrėkite suteiktus leidimus"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atnaujino administratorius"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Ištrynė administratorius"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Gerai"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vaizdinius efektus, tam tikras funkcijas bei kai kuriuos tinklo ryšius."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0d19dc2..78c7ebd 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Vienas rokas režīms"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Papildu aptumšošana"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dzirdes aparāti"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automātiskā klikšķināšana"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Atvienota"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Pievienota"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktīva"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pirms atspraušanas pieprasīt atbloķēšanas kombināciju"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pirms atspraušanas pieprasīt paroli"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalēja jūsu administrators.\nPārejiet uz iestatījumiem, lai skatītu piešķirtās atļaujas."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs un tiek ierobežotas vai izslēgtas darbības fonā, daži vizuālie efekti, noteiktas funkcijas un noteikti tīkla savienojumi."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 9889ea9..146de01 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1531,7 +1531,7 @@
     <string name="ext_media_status_unmounted" msgid="8145812017295835941">"Исфрлено"</string>
     <string name="ext_media_status_checking" msgid="159013362442090347">"Се проверува..."</string>
     <string name="ext_media_status_mounted" msgid="3459448555811203459">"Подготвено"</string>
-    <string name="ext_media_status_mounted_ro" msgid="1974809199760086956">"Само за читање"</string>
+    <string name="ext_media_status_mounted_ro" msgid="1974809199760086956">"Само за преглед"</string>
     <string name="ext_media_status_bad_removal" msgid="508448566481406245">"Отстранет небезбедно"</string>
     <string name="ext_media_status_unmountable" msgid="7043574843541087748">"Оштетено"</string>
     <string name="ext_media_status_unsupported" msgid="5460509911660539317">"Неподдржано"</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим со една рака"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дополнително затемнување"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слушни помагала"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автоматско кликнување"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Не е поврзано"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Поврзано"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Побарај шема за откл. пред откачување"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Побарај лозинка пред откачување"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Инсталирано од администраторот.\nОдете во „Поставки“ за да ги прегледате доделените дозволи"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирано од администраторот"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Избришано од администраторот"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Во ред"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"„Штедачот на батерија“ вклучува „Темна тема“ и ограничува или исклучува активност во заднина, некои визуелни ефекти, одредени функции и некои мрежни врски."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index ff07aa0..3bb425e 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1965,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"അൺപിന്നിനുമുമ്പ് അൺലോക്ക് പാറ്റേൺ ആവശ്യപ്പെടൂ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"അൺപിന്നിനുമുമ്പ് പാസ്‌വേഡ് ആവശ്യപ്പെടൂ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"നിങ്ങളുടെ അഡ്‌മിൻ ഇൻസ്‌റ്റാൾ ചെയ്തത്.\nനൽകിയ അനുമതികൾ കാണാൻ ക്രമീകരണത്തിലേക്ക് പോകുക"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"നിങ്ങളുടെ അഡ്‌മിൻ അപ്‌ഡേറ്റ് ചെയ്യുന്നത്"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്‌മിൻ ഇല്ലാതാക്കുന്നത്"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\'ബാറ്ററി സേവർ\' ഡാർക്ക് തീം ഓണാക്കുന്നു, ഒപ്പം പശ്ചാത്തല ആക്‌റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്‌വർക്ക് കണക്ഷനുകളും പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 3a1e0a6..1ad9685 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Нэг гарын горим"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Хэт бүүдгэр"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Сонсголын төхөөрөмжүүд"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автомат товшилт"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Салсан"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Холбогдсон"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Идэвхтэй"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Бэхэлснийг болиулахаас өмнө түгжээ тайлах хээ асуух"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Танай админ суулгасан.\nОлгосон зөвшөөрлүүдийг харахын тулд тохиргоо руу очно уу"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Таны админ шинэчилсэн"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Таны админ устгасан"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект, тодорхой онцлогууд болон зарим сүлжээний холболтыг хязгаарлах эсвэл унтраана."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index d79dc6d..82f217f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एकहाती मोड"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"आणखी डिम"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"श्रवणयंत्रे"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ऑटोक्लिक"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिस्कनेक्ट केले आहे"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट केले आहे"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"अ‍ॅक्टिव्ह"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन करण्‍यापूर्वी अनलॉक नमुन्यासाठी विचारा"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"अनपिन करण्‍यापूर्वी संकेतशब्दासाठी विचारा"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"तुमच्या ॲडमिनने इंस्टॉल केले आहे.\nदिलेल्या परवानग्या पाहण्यासाठी सेटिंग्जवर जा"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"आपल्या प्रशासकाने अपडेट केले"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"आपल्या प्रशासकाने हटवले"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ओके"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट, ठरावीक वैशिष्ट्ये व काही नेटवर्क कनेक्शन मर्यादित किंवा बंद करते."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 76d4027..bda439a 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1965,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Minta corak buka kunci sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Minta kata laluan sebelum menyahsemat"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Dipasang oleh pentadbir anda.\nAkses tetapan untuk melihat kebenaran yang diberikan"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Dikemas kini oleh pentadbir anda"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dipadamkan oleh pentadbir anda"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual, ciri tertentu dan sesetengah sambungan rangkaian."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index fc6df7a..9a80416 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"လက်တစ်ဖက်သုံးမုဒ်"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ပိုမှိန်ခြင်း"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"နားကြားကိရိယာ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"အော်တိုနှိပ်ခြင်း"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ချိတ်ဆက်မထားပါ"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ချိတ်ဆက်ထားသည်"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"သုံးနေသည်"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ပင်မဖြုတ်မီ လော့ခ်ဖွင့်ပုံစံကို မေးရန်"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ပင်မဖြုတ်မီမှာ စကားဝှက်ကို မေးကြည့်ရန်"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"သင့်စီမံခန့်ခွဲသူက ထည့်သွင်းထားသည်။\nပေးထားသည့် ခွင့်ပြုချက်များကို ကြည့်ရန် ဆက်တင်များသို့ သွားပါ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"‘ဘက်ထရီ အားထိန်း’ က ‘အမှောင်နောက်ခံ’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ဖန်တီးပြသချက်အချို့၊ ဝန်ဆောင်မှုအချို့နှင့် ကွန်ရက်ချိတ်ဆက်မှုအချို့တို့ကို ကန့်သတ်သည် သို့မဟုတ် ပိတ်သည်။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index b8cc711..d8e785f 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndsmodus"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dimmet"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Høreapparater"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoklikk"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Frakoblet"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Tilkoblet"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Krev opplåsingsmønster for å løsne apper"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Krev passord for å løsne apper"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installert av administratoren din.\nGå til innstillingene for å se hvilke tillatelser som er gitt"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Oppdatert av administratoren din"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet av administratoren din"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter, noen funksjoner og noen nettverkstilkoblinger."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 5907182..88e9370 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एक हाते मोड"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"अझै मधुरो"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"हियरिङ डिभाइसहरू"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"अटोक्लिक"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिस्कनेक्ट गरिएको"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट गरिएको"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"सक्रिय"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन गर्नअघि अनलक प्याटर्न माग्नुहोस्"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"पिन निकाल्नुअघि पासवर्ड सोध्नुहोस्"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"यो प्याकेज तपाईंका एड्मिनले इन्स्टल गर्नुभएको हो।\nप्रदान गरिएका अनुमतिसम्बन्धी जानकारी हेर्न सेटिङमा जानुहोस्"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"तपाईंका प्रशासकले अद्यावधिक गर्नुभएको"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"तपाईंका प्रशासकले मेट्नुभएको"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ठिक छ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ब्याट्री सेभरले अँध्यारो थिम अन गर्छ र ब्याकग्राउन्डमा हुने क्रियाकलाप, केही भिजुअल इफेक्ट, निश्चित सुविधा र केही नेटवर्क कनेक्सनहरू अफ गर्छ वा सीमित रूपमा मात्र चल्न दिन्छ।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 98ce463..a43c0c4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Bediening met 1 hand"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dimmen"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hoortoestellen"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatisch klikken"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Verbinding verbroken"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Verbonden"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Actief"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ontgrendelingspatroon vragen om app los te maken"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vraag wachtwoord voor losmaken"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Geïnstalleerd door je beheerder.\nGa naar instellingen om verleende rechten te bekijken."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Geüpdatet door je beheerder"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Verwijderd door je beheerder"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, bepaalde visuele effecten, bepaalde functies en sommige netwerkverbindingen beperkt of uitgezet."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 4931bd2e..f61e109 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1965,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ଅନପିନ୍‌ କରିବା ପୂର୍ବରୁ ଲକ୍‌ ଖୋଲିବା ପାଟର୍ନ ପଚାରନ୍ତୁ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ଅନପିନ୍‌ କରିବା ପୂର୍ବରୁ ପାସ୍‌ୱର୍ଡ ପଚାରନ୍ତୁ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଇନଷ୍ଟଲ କରାଯାଇଛି।\nଅନୁମୋଦିତ ଅମୁମତିଗୁଡ଼ିକ ଭ୍ୟୁ କରିବା ପାଇଁ ସେଟିଂସକୁ ଯାଆନ୍ତୁ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଅପଡେଟ୍‍ କରିଛନ୍ତି"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଡିଲିଟ୍‍ କରିଛନ୍ତି"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ ଅଛି"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ବେଟେରୀ ସେଭର ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ ଇଫେକ୍ଟ, କିଛି ଫିଚର ଏବଂ କିଛି ନେଟୱାର୍କ ସଂଯୋଗକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 80ed484..5d2cc7b 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1965,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ਅਨਪਿੰਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਅਣਲਾਕ ਪੈਟਰਨ ਵਾਸਤੇ ਪੁੱਛੋ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ਅਣਪਿੰਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪਾਸਵਰਡ ਮੰਗੋ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਸਥਾਪਤ ਕੀਤਾ ਗਿਆ।\nਦਿੱਤੀਆਂ ਗਈਆਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ਠੀਕ ਹੈ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਕੁਝ ਖਾਸ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਅਤੇ ਕੁਝ ਨੈੱਟਵਰਕ ਕਨੈਕਸ਼ਨਾਂ ਨੂੰ ਸੀਮਤ ਜਾਂ ਬੰਦ ਕਰਦਾ ਹੈ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index efae947..bb7edb8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tryb jednej ręki"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatkowe przyciemnienie"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Urządzenia słuchowe"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatyczne kliknięcie"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Rozłączone"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Połączone"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktywne"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Aby odpiąć, poproś o wzór odblokowania"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Aby odpiąć, poproś o hasło"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Zainstalowany przez administratora.\nOtwórz ustawienia, aby wyświetlić przyznane uprawnienia"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne, pewne funkcje oraz wybrane połączenia sieciowe."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 4036d636..0440e39 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Tela ainda mais escura"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clique automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir senha antes de liberar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pelo administrador.\nAcesse as configurações para conferir as permissões concedidas"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index df3f9c6..745e17b 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mais escuro"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clique automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desligado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ligado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de soltar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir palavra-passe antes de soltar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pelo seu administrador.\nAceda às definições para ver as autorizações concedidas"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu gestor"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado pelo seu gestor"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais, determinadas funcionalidades e algumas ligações de rede."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 4036d636..0440e39 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Tela ainda mais escura"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clique automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir senha antes de liberar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pelo administrador.\nAcesse as configurações para conferir as permissões concedidas"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index b12af39..4ef0423 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modul cu o mână"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Luminozitate redusă suplimentar"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparate auditive"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automat"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Deconectat"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectat"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Activ"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicită mai întâi modelul pentru deblocare"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicită parola înainte de a anula fixarea"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalat de administrator.\nAccesează setările ca să vezi permisiunile acordate."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizat de administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Economisirea bateriei activează tema întunecată și restricționează sau dezactivează activitatea în fundal, unele efecte vizuale, alte funcții și câteva conexiuni la rețea."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 4911fc6..a03963e 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим управления одной рукой"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дополнительное уменьшение яркости"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слуховые аппараты"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автонажатие"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Отключено"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Подключено"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запрашивать графический ключ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запрашивать пароль"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Установлено администратором.\nЧтобы посмотреть предоставленные разрешения, перейдите в настройки."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Обновлено администратором"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Удалено администратором"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, а также некоторые визуальные эффекты, часть функций и сетевых подключений."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index b11e442..571706e 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"තනි අත් ප්‍රකාරය"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"තවත් අඳුරු"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ශ්‍රවණ උපාංග"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ස්වයං ක්ලික් කිරීම"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"විසන්ධි විය"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"සම්බන්ධිතයි"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"සක්‍රිය"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ගැලවීමට පෙර අගුළු අරින රටාව සඳහා අසන්න"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ගැලවීමට පෙර මුරපදය විමසන්න"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ඔබේ පරිපාලකයා විසින් ස්ථාපන කරනු ලබයි.\nදෙන ලද අවසර බැලීමට සැකසීම් වෙත යන්න"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"හරි"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"බැටරි සුරැකුම අඳුරු තේමාව ක්‍රියාත්මක කර පසුබිම් ක්‍රියාකාරකම්, සමහර දෘශ්‍ය ප්‍රයෝග, යම් විශේෂාංග සහ සමහර ජාල සම්බන්ධතා සීමා හෝ ක්‍රියාවිරහිත කරයි."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 47bee0a..bcbd66f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jednej ruky"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mimoriadne stmavenie"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Načúvacie zariadenia"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatické kliknutie"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Odpojené"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Pripojené"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktívne"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pred uvoľnením požiadať o bezpečnostný vzor"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pred odopnutím požiadať o heslo"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Nainštaloval správca.\nAk si chcete zobraziť udelené povolenia, prejdite do nastavení."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty, určité funkcie a niektoré pripojenia k sieti."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 208c174..c0d18ed 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enoročni način"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Zelo zatemnjen zaslon"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni pripomočki"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Samodejni klik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Brez povezave"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pred odpenjanjem vprašaj za vzorec za odklepanje"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pred odpenjanjem vprašaj za geslo"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Namestil skrbnik.\nV nastavitvah si oglejte odobrena dovoljenja."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Posodobil skrbnik"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisal skrbnik"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Funkcija varčevanja z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke, določene funkcije in nekatere omrežne povezave."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 5f84908..ddccede 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modaliteti i përdorimit me një dorë"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Shumë më i zbehtë"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Pajisjet e dëgjimit"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Klikimi automatik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Shkëputur"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Lidhur"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktive"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Kërko motivin e shkyçjes para heqjes së gozhdimit"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Kërko fjalëkalim para heqjes nga gozhdimi."</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instaluar nga administratori.\nShko te cilësimet për të shikuar lejet e dhëna"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Përditësuar nga administratori"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Fshirë nga administratori"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Në rregull"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\" dhe kufizon ose çaktivizon aktivitetin në sfond, disa efekte vizuale, veçori të caktuara dhe disa lidhje të rrjetit."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 61102d3..397a394 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1966,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Тражи шаблон за откључавање пре откачињања"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тражи лозинку пре откачињања"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Инсталирао је администратор.\nИдите у подешавања да бисте видели одобрене дозволе"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирао је администратор"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Избрисао је администратор"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Потврди"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Уштеда батерије укључује тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте, одређене функције и неке мрежне везе."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d5fc694..71062ad 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhandsläge"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradimmat"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörhjälpmedel"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatiskt klick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Frånkopplad"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ansluten"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Be om upplåsningsmönster innan skärmen slutar fästas"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Be om lösenord innan skärmen slutar fästas"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Har installerats av administratören.\nÖppna inställningarna för att se behörigheter som beviljats"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Administratören uppdaterade paketet"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"I batterisparläget aktiveras mörkt tema medan bakgrundsaktivitet, vissa visuella effekter och funktioner samt vissa nätverksanslutningar begränsas eller inaktiveras."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 49e9f1c..e74ac18 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Hali ya kutumia kwa mkono mmoja"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Kipunguza mwangaza zaidi"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Vifaa vya kusaidia kusikia"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Kubofya kiotomatiki"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Haijaunganishwa"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Imeunganishwa"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Inatumika"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Omba mchoro wa kufungua kabla hujabandua"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Omba nenosiri kabla hujabandua"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Kimewekwa na msimamizi wako.\nNenda kwenye mipangilio ili uone ruhusa zilizotolewa"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Imesasishwa na msimamizi wako"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Imefutwa na msimamizi wako"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Sawa"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana, vipengele fulani na baadhi ya miunganisho ya mtandao."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index dad40dc..7737d8f 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ஒற்றைக் கைப் பயன்முறை"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"மிகக் குறைவான வெளிச்சம்"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"செவித்துணைக் கருவிகள்"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ஆட்டோ கிளிக்"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"இணைப்புநீக்கப்பட்டது"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"இணைக்கப்பட்டுள்ளது"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"செயலில் உள்ளது"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"அகற்றும் முன் அன்லாக் பேட்டர்னைக் கேள்"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"அகற்றும் முன் கடவுச்சொல்லைக் கேள்"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"உங்கள் நிர்வாகி நிறுவியுள்ளார்.\nவழங்கப்பட்டுள்ள அனுமதிகளை பார்க்க அமைப்புகளுக்குச் செல்லவும்"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"சரி"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"பேட்டரி சேமிப்பான் அம்சம் டார்க் தீமை இயக்குவதோடு பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபக்ட்கள், குறிப்பிட்ட அம்சங்கள், சில நெட்வொர்க் இணைப்புகள் ஆகியவற்றைக் கட்டுப்படுத்தும் அல்லது முடக்கும்."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 322a703..265fb8c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"వన్-హ్యాండెడ్ మోడ్"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ఎక్స్‌ట్రా డిమ్"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"వినికిడి పరికరాలు"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ఆటో-క్లిక్"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"డిస్‌కనెక్ట్ అయింది"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"కనెక్ట్ చేయబడింది"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"యాక్టివ్"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"అన్‌పిన్ చేయడానికి ముందు అన్‌లాక్ ఆకృతి కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"అన్‌పిన్ చేయడానికి ముందు పాస్‌వర్డ్ కోసం అడుగు"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"మీ అడ్మిన్ ఇన్‌స్టాల్ చేశారు.\nసెట్టింగ్‌లకు వెళ్లి, మంజూరు చేసిన అనుమతులు చూడండి"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు అప్‌డేట్ చేశారు"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్‌గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్‌లు, నిర్దిష్ట ఫీచర్‌లు, ఇంకా కొన్ని నెట్‌వర్క్ కనెక్షన్‌లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 107a59f..a922943 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1965,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ขอรูปแบบการปลดล็อกก่อนเลิกปักหมุด"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ขอรหัสผ่านก่อนเลิกปักหมุด"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ติดตั้งโดยผู้ดูแลระบบของคุณ\nไปที่การตั้งค่าเพื่อดูสิทธิ์ที่ได้รับอนุญาต"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง ฟีเจอร์บางส่วน และการเชื่อมต่อบางเครือข่าย"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 9788327..5e3e1e8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-Hand mode"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Mga hearing device"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoclick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nadiskonekta"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Nakakonekta"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktibo"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Humingi ng pattern sa pag-unlock bago mag-unpin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Humingi ng password bago mag-unpin"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Na-install ng iyong admin.\nPumunta sa mga setting para makita ang mga ibinigay na pahintulot"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Na-update ng iyong admin"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, ilang partikular na feature, at ilang koneksyon sa network."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 095a3da..72d62d5 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tek El modu"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra loş"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"İşitme cihazları"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Otomatik tıklama"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Bağlı değil"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Bağlı"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Etkin"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Sabitlemeyi kaldırmadan önce şifre sor"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Yöneticiniz tarafından yüklendi.\nVerilen izinleri görüntülemek için ayarlara gidin"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Yöneticiniz tarafından güncellendi"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Yöneticiniz tarafından silindi"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Tamam"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Pil Tasarrufu, Koyu temayı açıp arka plan etkinliğini, bazı görsel efektleri, belirli özellikleri ve bazı ağ bağlantılarını sınırlandırır veya kapatır."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index bc05f49..e4e1e99 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим керування однією рукою"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Додаткове зменшення яскравості"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слухові апарати"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автоматичне натискання"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Від’єднано"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Під’єднано"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активний"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запитувати ключ розблокування перед відкріпленням"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запитувати пароль перед відкріпленням"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Установлено адміністратором.\nПерейдіть у налаштування, щоб переглянути надані дозволи."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Оновлено адміністратором"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Видалено адміністратором"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"У режимі енергозбереження вмикається темна тема й обмежуються чи вимикаються дії у фоновому режимі, а також деякі візуальні ефекти, функції та з’єднання з мережами."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7794c9a..a98179a 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ایک ہاتھ کی وضع"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"اضافی مدھم"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعتی آلات"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"خودکار کلک"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"غیر منسلک ہے"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"منسلک ہے"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"فعال"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"پن ہٹانے سے پہلے غیر مقفل کرنے کا پیٹرن طلب کریں"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"پن ہٹانے سے پہلے پاس ورڈ طلب کریں"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"آپ کے منتظم نے انسٹال کیا ہے۔\nدی گئی اجازتیں دیکھنے کیلئے ترتیبات پر جائیں"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ٹھیک ہے"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات، مخصوص خصوصیات اور کچھ نیٹ ورک کنکشنز کو محدود یا آف کرتی ہے۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 95a44bb..81ebe5f 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Ixcham rejim"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Juda xira"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Eshitish qurilmalari"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Avtoklik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Uzildi"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ulandi"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Faol"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Yechishdan oldin grafik kalit so‘ralsin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Bo‘shatishdan oldin parol so‘ralsin"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Administrator oʻrnatgan.\nBerilgan ruxsatlarni koʻrish uchun sozlamalarni oching"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Administrator tomonidan yangilangan"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administrator tomonidan o‘chirilgan"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi hamda fondagi harakatlar, vizual effektlar, ayrim funksiyalar va tarmoq aloqalari kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index bb9b797..4dda8cc 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Chế độ một tay"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Siêu tối"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Thiết bị trợ thính"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Tự động nhấp"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Đã ngắt kết nối"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Đã kết nối"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Đang hoạt động"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Hỏi hình mở khóa trước khi bỏ ghim"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Hỏi mật khẩu trước khi bỏ ghim"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Do quản trị viên của bạn cài đặt.\nChuyển đến phần cài đặt để xem các quyền được cấp"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Do quản trị viên của bạn cập nhật"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Do quản trị viên của bạn xóa"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Trình tiết kiệm pin sẽ bật Giao diện tối, đồng thời hạn chế hoặc tắt hoạt động chạy trong nền, một số hiệu ứng hình ảnh, các tính năng nhất định và một số đường kết nối mạng."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 108d62e..851195a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"单手模式"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"极暗"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助听装置"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"自动点击"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"已断开连接"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"已连接"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"活跃"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定前要求绘制解锁图案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消时要求输入密码"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"由您的管理员安装。\n前往设置可查看已授予的权限"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理员更新"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理员删除"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"确定"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"在省电模式下,系统会启用深色主题,并限制或关闭后台活动、某些视觉效果、特定功能和部分网络连接。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index fc9e6e8..87b403d 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助聽器"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"自動點擊"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"已中斷連線"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"已連線"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"運作中"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定時必須提供解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消固定時必須輸入密碼"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"已由你的管理員安裝。\n請前往設定查看已授予的權限"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"好"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"「慳電模式」會開啟深色主題背景,並限制或關閉背景活動、部分視覺效果、特定功能和部分網絡連線。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d2ca941..72d2e7c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助聽器"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"自動點選"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"連線中斷"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"已連線"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"運作中"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定時必須畫出解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消固定時必須輸入密碼"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"這是管理員安裝的套件。\n你可以前往設定查看授予的權限"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果、特定功能和部分網路連線。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e116832..13356cb 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Imodi yesandla esisodwa"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ukufiphaza okwengeziwe"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Amadivayizi okuzwa"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Chofoza ngokuzenzekelayo"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Inqamukile"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ixhunyiwe"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Kuyasebenza"</string>
@@ -1966,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Cela iphethini yokuvula ngaphambi kokususa ukuphina"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Cela iphasiwedi ngaphambi kokususa ukuphina"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Kufakwe ngumphathi wakho.\nIya kumasethingi ukuze ubuke izimvume ezinikeziwe"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Kubuyekezwe umlawuli wakho"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Kususwe umlawuli wakho"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"KULUNGILE"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Isilondolozi Sebhethri sivula ingqikithi emnyama futhi sibeke umkhawulo noma sivale umsebenzi ongemuva, imiphumela ethile yokubuka, izici ezithile, nokuxhumeka okuthile kwenethiwekhi."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fbb8e25..8c5b20d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2812,6 +2812,20 @@
     <integer name="config_dreamsBatteryLevelDrainCutoff">5</integer>
     <!-- Limit of how long the device can remain unlocked due to attention checking.  -->
     <integer name="config_attentionMaximumExtension">900000</integer> <!-- 15 minutes.  -->
+
+    <!-- Enables or disables the 'prevent screen timeout' feature, where when a user manually
+         undims the screen, the feature acquires a wakelock to prevent screen timeout.
+         false = disabled, true = enabled. Disabled by default. -->
+    <bool name="config_defaultPreventScreenTimeoutEnabled">false</bool>
+    <!-- Default value (in milliseconds) to prevent the screen timeout after user undims it
+         manually between screen dims, a sign the user is interacting with the device. -->
+    <integer name="config_defaultPreventScreenTimeoutForMillis">300000</integer> <!-- 5 minutes. -->
+    <!-- Default max duration (in milliseconds) of the time between undims to still consider them
+         consecutive. -->
+    <integer name="config_defaultMaxDurationBetweenUndimsMillis">600000</integer> <!-- 10 min.  -->
+    <!-- Default number of user undims required to trigger preventing screen sleep. -->
+    <integer name="config_defaultUndimsRequired">2</integer>
+
     <!-- Whether there is to be a chosen Dock User who is the only user allowed to dream. -->
     <bool name="config_dreamsOnlyEnabledForDockUser">false</bool>
     <!-- Whether dreams are disabled when ambient mode is suppressed. -->
@@ -4459,6 +4473,10 @@
          etc. dialogs. -->
     <string translatable="false" name="config_appsNotReportingCrashes"></string>
 
+    <!-- Specifies the delay in milliseconds for JobScheduler to postpone the running
+         of regular jobs when coming out of doze -->
+    <integer name="config_jobSchedulerBackgroundJobsDelay">3000</integer>
+
     <!-- Inactivity threshold (in milliseconds) used in JobScheduler. JobScheduler will consider
          the device to be "idle" after being inactive for this long. -->
     <integer name="config_jobSchedulerInactivityIdleThreshold">1860000</integer>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 6245a53..ef6b918 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -80,11 +80,6 @@
     <bool name="auto_data_switch_ping_test_before_switch">true</bool>
     <java-symbol type="bool" name="auto_data_switch_ping_test_before_switch" />
 
-    <!-- TODO: remove after V -->
-    <!-- Boolean indicating whether allow to use a roaming nonDDS if user enabled its roaming. -->
-    <bool name="auto_data_switch_allow_roaming">true</bool>
-    <java-symbol type="bool" name="auto_data_switch_allow_roaming" />
-
     <!-- Define the tolerated gap of score for auto data switch decision, larger than which the
          device will switch to the SIM with higher score. The score is used in conjunction with the
          score table defined in
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index a1961ae..465e318 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -390,6 +390,16 @@
     <!-- The absolute size of the notification expand icon. -->
     <dimen name="notification_header_expand_icon_size">56dp</dimen>
 
+    <!-- Margin to allow space for the expand button when showing the right icon in expanded -->
+    <!-- notifications. This is equal to notification_2025_expand_button_pill_width -->
+    <!-- + notification_2025_margin (end padding for expand button) -->
+    <!-- + notification_2025_expand_button_right_icon_spacing (space between pill and icon) -->
+    <dimen name="notification_2025_right_icon_expanded_margin_end">52dp</dimen>
+
+    <!-- The large icon has a smaller vertical margin than most other notification content, to -->
+    <!-- allow it to grow up to 48dp. -->
+    <dimen name="notification_2025_right_icon_vertical_margin">12dp</dimen>
+
     <!-- the height of the expand button pill -->
     <dimen name="notification_expand_button_pill_height">24dp</dimen>
 
@@ -411,15 +421,24 @@
     <!-- the padding of the expand icon in the notification header -->
     <dimen name="notification_2025_expand_button_horizontal_icon_padding">6dp</dimen>
 
-    <!-- a smaller padding for the end of the expand button, for use when showing the number -->
+    <!-- smaller padding for the end of the expand icon, for use when showing the number -->
     <dimen name="notification_2025_expand_button_reduced_end_padding">4dp</dimen>
 
+    <!-- the space needed between the expander pill and the large icon when visible -->
+    <dimen name="notification_2025_expand_button_right_icon_spacing">8dp</dimen>
+
     <!-- the size of the notification close button -->
     <dimen name="notification_close_button_size">16dp</dimen>
 
     <!-- Margin for all notification content -->
     <dimen name="notification_2025_margin">16dp</dimen>
 
+    <!-- A smaller version of the margin to be used when we need more space for the content -->
+    <dimen name="notification_2025_reduced_margin">12dp</dimen>
+
+    <!-- The difference between the usual margin and the reduced margin -->
+    <dimen name="notification_2025_additional_margin">4dp</dimen>
+
     <!-- Vertical margin for the headerless notification content, when content has 1 line -->
     <!-- 16 * 2 (margins) + 24 (1 line) = 56 (notification) -->
     <dimen name="notification_headerless_margin_oneline">16dp</dimen>
@@ -438,7 +457,7 @@
     <dimen name="notification_collapsed_height_with_summarization">156dp</dimen>
 
     <!-- Max height of a collapsed (headerless) notification with one or two lines -->
-    <!-- 16 * 2 (margins) + 48 (min content height) = 72 (notification) -->
+    <!-- 14 * 2 (reduced margins) + 48 (max collapsed content height) = 72 (notification) -->
     <dimen name="notification_2025_min_height">72dp</dimen>
 
     <!-- Height of a headerless notification with one line -->
@@ -729,6 +748,9 @@
     <!-- The accessibility autoclick panel divider height -->
     <dimen name="accessibility_autoclick_type_panel_divider_height">24dp</dimen>
 
+    <!-- The accessibility autoclick scroll panel button width and height -->
+    <dimen name="accessibility_autoclick_scroll_panel_button_size">36dp</dimen>
+
     <!-- Margin around the various security views -->
     <dimen name="keyguard_muliuser_selector_margin">8dp</dimen>
 
@@ -893,6 +915,8 @@
     <dimen name="notification_right_icon_size">48dp</dimen>
     <!-- The margin between the right icon and the content. -->
     <dimen name="notification_right_icon_content_margin">12dp</dimen>
+    <!-- The margin between the right icon and the content. (2025 redesign version) -->
+    <dimen name="notification_2025_right_icon_content_margin">16dp</dimen>
     <!-- The top and bottom margin of the right icon in the normal notification states -->
     <dimen name="notification_right_icon_headerless_margin">20dp</dimen>
     <!-- The top margin of the right icon in the "big" notification states -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b3cc883..d94d659 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -6226,6 +6226,18 @@
     <string name="accessibility_autoclick_pause">Pause</string>
     <!-- Label for autoclick position button [CHAR LIMIT=NONE] -->
     <string name="accessibility_autoclick_position">Position</string>
+    <!-- Label for autoclick scroll up button [CHAR LIMIT=NONE] -->
+    <string name="accessibility_autoclick_scroll_up">Scroll Up</string>
+    <!-- Label for autoclick scroll down button [CHAR LIMIT=NONE] -->
+    <string name="accessibility_autoclick_scroll_down">Scroll Down</string>
+    <!-- Label for autoclick scroll left button [CHAR LIMIT=NONE] -->
+    <string name="accessibility_autoclick_scroll_left">Scroll Left</string>
+    <!-- Label for autoclick scroll right button [CHAR LIMIT=NONE] -->
+    <string name="accessibility_autoclick_scroll_right">Scroll Right</string>
+    <!-- Label for autoclick scroll exit button [CHAR LIMIT=NONE] -->
+    <string name="accessibility_autoclick_scroll_exit">Exit Scroll Mode</string>
+    <!-- Label for autoclick scroll panel title [CHAR LIMIT=NONE] -->
+    <string name="accessibility_autoclick_scroll_panel_title">Scroll Panel</string>
 
     <!-- Text to tell the user that a package has been forced by themselves in the RESTRICTED bucket. [CHAR LIMIT=NONE] -->
     <string name="as_app_forced_to_restricted_bucket">
@@ -6698,6 +6710,8 @@
     <string name="profile_label_test">Test</string>
     <!-- Communal profile label on a screen. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
     <string name="profile_label_communal">Communal</string>
+    <!-- Supervising profile label on a screen. This can be used as a tab label for this profile in tabbed views and can be used to represent the profile in sharing surfaces, etc. [CHAR LIMIT=20] -->
+    <string name="profile_label_supervising">Supervising</string>
 
     <!-- Accessibility label for managed profile user type [CHAR LIMIT=30] -->
     <string name="accessibility_label_managed_profile">Work profile</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index ee1edda..1c3529f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1761,6 +1761,19 @@
         <item name="android:tint">@color/materialColorPrimary</item>
     </style>
 
+    <style name="AccessibilityAutoclickScrollPanelButtonLayoutStyle">
+        <item name="android:gravity">center</item>
+        <item name="android:layout_width">@dimen/accessibility_autoclick_scroll_panel_button_size   </item>
+        <item name="android:layout_height">@dimen/accessibility_autoclick_scroll_panel_button_size</item>
+    </style>
+
+    <style name="AccessibilityAutoclickScrollPanelImageButtonStyle">
+        <item name="android:gravity">center</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:scaleType">center</item>
+    </style>
+
     <!--
         TODO(b/309578419): Make activities go edge-to-edge properly and then remove this.
     -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f5424db..3de30f7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1129,6 +1129,7 @@
   <java-symbol type="string" name="profile_label_work_3" />
   <java-symbol type="string" name="profile_label_test" />
   <java-symbol type="string" name="profile_label_communal" />
+  <java-symbol type="string" name="profile_label_supervising" />
   <java-symbol type="string" name="accessibility_label_managed_profile" />
   <java-symbol type="string" name="accessibility_label_private_profile" />
   <java-symbol type="string" name="accessibility_label_clone_profile" />
@@ -3016,6 +3017,7 @@
 
   <java-symbol type="integer" name="config_defaultNightMode" />
 
+  <java-symbol type="integer" name="config_jobSchedulerBackgroundJobsDelay" />
   <java-symbol type="integer" name="config_jobSchedulerInactivityIdleThreshold" />
   <java-symbol type="integer" name="config_jobSchedulerInactivityIdleThresholdOnStablePower" />
   <java-symbol type="integer" name="config_jobSchedulerIdleWindowSlop" />
@@ -3266,6 +3268,8 @@
   <java-symbol type="dimen" name="notification_2025_content_margin_start" />
   <java-symbol type="dimen" name="notification_2025_expand_button_horizontal_icon_padding" />
   <java-symbol type="dimen" name="notification_2025_expand_button_reduced_end_padding" />
+  <java-symbol type="dimen" name="notification_2025_expand_button_right_icon_spacing" />
+  <java-symbol type="dimen" name="notification_2025_right_icon_expanded_margin_end" />
   <java-symbol type="dimen" name="notification_progress_margin_horizontal" />
   <java-symbol type="dimen" name="notification_header_background_height" />
   <java-symbol type="dimen" name="notification_header_touchable_height" />
@@ -3956,6 +3960,7 @@
   <java-symbol type="dimen" name="notification_big_picture_max_width"/>
   <java-symbol type="dimen" name="notification_right_icon_size"/>
   <java-symbol type="dimen" name="notification_right_icon_content_margin"/>
+  <java-symbol type="dimen" name="notification_2025_right_icon_content_margin"/>
   <java-symbol type="dimen" name="notification_actions_icon_drawable_size"/>
   <java-symbol type="dimen" name="notification_custom_view_max_image_height"/>
   <java-symbol type="dimen" name="notification_custom_view_max_image_width"/>
@@ -4441,6 +4446,11 @@
   <!-- For Attention Service -->
   <java-symbol type="integer" name="config_attentionMaximumExtension" />
 
+  <java-symbol type="bool" name="config_defaultPreventScreenTimeoutEnabled" />
+  <java-symbol type="integer" name="config_defaultPreventScreenTimeoutForMillis" />
+  <java-symbol type="integer" name="config_defaultMaxDurationBetweenUndimsMillis" />
+  <java-symbol type="integer" name="config_defaultUndimsRequired" />
+
   <java-symbol type="string" name="config_incidentReportApproverPackage" />
   <java-symbol type="array" name="config_restrictedImagesServices" />
 
@@ -5665,6 +5675,32 @@
   <java-symbol type="drawable" name="accessibility_autoclick_resume" />
   <java-symbol type="drawable" name="ic_accessibility_autoclick" />
 
+  <!-- Accessibility autoclick scroll panel related -->
+  <java-symbol type="layout" name="accessibility_autoclick_scroll_panel" />
+  <java-symbol type="dimen" name="accessibility_autoclick_scroll_panel_button_size" />
+  <java-symbol type="drawable" name="accessibility_autoclick_scroll_up" />
+  <java-symbol type="drawable" name="accessibility_autoclick_scroll_down" />
+  <java-symbol type="drawable" name="accessibility_autoclick_scroll_left" />
+  <java-symbol type="drawable" name="accessibility_autoclick_scroll_right" />
+  <java-symbol type="drawable" name="accessibility_autoclick_scroll_exit" />
+  <java-symbol type="string" name="accessibility_autoclick_scroll_up" />
+  <java-symbol type="string" name="accessibility_autoclick_scroll_down" />
+  <java-symbol type="string" name="accessibility_autoclick_scroll_left" />
+  <java-symbol type="string" name="accessibility_autoclick_scroll_right" />
+  <java-symbol type="string" name="accessibility_autoclick_scroll_exit" />
+  <java-symbol type="string" name="accessibility_autoclick_scroll_panel_title" />
+  <java-symbol type="id" name="accessibility_autoclick_scroll_panel" />
+  <java-symbol type="id" name="scroll_up_layout" />
+  <java-symbol type="id" name="scroll_down_layout" />
+  <java-symbol type="id" name="scroll_left_layout" />
+  <java-symbol type="id" name="scroll_right_layout" />
+  <java-symbol type="id" name="scroll_exit_layout" />
+  <java-symbol type="id" name="scroll_up" />
+  <java-symbol type="id" name="scroll_down" />
+  <java-symbol type="id" name="scroll_left" />
+  <java-symbol type="id" name="scroll_right" />
+  <java-symbol type="id" name="scroll_exit" />
+
   <!-- For HapticFeedbackConstants configurability defined at HapticFeedbackCustomization -->
   <java-symbol type="string" name="config_hapticFeedbackCustomizationFile" />
   <java-symbol type="xml" name="haptic_feedback_customization" />
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
index 33a46d0..6d86bd2 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
@@ -20,6 +20,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.os.Handler;
+import android.os.Looper;
 import android.util.PollingCheck;
 import android.view.View;
 
@@ -486,6 +488,42 @@
         });
     }
 
+    @Test
+    public void testCancelOnPendingEndListener() throws Throwable {
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final Handler handler = new Handler(Looper.getMainLooper());
+        final boolean[] endCalledRightAfterCancel = new boolean[2];
+        final AnimatorSet set = new AnimatorSet();
+        final ValueAnimatorTests.MyListener asListener = new ValueAnimatorTests.MyListener();
+        final ValueAnimatorTests.MyListener vaListener = new ValueAnimatorTests.MyListener();
+        final ValueAnimator va = new ValueAnimator();
+        va.setFloatValues(0f, 1f);
+        va.setDuration(30);
+        va.addUpdateListener(animation -> {
+            if (animation.getAnimatedFraction() == 1f) {
+                handler.post(() -> {
+                    set.cancel();
+                    endCalledRightAfterCancel[0] = vaListener.endCalled;
+                    endCalledRightAfterCancel[1] = asListener.endCalled;
+                    endLatch.countDown();
+                });
+            }
+        });
+        set.addListener(asListener);
+        va.addListener(vaListener);
+        set.play(va);
+
+        ValueAnimator.setPostNotifyEndListenerEnabled(true);
+        try {
+            handler.post(set::start);
+            assertTrue(endLatch.await(1, TimeUnit.SECONDS));
+            assertTrue(endCalledRightAfterCancel[0]);
+            assertTrue(endCalledRightAfterCancel[1]);
+        } finally {
+            ValueAnimator.setPostNotifyEndListenerEnabled(false);
+        }
+    }
+
     private void waitForOnUiThread(PollingCheck.PollingCheckCondition condition) {
         final boolean[] value = new boolean[1];
         PollingCheck.waitFor(() -> {
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index 0469846..a55909f 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -922,6 +922,36 @@
     }
 
     @Test
+    public void testCancelOnPendingEndListener() throws Throwable {
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final Handler handler = new Handler(Looper.getMainLooper());
+        final boolean[] endCalledRightAfterCancel = new boolean[1];
+        final MyListener listener = new MyListener();
+        final ValueAnimator va = new ValueAnimator();
+        va.setFloatValues(0f, 1f);
+        va.setDuration(30);
+        va.addUpdateListener(animation -> {
+            if (animation.getAnimatedFraction() == 1f) {
+                handler.post(() -> {
+                    va.cancel();
+                    endCalledRightAfterCancel[0] = listener.endCalled;
+                    endLatch.countDown();
+                });
+            }
+        });
+        va.addListener(listener);
+
+        ValueAnimator.setPostNotifyEndListenerEnabled(true);
+        try {
+            handler.post(va::start);
+            assertThat(endLatch.await(1, TimeUnit.SECONDS)).isTrue();
+            assertThat(endCalledRightAfterCancel[0]).isTrue();
+        } finally {
+            ValueAnimator.setPostNotifyEndListenerEnabled(false);
+        }
+    }
+
+    @Test
     public void testZeroDuration() throws Throwable {
         // Run two animators with zero duration, with one running forward and the other one
         // backward. Check that the animations start and finish with the correct end fractions.
@@ -1182,6 +1212,7 @@
             assertEquals(A1_START_VALUE, a1.getAnimatedValue());
         });
     }
+
     class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
         boolean wasRunning = false;
         long firstRunningFrameTime = -1;
@@ -1207,7 +1238,7 @@
         }
     }
 
-    class MyListener implements Animator.AnimatorListener {
+    static class MyListener implements Animator.AnimatorListener {
         boolean startCalled = false;
         boolean cancelCalled = false;
         boolean endCalled = false;
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index f89e441..157c74a 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -371,16 +371,6 @@
 
     @Test
     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
-    public void testHasPromotableStyle_bigPicture() {
-        Notification n = new Notification.Builder(mContext, "test")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon)
-                .setStyle(new Notification.BigPictureStyle())
-                .build();
-        assertThat(n.hasPromotableStyle()).isTrue();
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
     public void testHasPromotableStyle_bigText() {
         Notification n = new Notification.Builder(mContext, "test")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -391,6 +381,16 @@
 
     @Test
     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
+    public void testHasPromotableStyle_no_bigPictureStyle() {
+        Notification n = new Notification.Builder(mContext, "test")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setStyle(new Notification.BigPictureStyle())
+                .build();
+        assertThat(n.hasPromotableStyle()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
     public void testHasPromotableStyle_no_messagingStyle() {
         Notification.MessagingStyle style = new Notification.MessagingStyle("self name")
                 .setGroupConversation(true)
diff --git a/core/tests/coretests/src/android/util/ArrayMapTest.java b/core/tests/coretests/src/android/util/ArrayMapTest.java
index 711ff94..c7efe6f9 100644
--- a/core/tests/coretests/src/android/util/ArrayMapTest.java
+++ b/core/tests/coretests/src/android/util/ArrayMapTest.java
@@ -14,14 +14,18 @@
 
 package android.util;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.annotations.Presubmit;
 import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,6 +36,7 @@
  * Unit tests for ArrayMap that don't belong in CTS.
  */
 @LargeTest
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ArrayMapTest {
     private static final String TAG = "ArrayMapTest";
@@ -51,6 +56,7 @@
      * @throws Exception
      */
     @Test
+    @Ignore("Failing; b/399137661")
     @IgnoreUnderRavenwood(reason = "Long test runtime")
     public void testConcurrentModificationException() throws Exception {
         final int TEST_LEN_MS = 5000;
@@ -118,4 +124,49 @@
             }
         }
     }
+
+    @Test
+    public void testToString() {
+        map.put("1", "One");
+        map.put("2", "Two");
+        map.put("3", "Five");
+        map.put("3", "Three");
+
+        assertThat(map.toString()).isEqualTo("{1=One, 2=Two, 3=Three}");
+        assertThat(map.keySet().toString()).isEqualTo("[1, 2, 3]");
+        assertThat(map.values().toString()).isEqualTo("[One, Two, Three]");
+    }
+
+    @Test
+    public void testToStringRecursive() {
+        ArrayMap<Object, Object> weird = new ArrayMap<>();
+        weird.put("1", weird);
+
+        assertThat(weird.toString()).isEqualTo("{1=(this Map)}");
+        assertThat(weird.keySet().toString()).isEqualTo("[1]");
+        assertThat(weird.values().toString()).isEqualTo("[{1=(this Map)}]");
+    }
+
+    @Test
+    public void testToStringRecursiveKeySet() {
+        ArrayMap<Object, Object> weird = new ArrayMap<>();
+        weird.put("1", weird.keySet());
+        weird.put(weird.keySet(), "2");
+
+        assertThat(weird.toString()).isEqualTo("{1=[1, (this KeySet)], [1, (this KeySet)]=2}");
+        assertThat(weird.keySet().toString()).isEqualTo("[1, (this KeySet)]");
+        assertThat(weird.values().toString()).isEqualTo("[[1, (this KeySet)], 2]");
+    }
+
+    @Test
+    public void testToStringRecursiveValues() {
+        ArrayMap<Object, Object> weird = new ArrayMap<>();
+        weird.put("1", weird.values());
+        weird.put(weird.values(), "2");
+
+        assertThat(weird.toString()).isEqualTo(
+                "{1=[(this ValuesCollection), 2], [(this ValuesCollection), 2]=2}");
+        assertThat(weird.keySet().toString()).isEqualTo("[1, [(this ValuesCollection), 2]]");
+        assertThat(weird.values().toString()).isEqualTo("[(this ValuesCollection), 2]");
+    }
 }
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index 4d6c30e..215c162 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -541,24 +541,30 @@
             throws RemoteException, InterruptedException {
         // Setup a callback that unregisters itself after the gesture is finished but before the
         // progress is animated back to 0f
-        final AtomicBoolean unregisterOnProgressUpdate = new AtomicBoolean(false);
+        final AtomicBoolean unregisterOnNextCallbackInvocation = new AtomicBoolean(false);
         final AtomicInteger onBackInvokedCalled = new AtomicInteger(0);
         final CountDownLatch onBackCancelledCalled = new CountDownLatch(1);
         OnBackAnimationCallback onBackAnimationCallback = new OnBackAnimationCallback() {
             @Override
             public void onBackProgressed(@NonNull BackEvent backEvent) {
-                if (unregisterOnProgressUpdate.get()) {
+                if (unregisterOnNextCallbackInvocation.getAndSet(false)) {
                     mDispatcher.unregisterOnBackInvokedCallback(this);
                 }
             }
 
             @Override
             public void onBackInvoked() {
+                if (unregisterOnNextCallbackInvocation.getAndSet(false)) {
+                    mDispatcher.unregisterOnBackInvokedCallback(this);
+                }
                 onBackInvokedCalled.getAndIncrement();
             }
 
             @Override
             public void onBackCancelled() {
+                if (unregisterOnNextCallbackInvocation.getAndSet(false)) {
+                    mDispatcher.unregisterOnBackInvokedCallback(this);
+                }
                 onBackCancelledCalled.countDown();
             }
         };
@@ -572,7 +578,7 @@
 
         // simulate back gesture finished and onBackCancelled() called, which starts the progress
         // animation back to 0f. On the first progress emission, the callback will unregister itself
-        unregisterOnProgressUpdate.set(true);
+        unregisterOnNextCallbackInvocation.set(true);
         callbackInfo.getCallback().onBackCancelled();
         waitForIdle();
         onBackCancelledCalled.await(1000, TimeUnit.MILLISECONDS);
diff --git a/core/tests/vibrator/src/android/os/ExternalVibrationTest.java b/core/tests/vibrator/src/android/os/ExternalVibrationTest.java
index 8741907..9c9d502 100644
--- a/core/tests/vibrator/src/android/os/ExternalVibrationTest.java
+++ b/core/tests/vibrator/src/android/os/ExternalVibrationTest.java
@@ -49,4 +49,22 @@
         assertThat(restored.getAudioAttributes()).isEqualTo(original.getAudioAttributes());
         assertThat(restored.getToken()).isEqualTo(original.getToken());
     }
+
+    @Test
+    public void testSerialization_systemUsage() {
+        ExternalVibration original =
+                new ExternalVibration(
+                        123,
+                        "pkg",
+                        new AudioAttributes.Builder()
+                                .setSystemUsage(AudioAttributes.USAGE_SPEAKER_CLEANUP)
+                                .build(),
+                        IExternalVibrationController.Stub.asInterface(new Binder()));
+        Parcel p = Parcel.obtain();
+        original.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        ExternalVibration restored = ExternalVibration.CREATOR.createFromParcel(p);
+
+        assertThat(restored.getAudioAttributes()).isEqualTo(original.getAudioAttributes());
+    }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index e141f70..da25da1 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -54,6 +54,8 @@
 import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSplit;
 import static androidx.window.extensions.embedding.TaskFragmentContainer.OverlayContainerRestoreParams;
 
+import static com.android.window.flags.Flags.activityEmbeddingDelayTaskFragmentFinishForActivityLaunch;
+
 import android.annotation.CallbackExecutor;
 import android.app.Activity;
 import android.app.ActivityClient;
@@ -815,11 +817,17 @@
                         .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
                 mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
             } else if (!container.isWaitingActivityAppear()) {
-                // Do not finish the container before the expected activity appear until
-                // timeout.
-                mTransactionManager.getCurrentTransactionRecord()
-                        .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
-                mPresenter.cleanupContainer(wct, container, true /* shouldFinishDependent */);
+                if (activityEmbeddingDelayTaskFragmentFinishForActivityLaunch()
+                        && container.hasActivityLaunchHint()) {
+                    // If we have recently attempted to launch a new activity into this
+                    // TaskFragment, we schedule delayed cleanup. If the new activity appears in
+                    // this TaskFragment, we no longer need to finish the TaskFragment.
+                    container.scheduleDelayedTaskFragmentCleanup();
+                } else {
+                    mTransactionManager.getCurrentTransactionRecord()
+                            .setOriginType(TASK_FRAGMENT_TRANSIT_CLOSE);
+                    mPresenter.cleanupContainer(wct, container, true /* shouldFinishDependent */);
+                }
             }
         } else if (wasInPip && isInPip) {
             // No update until exit PIP.
@@ -3164,6 +3172,9 @@
                     // TODO(b/229680885): skip override launching TaskFragment token by split-rule
                     options.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
                             launchedInTaskFragment.getTaskFragmentToken());
+                    if (activityEmbeddingDelayTaskFragmentFinishForActivityLaunch()) {
+                        launchedInTaskFragment.setActivityLaunchHint();
+                    }
                     mCurrentIntent = intent;
                 } else {
                     transactionRecord.abort();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index b3e003e..6fa855e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -18,6 +18,8 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
+import static com.android.window.flags.Flags.activityEmbeddingDelayTaskFragmentFinishForActivityLaunch;
+
 import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.WindowConfiguration.WindowingMode;
@@ -53,6 +55,8 @@
 class TaskFragmentContainer {
     private static final int APPEAR_EMPTY_TIMEOUT_MS = 3000;
 
+    private static final int DELAYED_TASK_FRAGMENT_CLEANUP_TIMEOUT_MS = 500;
+
     /** Parcelable data of this TaskFragmentContainer. */
     @NonNull
     private final ParcelableTaskFragmentContainerData mParcelableData;
@@ -165,6 +169,18 @@
      */
     private boolean mLastDimOnTask;
 
+    /** The timestamp of the latest pending activity launch attempt. 0 means no pending launch. */
+    private long mLastActivityLaunchTimestampMs = 0;
+
+    /**
+     * The scheduled runnable for delayed TaskFragment cleanup. This is used when the TaskFragment
+     * becomes empty, but we expect a new activity to appear in it soon.
+     *
+     * It should be {@code null} when not scheduled.
+     */
+    @Nullable
+    private Runnable mDelayedTaskFragmentCleanupRunnable;
+
     /**
      * Creates a container with an existing activity that will be re-parented to it in a window
      * container transaction.
@@ -540,6 +556,10 @@
             mAppearEmptyTimeout = null;
         }
 
+        if (activityEmbeddingDelayTaskFragmentFinishForActivityLaunch()) {
+            clearActivityLaunchHintIfNecessary(mInfo, info);
+        }
+
         mHasCrossProcessActivities = false;
         mInfo = info;
         if (mInfo == null || mInfo.isEmpty()) {
@@ -1064,6 +1084,89 @@
         return isOverlay() && mParcelableData.mAssociatedActivityToken != null;
     }
 
+    /**
+     * Indicates whether there is possibly a pending activity launching into this TaskFragment.
+     *
+     * This should only be used as a hint because we cannot reliably determine if the new activity
+     * is going to appear into this TaskFragment.
+     *
+     * TODO(b/293800510) improve activity launch tracking in TaskFragment.
+     */
+    boolean hasActivityLaunchHint() {
+        if (mLastActivityLaunchTimestampMs == 0) {
+            return false;
+        }
+        if (System.currentTimeMillis() > mLastActivityLaunchTimestampMs + APPEAR_EMPTY_TIMEOUT_MS) {
+            // The hint has expired after APPEAR_EMPTY_TIMEOUT_MS.
+            mLastActivityLaunchTimestampMs = 0;
+            return false;
+        }
+        return true;
+    }
+
+    /** Records the latest activity launch attempt. */
+    void setActivityLaunchHint() {
+        mLastActivityLaunchTimestampMs = System.currentTimeMillis();
+    }
+
+    /**
+     * If we get a new info showing that the TaskFragment has more activities than the previous
+     * info, we clear the new activity launch hint.
+     *
+     * Note that this is not a reliable way and cannot cover situations when the attempted
+     * activity launch did not cause TaskFragment info activity count changes, such as trampoline
+     * launches or single top launches.
+     *
+     * TODO(b/293800510) improve activity launch tracking in TaskFragment.
+     */
+    private void clearActivityLaunchHintIfNecessary(
+            @Nullable TaskFragmentInfo oldInfo, @NonNull TaskFragmentInfo newInfo) {
+        final int previousActivityCount = oldInfo == null ? 0 : oldInfo.getRunningActivityCount();
+        if (newInfo.getRunningActivityCount() > previousActivityCount) {
+            mLastActivityLaunchTimestampMs = 0;
+            cancelDelayedTaskFragmentCleanup();
+        }
+    }
+
+    /**
+     * Schedules delayed TaskFragment cleanup due to pending activity launch. The scheduled cleanup
+     * will be canceled if a new activity appears in this TaskFragment.
+     */
+    void scheduleDelayedTaskFragmentCleanup() {
+        if (mDelayedTaskFragmentCleanupRunnable != null) {
+            // Remove the previous callback if there is already one scheduled.
+            mController.getHandler().removeCallbacks(mDelayedTaskFragmentCleanupRunnable);
+        }
+        mDelayedTaskFragmentCleanupRunnable = new Runnable() {
+            @Override
+            public void run() {
+                synchronized (mController.mLock) {
+                    if (mDelayedTaskFragmentCleanupRunnable != this) {
+                        // The scheduled cleanup runnable has been canceled or rescheduled, so
+                        // skipping.
+                        return;
+                    }
+                    if (isEmpty()) {
+                        mLastActivityLaunchTimestampMs = 0;
+                        mController.onTaskFragmentAppearEmptyTimeout(
+                                TaskFragmentContainer.this);
+                    }
+                    mDelayedTaskFragmentCleanupRunnable = null;
+                }
+            }
+        };
+        mController.getHandler().postDelayed(
+                mDelayedTaskFragmentCleanupRunnable, DELAYED_TASK_FRAGMENT_CLEANUP_TIMEOUT_MS);
+    }
+
+    private void cancelDelayedTaskFragmentCleanup() {
+        if (mDelayedTaskFragmentCleanupRunnable == null) {
+            return;
+        }
+        mController.getHandler().removeCallbacks(mDelayedTaskFragmentCleanupRunnable);
+        mDelayedTaskFragmentCleanupRunnable = null;
+    }
+
     @Override
     public String toString() {
         return toString(true /* includeContainersToFinishOnExit */);
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 1e72d64..ab28046 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -194,3 +194,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "enable_gsf"
+    namespace: "multitasking"
+    description: "Applies GSF font styles to multitasking."
+    bug: "400534660"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt b/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt
index 24f43d3..5777cb0 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt
@@ -94,6 +94,7 @@
 
         private val splitScreenModeName =
             when (splitScreenMode) {
+                SplitScreenMode.UNSUPPORTED -> "_split_unsupported"
                 SplitScreenMode.NONE -> ""
                 SplitScreenMode.SPLIT_50_50 -> "_split_50_50"
                 SplitScreenMode.SPLIT_10_90 -> "_split_10_90"
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
index 477d207..16e098b 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
@@ -53,15 +53,12 @@
 
         <com.android.wm.shell.windowdecor.HandleMenuImageButton
             android:id="@+id/collapse_menu_button"
-            android:layout_width="16dp"
-            android:layout_height="16dp"
-            android:layout_marginEnd="16dp"
-            android:layout_marginStart="14dp"
+            android:padding="16dp"
             android:contentDescription="@string/collapse_menu_text"
-            android:src="@drawable/ic_baseline_expand_more_24"
+            android:src="@drawable/ic_baseline_expand_more_16"
             android:rotation="180"
             android:tint="@androidprv:color/materialColorOnSurface"
-            android:background="?android:selectableItemBackgroundBorderless"/>
+            style="@style/DesktopModeHandleMenuWindowingButton"/>
     </LinearLayout>
 
     <LinearLayout
@@ -145,6 +142,7 @@
             android:contentDescription="@string/screenshot_text"
             android:text="@string/screenshot_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_screenshot"
+            android:importantForAccessibility="no"
             style="@style/DesktopModeHandleMenuActionButton"/>
 
         <com.android.wm.shell.windowdecor.HandleMenuActionButton
@@ -152,6 +150,7 @@
             android:contentDescription="@string/new_window_text"
             android:text="@string/new_window_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_new_window"
+            android:importantForAccessibility="no"
             style="@style/DesktopModeHandleMenuActionButton"/>
 
         <com.android.wm.shell.windowdecor.HandleMenuActionButton
@@ -159,6 +158,7 @@
             android:contentDescription="@string/manage_windows_text"
             android:text="@string/manage_windows_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_manage_windows"
+            android:importantForAccessibility="no"
             style="@style/DesktopModeHandleMenuActionButton"/>
 
         <com.android.wm.shell.windowdecor.HandleMenuActionButton
@@ -166,6 +166,7 @@
             android:contentDescription="@string/change_aspect_ratio_text"
             android:text="@string/change_aspect_ratio_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio"
+            android:importantForAccessibility="no"
             style="@style/DesktopModeHandleMenuActionButton"/>
     </LinearLayout>
 
@@ -185,6 +186,7 @@
             android:text="@string/open_in_browser_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_open_in_browser"
             style="@style/DesktopModeHandleMenuActionButton"
+            android:importantForAccessibility="no"
             android:layout_width="0dp"
             android:layout_weight="1"/>
 
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml
index 0163c01..de38e6f 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml
@@ -34,5 +34,6 @@
 
     <com.android.wm.shell.windowdecor.MarqueedTextView
         android:id="@+id/label"
+        android:importantForAccessibility="no"
         style="@style/DesktopModeHandleMenuActionButtonTextView"/>
 </LinearLayout>
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 4dffce5..61dbb69 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Links 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Links 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Volskerm regs"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Ruil boonste app met onderste een"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Ruil linkerapp met regterapp"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Volskerm bo"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Bo 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bo 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Herbegin"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Moenie weer wys nie"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dubbeltik om\nhierdie app te skuif"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimeer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Stel <xliff:g id="APP_NAME">%1$s</xliff:g> terug"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimeer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Maak <xliff:g id="APP_NAME">%1$s</xliff:g> toe"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Terug"</string>
     <string name="handle_text" msgid="4419667835599523257">"Apphandvatsel"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Appikoon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Verander grootte van linkerkantse venster"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Verander grootte van regterkantse venster"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimeer of stel venstergrootte terug"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimeer appvenstergrootte"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Stel venstergrootte terug"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimeer appvenster"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Maak appvenster toe"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Maak By Verstek Oop-instellings"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Kies hoe om webskakels vir hierdie app oop te maak"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In die app"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 0881e77..52008a6 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ግራ 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ግራ 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"የቀኝ ሙሉ ማያ ገፅ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ከላይ ያለውን መተግበሪያ ከታች ባለው ቀይር"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"በግራ ያለውን መተግበሪያን በቀኝ ባለው ቀይር"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"የላይ ሙሉ ማያ ገፅ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ከላይ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ከላይ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"እንደገና ያስጀምሩ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ዳግም አታሳይ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ይህን መተግበሪያ\nለማንቀሳቀስ ሁለቴ መታ ያድርጉ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን አሳድግ"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ወደነበረበት መልስ"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን አሳንስ"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ዝጋ"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ተመለስ"</string>
     <string name="handle_text" msgid="4419667835599523257">"የመተግበሪያ መያዣ"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"የመተግበሪያ አዶ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"መስኮትን ወደ ግራ መጠን ቀይር"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"መስኮትን ወደ ቀኝ መጠን ቀይር"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"የመተግበሪያ መስኮት መጠንን አሳድግ"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"የመስኮት መጠንን ወደነበረበት መልስ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"የመተግበሪያ መስኮትን አሳንስ"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"የመተግበሪያ መስኮትን ዝጋ"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"በነባሪ ቅንብሮች ክፈት"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ለዚህ የድር መተግበሪያ አገናኙን እንዴት እንደሚከፍቱ ይምረጡ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"በመተግበሪያው ውስጥ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 9cc49aa..65dd965 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ضبط حجم النافذة اليسرى ليكون ٥٠%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ضبط حجم النافذة اليسرى ليكون ٣٠%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"عرض النافذة اليمنى بملء الشاشة"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"تبديل التطبيق العلوي بالسفلي"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"تبديل التطبيق الأيسر بالأيمن"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"عرض النافذة العلوية بملء الشاشة"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ضبط حجم النافذة العلوية ليكون ٧٠%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ضبط حجم النافذة العلوية ليكون ٥٠%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"إعادة التشغيل"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"عدم عرض مربّع حوار التأكيد مجددًا"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"انقر مرّتَين لنقل\nهذا التطبيق."</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"تكبير \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"استعادة \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"تصغير \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="close_button_text" msgid="4544839489310949894">"إغلاق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="back_button_text" msgid="1469718707134137085">"رجوع"</string>
     <string name="handle_text" msgid="4419667835599523257">"مقبض التطبيق"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"رمز التطبيق"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"تغيير حجم النافذة بمحاذاتها إلى اليمين"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"تغيير حجم النافذة بمحاذاتها إلى اليسار"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"تكبير حجم النافذة أو استعادته"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"تكبير نافذة التطبيق"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"استعادة حجم النافذة"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"تصغير نافذة التطبيق"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"إغلاق نافذة التطبيق"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"إعدادات الفتح تلقائيًا"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اختيار طريقة فتح روابط الويب لهذا التطبيق"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"في التطبيق"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index c59753c..919447e 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"বাওঁফালৰ স্ক্ৰীনখন ৫০% কৰক"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"বাওঁফালৰ স্ক্ৰীনখন ৩০% কৰক"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"সোঁফালৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"একেবাৰে তলৰ সৈতে একেবাৰে ওপৰৰ এপ্‌টো সলনাসলনি কৰক"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"সোঁফালৰ সৈতে বাওঁফালৰ এপ্‌টো সলনাসলনি কৰক"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"শীৰ্ষ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ স্ক্ৰীনখন ৭০% কৰক"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ স্ক্ৰীনখন ৫০% কৰক"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ৰিষ্টাৰ্ট কৰক"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"পুনৰাই নেদেখুৱাব"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"এই এপ্‌টো\nস্থানান্তৰ কৰিবলৈ দুবাৰ টিপক"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> মেক্সিমাইজ কৰক"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক পুনঃস্থাপন কৰক"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> মিনিমাইজ কৰক"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> বন্ধ কৰক"</string>
     <string name="back_button_text" msgid="1469718707134137085">"উভতি যাওক"</string>
     <string name="handle_text" msgid="4419667835599523257">"এপৰ হেণ্ডেল"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"এপৰ চিহ্ন"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"সোঁফাললৈ ৱিণ্ড’ৰ আকাৰ সলনি কৰক"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"বাওঁফাললৈ ৱিণ্ড’ৰ আকাৰ সলনি কৰক"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ৱিণ্ড’ৰ আকাৰ মেক্সিমাইজ বা পুনঃস্থাপন কৰক"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"এপ্‌ ৱিণ্ড’ৰ আকাৰ মেক্সিমাইজ কৰক"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ৱিণ্ড’ৰ আকাৰ পুনঃস্থাপন কৰক"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"এপ্‌ ৱিণ্ড’ মিনিমাইজ কৰক"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"এপ্‌ ৱিণ্ড’ বন্ধ কৰক"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ডিফ’ল্ট ছেটিং খোলক"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"এই এপ্‌টোৰ বাবে কিদৰে ৱেব লিংক খুলিব পাৰি সেয়া বাছনি কৰক"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"এপ্‌টোত"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 63e610b..846240f 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sol 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sol 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağ tam ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Yuxarıdakı tətbiqi aşağıdakı ilə dəyişdirin"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Soldakı tətbiqi sağdakı ilə dəyişdirin"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yuxarı tam ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yuxarı 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Yenidən başladın"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Yenidən göstərməyin"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tətbiqi köçürmək üçün\niki dəfə toxunun"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Böyüdün: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Bərpa edin: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Kiçildin: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Bağlayın: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Geriyə"</string>
     <string name="handle_text" msgid="4419667835599523257">"Tətbiq ləqəbi"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Tətbiq ikonası"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pəncərə ölçüsünü sola dəyişin"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pəncərə ölçüsünü sağa dəyişin"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Tətbiq pəncərəsi ölçüsünü böyüdün"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Pəncərə ölçüsünü bərpa edin"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Tətbiq pəncərəsini kiçildin"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Tətbiq pəncərəsini bağlayın"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Defolt ayarlarla açın"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu tətbiq üçün veb-linklərin necə açılacağını seçin"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Tətbiqdə"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 4f3da2b..d686da9 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левы экран – 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левы экран – 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Правы экран – поўнаэкранны рэжым"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Памяняць месцамі верхнюю і ніжнюю праграмы"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Памяняць месцамі левую і правую праграмы"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхні экран – поўнаэкранны рэжым"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхні экран – 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхні экран – 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перазапусціць"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Больш не паказваць"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Каб перамясціць праграму,\nнацісніце двойчы"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Разгарнуць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Аднавіць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Згарнуць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Закрыць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Маркер праграмы"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Значок праграмы"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Змяніць памер акна і перамясціць да левага краю"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Змяніць памер акна і перамясціць да правага краю"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Разгарнуць акно ці аднавіць яго памер"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Разгарнуць акно праграмы"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Аднавіць памер акна"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Згарнуць акно праграмы"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Закрыць акно праграмы"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Налады параметра \"Адкрываць стандартна\""</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Выберыце, як гэта праграма будзе адкрываць вэб-спасылкі"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У праграме"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 3f867a22..984c20f 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ляв екран: 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ляв екран: 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десен екран: Показване на цял екран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Размяна на горното и долното приложение"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Размяна на лявото и дясното приложение"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горен екран: Показване на цял екран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горен екран: 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горен екран: 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартиране"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Да не се показва отново"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Докоснете двукратно, за да\nпреместите това приложение"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Увеличаване на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Възстановяване на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Намаляване на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Затваряне на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Манипулатор за приложението"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Икона на приложението"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Преоразмеряване на прозореца наляво"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Преоразмеряване на прозореца надясно"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Увеличаване или възстановяване на размера на прозореца"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Увеличаване на размера на прозореца на приложението"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Възстановяване на размера на прозореца"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Намаляване на прозореца на приложението"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Затваряне на прозореца на приложението"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Отваряне на настройките по подразбиране"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете как да се отварят уеб връзките за това приложение"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"В приложението"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 3967d4b..dd5653c 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"৫০% বাকি আছে"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"৩০% বাকি আছে"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ডান দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"নিচেরটির মাধ্যমে উপরের অ্যাপ অদল বদল করে নিন"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ডানদিকের মাধ্যমে বাঁদিকের অ্যাপ অদল বদল করে নিন"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"উপর দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ ৭০%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ ৫০%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"রিস্টার্ট করুন"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"আর দেখতে চাই না"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"এই অ্যাপ সরাতে\nডবল ট্যাপ করুন"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> বড় করুন"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> আবার ফিরিয়ে আনুন"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ছোট করুন"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> বন্ধ করুন"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ফিরে যান"</string>
     <string name="handle_text" msgid="4419667835599523257">"অ্যাপের হ্যান্ডেল"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"অ্যাপ আইকন"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"বাঁদিকে উইন্ডো রিসাইজ করুন"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ডানদিকে উইন্ডো রিসাইজ করুন"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"অ্যাপ উইন্ডোর সাইজ বাড়ান"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"উইন্ডোর সাইজ ফিরিয়ে আনুন"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"অ্যাপ উইন্ডো ছোট করুন"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"অ্যাপ উইন্ডো বন্ধ করুন"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ডিফল্ট হিসেবে থাকা সেটিংস খুলুন"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"এই অ্যাপের জন্য কীভাবে ওয়েব লিঙ্ক খুলবেন তা বেছে নিন"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"অ্যাপের মধ্যে"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 6b59d91..01e0515 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevo 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Lijevo 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desno cijeli ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamjena gornje aplikacije donjom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamjena lijeve aplikacije desnom"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Gore cijeli ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gore 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gore 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Ponovo pokreni"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovo"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dodirnite dvaput da\npomjerite aplikaciju"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimiziranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Vraćanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimiziranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zatvaranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Nazad"</string>
     <string name="handle_text" msgid="4419667835599523257">"Ručica aplikacije"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promjena veličine prozora i poravnanje lijevo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promjena veličine prozora i poravnanje desno"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziranje ili vraćanje veličine prozora"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimiziranje veličine prozora aplikacije"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Vraćanje veličine prozora"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimiziranje prozora aplikacije"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zatvaranje prozora aplikacije"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvaranje prema zadanim postavkama"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja web linkova za ovu aplikaciju"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 955e5cc..77cf94b 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pantalla esquerra al 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pantalla esquerra al 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla dreta completa"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Intercanvia l\'aplicació superior amb la inferior"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Intercanvia l\'aplicació esquerra amb la dreta"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Pantalla superior al 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Pantalla superior al 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reinicia"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No ho tornis a mostrar"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Fes doble toc per\nmoure aquesta aplicació"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximitza <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaura <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimitza <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Tanca <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Enrere"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identificador de l\'aplicació"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icona de l\'aplicació"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Canvia la mida de la finestra a l\'esquerra"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Canvia la mida de la finestra a la dreta"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximitza o restaura la mida de la finestra"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximitza la mida de la finestra de l\'aplicació"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaura la mida de la finestra"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimitza la finestra de l\'aplicació"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Tanca la finestra de l\'aplicació"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configuració d\'obertura predeterminada"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Tria com vols obrir els enllaços web per a aquesta aplicació"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"A l\'aplicació"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 673f7fc..1a414ba 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % vlevo"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % vlevo"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pravá část na celou obrazovku"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Prohodit horní a dolní aplikaci"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Prohodit levou a pravou aplikaci"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Horní část na celou obrazovku"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % nahoře"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % nahoře"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartovat"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Tuto zprávu příště nezobrazovat"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvojitým klepnutím\npřesunete aplikaci"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximalizovat aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Obnovit aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimalizovat aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zavřít aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Zpět"</string>
     <string name="handle_text" msgid="4419667835599523257">"Popisovač aplikace"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikace"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Přichytit okno vlevo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Přichytit okno vpravo"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximalizovat nebo obnovit velikost okna"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximalizovat velikost okna aplikace"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Obnovit velikost okna"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimalizovat okno aplikace"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zavřít okno aplikace"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otevírat podle výchozího nastavení"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Určete, jak se v této aplikaci mají otevírat webové odkazy"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikaci"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 635df33..07f1969 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Venstre 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Venstre 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Vis højre del i fuld skærm"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Byt om på den øverste og nederste app"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Byt om på den venstre og højre app"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Vis øverste del i fuld skærm"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Øverste 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Øverste 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Genstart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Vis ikke igen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tryk to gange\nfor at flytte appen"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Gendan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Luk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Tilbage"</string>
     <string name="handle_text" msgid="4419667835599523257">"Apphåndtag"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Juster størrelsen på vinduet til venstre"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Juster størrelsen på vinduet til højre"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimer eller gendan vinduesstørrelse"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimer størrelsen på appvinduet"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Gendan størrelsen på vinduet"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimer appvindue"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Luk appvindue"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Indstillinger for automatisk åbning"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Vælg, hvordan denne app skal åben weblinks"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 5be8b0b..7a8f2d9 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % links"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % links"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Vollbild rechts"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Obere und untere App vertauschen"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Linke und rechte App vertauschen"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Vollbild oben"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % oben"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % oben"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Neu starten"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nicht mehr anzeigen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Zum Verschieben\ndoppeltippen"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> maximieren"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> wiederherstellen"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> minimieren"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> schließen"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Zurück"</string>
     <string name="handle_text" msgid="4419667835599523257">"App-Ziehpunkt"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App-Symbol"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Fenstergröße nach links anpassen"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Fenstergröße nach rechts anpassen"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Fenstergröße maximieren oder wiederherstellen"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"App-Fenster maximieren"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Fenstergröße wiederherstellen"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"App-Fenster minimieren"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"App-Fenster schließen"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Einstellungen für die Option „Standardmäßig öffnen“"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Festlegen, wie Weblinks für diese App geöffnet werden"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In der App"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index bd3cf05..e2477d3 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Αριστερή 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Αριστερή 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Δεξιά πλήρης οθόνη"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Εναλλαγή της εφαρμογής στην κορυφή με αυτή στο κάτω μέρος"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Εναλλαγή της εφαρμογής στα αριστερά με αυτή στα δεξιά"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Πάνω πλήρης οθόνη"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Πάνω 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Πάνω 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Επανεκκίνηση"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Να μην εμφανιστεί ξανά"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Πατήστε δύο φορές για\nμετακίνηση αυτής της εφαρμογής"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Μεγιστοποίηση <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Επαναφορά <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Ελαχιστοποίηση <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Κλείσιμο <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Πίσω"</string>
     <string name="handle_text" msgid="4419667835599523257">"Λαβή εφαρμογής"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Εικονίδιο εφαρμογής"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Αλλαγή μεγέθους παραθύρου προς τα αριστερά"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Αλλαγή μεγέθους παραθύρου προς τα δεξιά"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Μεγιστοποίηση μεγέθους παραθύρου εφαρμογής"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Επαναφορά μεγέθους παραθύρου"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Ελαχιστοποίηση παραθύρου εφαρμογής"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Κλείσιμο παραθύρου εφαρμογής"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Άνοιγμα ρυθμίσεων από προεπιλογή"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Επιλογή τρόπου ανοίγματος συνδέσμων ιστού για την εφαρμογή"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Στην εφαρμογή"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index b137d80..bed6e50 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Swap top app with bottom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Swap left app with right"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restore <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Close <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Back"</string>
     <string name="handle_text" msgid="4419667835599523257">"App handle"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximise app window size"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restore window size"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimise app window"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Close app window"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index b137d80..bed6e50 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Swap top app with bottom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Swap left app with right"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restore <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Close <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Back"</string>
     <string name="handle_text" msgid="4419667835599523257">"App handle"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximise app window size"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restore window size"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimise app window"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Close app window"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index b137d80..bed6e50 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Swap top app with bottom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Swap left app with right"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restore <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Close <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Back"</string>
     <string name="handle_text" msgid="4419667835599523257">"App handle"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximise app window size"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restore window size"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimise app window"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Close app window"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 1d5d385..2b7769d 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda: 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Izquierda: 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla derecha completa"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Intercambiar la app superior con la inferior"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Intercambiar la app de la izquierda con la de la derecha"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Superior: 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior: 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No volver a mostrar"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Presiona dos veces\npara mover esta app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restablecer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Cerrar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
     <string name="handle_text" msgid="4419667835599523257">"Controlador de la app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ícono de la app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ajustar el tamaño de la ventana hacia la izquierda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ajustar el tamaño de la ventana hacia la derecha"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar o restablecer el tamaño de la ventana"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar el tamaño de la ventana de la app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restablecer el tamaño de la ventana"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar ventana de la app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Cerrar ventana de la app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir con la configuración predeterminada"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Elige cómo abrir vínculos web para esta app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"En la app"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index dfa7869..afb1034 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Izquierda 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla derecha completa"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Intercambiar aplicación superior con inferior"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Intercambiar aplicación izquierda con derecha"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Superior 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No volver a mostrar"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toca dos veces para\nmover esta aplicación"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Cerrar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
     <string name="handle_text" msgid="4419667835599523257">"Controlador de la aplicación"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icono de la aplicación"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Cambiar tamaño de la ventana a la izquierda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Cambiar tamaño de la ventana a la derecha"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar o restaurar tamaño de la ventana"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar tamaño de la ventana de la aplicación"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar tamaño de la ventana"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar ventana de la aplicación"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Cerrar ventana de la aplicación"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir con los ajustes predeterminados"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Elige cómo quieres abrir los enlaces web de esta aplicación"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"En la aplicación"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 294b7fe..61ca3e0 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasak: 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vasak: 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Parem täisekraan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Ülemise ja alumise rakenduse vahetamine"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Vasaku ja parema rakenduse vahetamine"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ülemine täisekraan"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Ülemine: 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ülemine: 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Taaskäivita"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ära kuva uuesti"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Rakenduse teisaldamiseks\ntopeltpuudutage"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> maksimeerimine"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> taastamine"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> minimeerimine"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> sulgemine"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Tagasi"</string>
     <string name="handle_text" msgid="4419667835599523257">"Rakenduse element"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Rakenduse ikoon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Akna suuruse muutmine, vasakule"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Akna suuruse muutmine, paremale"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Akna suuruse maksimeerimine või taastamine"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Rakenduse akna suuruse maksimeerimine"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Akna suuruse taastamined"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Rakenduse akna minimeerimine"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Rakenduse akna sulgemine"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Avamisviisi vaikeseaded"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Valige, kuidas avada selle rakenduse puhul veebilinke"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Rakenduses"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index a8f9212..af175bc 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ezarri ezkerraldea % 50en"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ezarri ezkerraldea % 30en"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ezarri eskuinaldea pantaila osoan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Aldatu goiko aplikazioa behekoagatik"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Aldatu ezkerreko aplikazioa eskuinekoagatik"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ezarri goialdea pantaila osoan"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Ezarri goialdea % 70en"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ezarri goialdea % 50en"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Berrabiarazi"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ez erakutsi berriro"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Sakatu birritan\naplikazioa mugitzeko"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizatu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Leheneratu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizatu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Itxi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atzera"</string>
     <string name="handle_text" msgid="4419667835599523257">"Aplikazioaren kontrol-puntua"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Aplikazioaren ikonoa"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Aldatu leihoaren tamaina eta eraman ezkerrera"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Aldatu leihoaren tamaina eta eraman eskuinera"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizatu edo leheneratu leihoaren tamaina"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizatu aplikazioaren leihoaren tamaina"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Leheneratu leihoaren tamaina"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizatu aplikazioaren leihoa"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Itxi aplikazioaren leihoa"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Modu lehenetsian irekitzearen ezarpenak"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Aukeratu nola ireki sareko estekak aplikazio honetan"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Aplikazioan"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 59affd7..4df47c1 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"٪۵۰ چپ"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"٪۳۰ چپ"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"تمام‌صفحه راست"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"جابه‌جا کردن برنامه بالا با پایین"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"جابه‌جا کردن برنامه چپ با راست"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"تمام‌صفحه بالا"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"٪۷۰ بالا"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"٪۵۰ بالا"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"بازراه‌اندازی"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوباره نشان داده نشود"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"برای جابه‌جا کردن این برنامه\nدو تک‌ضرب بزنید"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"بزرگ کردن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"بازیابی <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"کوچک کردن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"بستن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"برگشتن"</string>
     <string name="handle_text" msgid="4419667835599523257">"دستگیره برنامه"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"نماد برنامه"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"تغییر اندازه پنجره به چپ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"تغییر اندازه پنجره به راست"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"بیشینه‌سازی یا بازیابی اندازه پنجره"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"بزرگ کردن اندازه پنجره برنامه"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"بازیابی اندازه پنجره"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"کوچک کردن پنجره برنامه"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"بستن پنجره برنامه"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"تنظیمات باز کردن به‌طور پیش‌فرض"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"انتخاب روش باز کردن پیوندهای وب مربوط به این برنامه"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"در برنامه"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index b1d8431..7da06bd 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasen 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vasen 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Oikea koko näytölle"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Vaihda ylä- ja alareunan sovellukset"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Vaihda vasen sovellus oikealla olevaan sovellukseen"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yläosa koko näytölle"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yläosa 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yläosa 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Käynnistä uudelleen"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Älä näytä uudelleen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Kaksoisnapauta, jos\nhaluat siirtää sovellusta"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Suurenna <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Palauta <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Pienennä <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Sulje <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Takaisin"</string>
     <string name="handle_text" msgid="4419667835599523257">"Sovelluksen tunnus"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Sovelluskuvake"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Muuta vasemmanpuoleisen ikkunan kokoa"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Muuta vasemmanpuoleisen ikkunan kokoa"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Suurenna ikkuna tai palauta ikkunan koko"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Suurenna sovellusikkunan koko"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Palauta ikkunan koko"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Pienennä sovellusikkuna"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Sulje sovellusikkuna"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Avaa oletusasetusten mukaan"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Valitse, miten verkkolinkit avataan tässä sovelluksessa"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Sovelluksessa"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index c58f4b0..d0fac37 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % à la gauche"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % à la gauche"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Plein écran à la droite"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Inverser l\'appli du haut avec celle du bas"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Inverser l\'appli de gauche avec celle de droite"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Plein écran dans le haut"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % dans le haut"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % dans le haut"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toucher deux fois pour\ndéplacer cette appli"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Agrandir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Réduire <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fermer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Retour"</string>
     <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icône de l\'appli"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Agrandir la taille de la fenêtre de l\'appli"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurer la taille de la fenêtre"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Réduire la fenêtre de l\'appli"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fermer la fenêtre de l\'appli"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ouvrir les paramètres par défaut"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choisissez comment ouvrir les liens Web pour cette appli"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Dans l\'appli"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index e8db4c9..91dc6de 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Écran de gauche à 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Écran de gauche à 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Écran de droite en plein écran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Inverser les applis du haut et du bas"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Inverser les applis de gauche et de droite"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Écran du haut en plein écran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Écran du haut à 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Écran du haut à 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Appuyez deux fois\npour déplacer cette appli"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Agrandir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Réduire <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fermer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Retour"</string>
     <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icône d\'application"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Agrandir la taille de la fenêtre de l\'application"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurer la taille de la fenêtre"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Réduire la fenêtre de l\'application"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fermer la fenêtre de l\'application"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ouvrir les paramètres par défaut"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choisir comment ouvrir les liens Web pour cette appli"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Dans l\'application"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index ba1c4a4..e315648 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % á esquerda"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % á esquerda"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla completa á dereita"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Cambiar a aplicación de arriba pola de abaixo"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Cambiar a aplicación da esquerda pola da dereita"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla completa arriba"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % arriba"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % arriba"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Non mostrar outra vez"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toca dúas veces para\nmover esta aplicación"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Pechar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
     <string name="handle_text" msgid="4419667835599523257">"Controlador da aplicación"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icona de aplicación"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Axustar o tamaño da ventá á esquerda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Axustar o tamaño da ventá á dereita"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamaño da ventá"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar o tamaño da ventá da aplicación"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar o tamaño da ventá"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar a ventá da aplicación"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Pechar a ventá da aplicación"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir coa configuración predeterminada"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escoller como abrir as ligazóns web para esta aplicación"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Na aplicación"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index d0be7d5..cbcb267 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बाईं स्क्रीन को 50% बनाएं"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बाईं स्क्रीन को 30% बनाएं"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"सबसे ऊपर मौजूद ऐप्लिकेशन को सबसे नीचे मौजूद ऐप्लिकेशन से बदलें"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"बाईं ओर मौजूद ऐप्लिकेशन को दाईं ओर मौजूद ऐप्लिकेशन से बदलें"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ऊपर की स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ऊपर की स्क्रीन को 70% बनाएं"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ऊपर की स्क्रीन को 50% बनाएं"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करें"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फिर से न दिखाएं"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ऐप्लिकेशन की जगह बदलने के लिए\nदो बार टैप करें"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> की विंडो को बड़ा करें"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> की विंडो को पहले जैसा करें"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> की विंडो को छोटा करें"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> को बंद करें"</string>
     <string name="back_button_text" msgid="1469718707134137085">"वापस जाएं"</string>
     <string name="handle_text" msgid="4419667835599523257">"ऐप्लिकेशन का हैंडल"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ऐप्लिकेशन आइकॉन"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विंडो का साइज़ बाईं ओर से बदलें"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विंडो का साइज़ दाईं ओर से बढ़ाएं"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ऐप्लिकेशन की विंडो का साइज़ बड़ा करें"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"विंडो का साइज़ पहले जैसा करें"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ऐप्लिकेशन की विंडो को छोटा करें"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ऐप्लिकेशन की विंडो बंद करें"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफ़ॉल्ट सेटिंग के हिसाब से खोलें"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"इस ऐप्लिकेशन के लिए वेब लिंक खोलने का तरीका चुनें"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ऐप्लिकेशन में"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index d3e7599..0eed0a4 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevi zaslon na 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Lijevi zaslon na 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desni zaslon u cijeli zaslon"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamijeni gornju aplikaciju donjom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamijeni lijevu aplikaciju desnom"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Gornji zaslon u cijeli zaslon"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gornji zaslon na 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji zaslon na 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Pokreni ponovno"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovno"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvaput dodirnite da biste\npremjestili ovu aplikaciju"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimiziraj aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Vrati aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimiziraj aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zatvori aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Natrag"</string>
     <string name="handle_text" msgid="4419667835599523257">"Pokazivač aplikacije"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promijeni veličinu prozora ulijevo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promijeni veličinu prozora udesno"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziraj ili vrati veličinu prozora"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimiziraj prozor aplikacije"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Vrati veličinu prozora"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimiziraj prozor aplikacije"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zatvori prozor aplikacije"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvori prema zadanim postavkama"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja web-veza za ovu aplikaciju"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 2f7a218..48d5afd 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Bal oldali 50%-ra"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Bal oldali 30%-ra"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Jobb oldali teljes képernyőre"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"A felső alkalmazás és az alsó alkalmazás felcserélése"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Bal és jobb alkalmazás felcserélése"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Felső teljes képernyőre"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Felső 70%-ra"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Felső 50%-ra"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Újraindítás"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne jelenjen meg többé"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Koppintson duplán\naz alkalmazás áthelyezéséhez"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> teljes méretűre állítása"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> visszaállítása"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> kis méretűre állítása"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> bezárása"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Vissza"</string>
     <string name="handle_text" msgid="4419667835599523257">"App fogópontja"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Alkalmazásikon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ablak átméretezése balra"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ablak átméretezése jobbra"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ablak teljes méretre állítása vagy visszaállítása"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Alkalmazásablak teljes méretre állítása"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Ablak méretének visszaállítása"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Alkalmazásablak kis méretre állítása"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Alkalmazás ablakának bezárása"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Alapértelmezett beállítások megnyitása"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Az app webes linkjeinek megnyitásához használt módszer"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Az alkalmazásban"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 2898dcc..bf1e8401 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ձախ էկրանը՝ 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ձախ էկրանը՝ 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Աջ էկրանը՝ լիաէկրան"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Փոխեք վերևի հավելվածը վերևից"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Փոխեք ձախ հավելվածը աջից"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Վերևի էկրանը՝ լիաէկրան"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Վերևի էկրանը՝ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Վերևի էկրանը՝ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Վերագործարկել"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Այլևս ցույց չտալ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Կրկնակի հպեք՝\nհավելվածը տեղափոխելու համար"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Ծավալել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Վերականգնել «<xliff:g id="APP_NAME">%1$s</xliff:g>» միջոցառումը"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Ծալել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Փակել՝ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Հետ"</string>
     <string name="handle_text" msgid="4419667835599523257">"Հավելվածի կեղծանուն"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Հավելվածի պատկերակ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ձգել պատուհանը դեպի ձախ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ձգել պատուհանը դեպի աջ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Առավելագույնի հասցրեք հավելվածի պատուհանի չափը"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Վերականգնել պատուհանի չափը"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Ծալել հավելվածի պատուհանը"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Փակեք հավելվածի պատուհանը"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Բացել կարգավորումներն ըստ կանխադրման"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Ընտրեք՝ ինչպես բացել այս հավելվածի վեբ հղումները"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Հավելվածում"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 617f9c9..d658f59 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kiri 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Layar penuh di kanan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Tukar aplikasi atas dengan aplikasi bawah"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Tukar aplikasi kiri dengan aplikasi kanan"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Layar penuh di atas"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Atas 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Mulai ulang"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Jangan tampilkan lagi"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ketuk dua kali untuk\nmemindahkan aplikasi ini"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimalkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Pulihkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimalkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Tutup <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Kembali"</string>
     <string name="handle_text" msgid="4419667835599523257">"Penanganan aplikasi"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikon Aplikasi"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ubah ukuran jendela ke kiri"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ubah ukuran jendela ke kanan"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimalkan atau pulihkan ukuran jendela"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimalkan ukuran jendela aplikasi"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Pulihkan ukuran jendela"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimalkan jendela aplikasi"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Tutup jendela aplikasi"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buka dengan setelan default"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pilih cara membuka link web untuk aplikasi ini"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Di aplikasi"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 797a4cc..f7b78d2 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vinstri 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vinstri 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Hægri á öllum skjánum"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Víxla efsta og neðsta forriti"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Víxla hægra og vinstra forriti"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Efri á öllum skjánum"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Efri 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Efri 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Endurræsa"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ekki sýna þetta aftur"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ýttu tvisvar til\nað færa þetta forrit"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Stækka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Endurheimta <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minnka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Loka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Til baka"</string>
     <string name="handle_text" msgid="4419667835599523257">"Handfang forrits"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Tákn forrits"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Breyta stærð glugga til vinstri"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Breyta stærð glugga til hægri"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Hámarka eða endurheimta stærð glugga"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Hámarka stærð forritsglugga"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Endurheimta gluggastærð"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Lágmarka stærð forritsglugga"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Loka forritsglugga"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Stillingar sjálfvirkrar opnunar"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Veldu hvernig veftenglar opnast í forritinu"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Í forritinu"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 2fbe1a7..369c019 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"მარცხენა ეკრანი — 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"მარცხენა ეკრანი — 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"მარჯვენა ნაწილის სრულ ეკრანზე გაშლა"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ზედა და ქვედა აპების მდებარეობის გაცვლა"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"მარცხენა და მარჯვენა აპების მდებარეობის გაცვლა"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ზედა ნაწილის სრულ ეკრანზე გაშლა"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ზედა ეკრანი — 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ზედა ეკრანი — 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"გადატვირთვა"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"აღარ გამოჩნდეს"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ამ აპის გადასატანად\nორმაგად შეეხეთ მას"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის მაქსიმალურად გაშლა"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის აღდგენა"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის ჩაკეცვა"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის დახურვა"</string>
     <string name="back_button_text" msgid="1469718707134137085">"უკან"</string>
     <string name="handle_text" msgid="4419667835599523257">"აპის იდენტიფიკატორი"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"აპის ხატულა"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ფანჯრის ზომის შეცვლა მარცხნივ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ფანჯრის ზომის შეცვლა მარჯვნივ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"აპის ფანჯრის მაქსიმალურ ზომამდე გაზრდა"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ფანჯრის ზომის აღდგენა"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"აპის ფანჯრის ზომის შემცირება"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"აპის ფანჯრის დახურვა"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"პარამეტრების ნაგულისხმევად გახსნა"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ამ აპისთვის ვებ ბმულების გახსნის წესის არჩევა"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"აპში"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index c494b16..1de32d4a 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% сол жақта"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% сол жақта"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жағын толық экранға шығару"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Жоғарыдағы қолданбаны төмендегімен орнын ауыстыру"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Сол жақтағы қолданбаны оң жақтағымен орнын ауыстыру"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Жоғарғы жағын толық экранға шығару"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% жоғарғы жақта"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% жоғарғы жақта"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Өшіріп қосу"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Қайта көрсетілмесін"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Бұл қолданбаны басқа орынға\nжылжыту үшін екі рет түртіңіз."</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын ұлғайту"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын қалпына келтіру"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын кішірейту"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын жабу"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Артқа"</string>
     <string name="handle_text" msgid="4419667835599523257">"Қолданба идентификаторы"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Қолданба белгішесі"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезе өлшемін сол жаққа өзгерту"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезе өлшемін оң жаққа өзгерту"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезе өлшемін ұлғайту не қалпына келтіру"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Қолданба терезесінің өлшемін ұлғайту"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Терезе өлшемін қалпына келтіру"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Қолданба терезесін кішірейту"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Қолданба терезесін жабу"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Әдепкісінше ашу параметрлері"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Осы қолданбадағы веб-сілтемелерді ашу жолын таңдаңыз"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Қолданбада"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 234c355..6c7faf1 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ឆ្វេង 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ឆ្វេង 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"អេក្រង់ពេញខាងស្តាំ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ប្ដូរកម្មវិធីខាងលើគេទៅខាងក្រោម"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ប្ដូរកម្មវិធីខាងឆ្វេងទៅខាងស្ដាំ"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"អេក្រង់ពេញខាងលើ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ខាងលើ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ខាងលើ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ចាប់ផ្ដើម​ឡើង​វិញ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"កុំ​បង្ហាញ​ម្ដង​ទៀត"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ចុចពីរដងដើម្បី\nផ្លាស់ទីកម្មវិធីនេះ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"ពង្រីក <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"ស្ដារ <xliff:g id="APP_NAME">%1$s</xliff:g> ឡើងវិញ"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"បង្រួម <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"បិទ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ថយក្រោយ"</string>
     <string name="handle_text" msgid="4419667835599523257">"ឈ្មោះអ្នកប្រើប្រាស់កម្មវិធី"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"រូប​កម្មវិធី"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ប្ដូរទំហំវិនដូទៅឆ្វេង"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ប្ដូរទំហំវិនដូទៅស្ដាំ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ស្ដារ ឬបង្កើនទំហំវិនដូជាអតិបរមា"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ពង្រីកទំហំវិនដូកម្មវិធី"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ស្ដារទំហំវិនដូ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"បង្រួមវិនដូកម្មវិធី"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"បិទវិនដូកម្មវិធី"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ការកំណត់បើកតាមលំនាំដើម"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ជ្រើសរើសរបៀបបើកតំណបណ្ដាញសម្រាប់កម្មវិធីនេះ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"នៅក្នុងកម្មវិធី"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 61ee3c3..6a9e07f 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% ಎಡಕ್ಕೆ"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% ಎಡಕ್ಕೆ"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ಬಲ ಫುಲ್ ಸ್ಕ್ರೀನ್"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ಮೇಲಿನ ಮತ್ತು ಕೆಳಗಿನ ಆ್ಯಪ್‌ಗಳನ್ನು ಅದಲು-ಬದಲು ಮಾಡಿ"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ಎಡ ಮತ್ತು ಬಲದ ಆ್ಯಪ್‌ಗಳನ್ನು ಅದಲು-ಬದಲು ಮಾಡಿ"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ಮೇಲಿನ ಫುಲ್ ಸ್ಕ್ರೀನ್"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% ಮೇಲಕ್ಕೆ"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% ಮೇಲಕ್ಕೆ"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ಮರುಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಸರಿಸಲು\nಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಿ"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಮಿನಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಮುಚ್ಚಿ"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ಹಿಂದಕ್ಕೆ"</string>
     <string name="handle_text" msgid="4419667835599523257">"ಆ್ಯಪ್ ಹ್ಯಾಂಡಲ್"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ಆ್ಯಪ್ ಐಕಾನ್"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ಮರುಗಾತ್ರಗೊಳಿಸಿ ವಿಂಡೋವನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ಮರುಗಾತ್ರಗೊಳಿಸಿ ವಿಂಡೋವನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ವಿಂಡೋ ಗಾತ್ರವನ್ನು ಗರಿಷ್ಠಗೊಳಿಸಿ ಅಥವಾ ಮರುಸ್ಥಾಪಿಸಿ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ಆ್ಯಪ್ ವಿಂಡೋದ ಗಾತ್ರವನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ವಿಂಡೋ ಗಾತ್ರವನ್ನು ಮರುಸ್ಥಾಪಿಸಿ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ಮಿನಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ಮುಚ್ಚಿರಿ"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ಡೀಫಾಲ್ಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಂದ ತೆರೆಯಿರಿ"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ಈ ಆ್ಯಪ್‌ಗೆ ವೆಬ್ ಲಿಂಕ್‌ಗಳನ್ನು ಹೇಗೆ ತೆರೆಯಬೇಕು ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ಆ್ಯಪ್‌ನಲ್ಲಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 2b36ba1..e94d889 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"왼쪽 화면 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"왼쪽 화면 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"오른쪽 화면 전체화면"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"상단 앱과 하단 앱 바꾸기"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"왼쪽 앱과 오른쪽 앱 바꾸기"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"위쪽 화면 전체화면"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"위쪽 화면 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"위쪽 화면 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"다시 시작"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"다시 표시 안함"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"두 번 탭하여\n이 앱 이동"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> 최대화"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> 복원"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> 최소화"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> 닫기"</string>
     <string name="back_button_text" msgid="1469718707134137085">"뒤로"</string>
     <string name="handle_text" msgid="4419667835599523257">"앱 핸들"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"앱 아이콘"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"창 크기 왼쪽으로 조절"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"창 크기 오른쪽으로 조절"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"창 최대화 또는 크기 복원"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"앱 창 크기 최대화"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"창 크기 복원"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"앱 창 최소화"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"앱 창 닫기"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"기본값으로 열기 설정"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"이 앱에서 웹 링크를 여는 방법을 선택하세요"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"앱에서"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index bb3c2fd..73e7436 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Сол жактагы экранды 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Сол жактагы экранды 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жактагы экранды толук экран режимине өткөрүү"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Өйдө жактагы колдонмону ылдый жактагы менен алмаштыруу"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Сол жактагы колдонмону оң жактагы менен алмаштыруу"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Үстүнкү экранды толук экран режимине өткөрүү"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Үстүнкү экранды 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Үстүнкү экранды 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Өчүрүп күйгүзүү"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Экинчи көрүнбөсүн"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Бул колдонмону жылдыруу үчүн\nэки жолу таптаңыз"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> чоңойтуу"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> калыбына келтирүү"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> кичирейтүү"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> жабуу"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Артка"</string>
     <string name="handle_text" msgid="4419667835599523257">"Колдонмонун маркери"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Колдонмонун сүрөтчөсү"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезенин өлчөмүн солго өзгөртүү"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезенин өлчөмүн оңго өзгөртүү"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Колдонмонун терезесинин өлчөмүн чоңойтуу"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Колдонмонун терезесинин өлчөмүн калыбына келтирүү"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Колдонмонун терезесин кичирейтүү"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Колдонмонун терезесин жабуу"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Демейки шартта ачылуучу шилтемелердин параметрлери"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Колдонмодо шилтемелер кантип ачыларын тандаңыз"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Колдонмодо"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 8850923..fd47465 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ຊ້າຍ 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ຊ້າຍ 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ເຕັມໜ້າຈໍຂວາ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ສະຫຼັບແອັບທາງເທິງກັບທາງລຸ່ມ"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ສະຫຼັບແອັບທາງຊ້າຍກັບທາງຂວາ"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ເຕັມໜ້າຈໍເທິງສຸດ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ເທິງສຸດ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ເທິງສຸດ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ຣີສະຕາດ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ແຕະສອງເທື່ອເພື່ອ\nຍ້າຍແອັບນີ້"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"ຂະຫຍາຍ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"ກູ້ຄືນ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"ຫຍໍ້ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"ປິດ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ກັບຄືນ"</string>
     <string name="handle_text" msgid="4419667835599523257">"ຊື່ຜູ້ໃຊ້ແອັບ"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ໄອຄອນແອັບ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ປັບຂະໜາດໜ້າຈໍໄປທາງຊ້າຍ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ປັບຂະໜາດໜ້າຈໍໄປທາງຂວາ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ຂະຫຍາຍຂະໜາດໜ້າຈໍແອັບໃຫ້ໃຫຍ່ສຸດ"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ກູ້ຄືນຂະໜາດໜ້າຈໍ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ຫຍໍ້ໜ້າຈໍແອັບ"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ປິດໜ້າຈໍແອັບ"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ເປີດຕາມການຕັ້ງຄ່າເລີ່ມຕົ້ນ"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ເລືອກວິທີເປີດລິ້ງເວັບສຳລັບແອັບນີ້"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ໃນແອັບ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 8ed826a..902ef04 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kairysis ekranas 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kairysis ekranas 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Dešinysis ekranas viso ekrano režimu"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Sukeisti viršutiniąją programą su apatiniąja"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Sukeisti kairiąją programą su dešiniąja"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Viršutinis ekranas viso ekrano režimu"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Viršutinis ekranas 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Viršutinis ekranas 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Paleisti iš naujo"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Daugiau neberodyti"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dukart palieskite, kad\nperkeltumėte šią programą"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Padidinti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Atkurti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Sumažinti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Uždaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atgal"</string>
     <string name="handle_text" msgid="4419667835599523257">"Programos kreipinys"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Programos piktograma"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pakeisti lango dydį kairėje"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pakeisti lango dydį dešinėje"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Padidinti arba atkurti lango dydį"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Padidinti programos lango dydį"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Atkurti lango dydį"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Sumažinti programos langą"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Uždaryti programos langą"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Atidaryti pagal numatytuosius nustatymus"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pasirinkite, kaip atidaryti šios programos žiniatinklio nuorodas"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Programoje"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 1227055..b4095df 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pa kreisi 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pa kreisi 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Labā daļa pa visu ekrānu"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Apmainīt vietām lietotni augšpusē ar lietotni apakšpusē"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Apmainīt vietām lietotni kreisajā pusē ar lietotni labajā pusē"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Augšdaļa pa visu ekrānu"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Augšdaļa 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Augšdaļa 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartēt"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Vairs nerādīt"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Veiciet dubultskārienu,\nlai pārvietotu šo lietotni"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimizēt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Atjaunot lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizēt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Aizvērt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atpakaļ"</string>
     <string name="handle_text" msgid="4419667835599523257">"Lietotnes turis"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Lietotnes ikona"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Mainīt loga lielumu uz kreiso pusi"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Mainīt loga lielumu uz labo pusi"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizēt vai atjaunot loga lielumu"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimizēt lietotnes loga lielumu"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Atjaunot loga lielumu"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizēt lietotnes logu"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Aizvērt lietotnes logu"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Atvērt pēc noklusējuma iestatījumiem"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Izvēlieties, kā atvērt šajā lietotnē norādītās saites"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Lietotnē"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index eb51374..be97489 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левиот 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левиот 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десниот на цел екран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Заменете ги местата на горната и долната апликација"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Заменете ги местата на левата и десната апликација"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горниот на цел екран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горниот 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горниот 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартирај"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не прикажувај повторно"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Допрете двапати за да ја\nпоместите апликацијава"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Максимизирај <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Врати <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Минимизирај <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Затвори <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Прекар на апликацијата"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Икона на апликацијата"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Променете ја големината на прозорецот налево"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Променете ја големината на прозорецот надесно"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Максимизирајте или вратете ја големината на прозорецот"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Максимизирај ја големината на прозорецот на апликацијата"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Врати ја големината на прозорецот"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Минимизирај го прозорецот на апликацијата"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Затвори го прозорецот на апликацијата"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Отвори според стандардните поставки"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете како да се отвораат линковите за апликацијава"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Во апликацијата"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index fca2f7c..d8efd8b 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Зүүн 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Зүүн 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Баруун талын бүтэн дэлгэц"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Дээд талын аппыг доод талынхаар солих"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Зүүн талын аппыг баруун талынхаар солих"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Дээд талын бүтэн дэлгэц"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Дээд 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Дээд 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Дахин эхлүүлэх"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Дахиж бүү харуул"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Энэ аппыг зөөхийн тулд\nхоёр товшино уу"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г томруулах"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г сэргээх"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г жижгэрүүлэх"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г хаах"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Буцах"</string>
     <string name="handle_text" msgid="4419667835599523257">"Аппын бариул"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Aппын дүрс тэмдэг"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Цонхны хэмжээг зүүн тал руу өөрчлөх"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Цонхны хэмжээг баруун тал руу өөрчлөх"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Аппын цонхны хэмжээг томруулах"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Цонхны хэмжээг сэргээх"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Аппын цонхыг жижгэрүүлэх"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Аппын цонхыг хаах"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Өгөгдмөл тохиргоогоор нээх"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Энэ аппад веб холбоосыг хэрхэн нээхийг сонгоно уу"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Аппад"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 8881187..d09a784 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"डावी 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"डावी 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"उजवी फुल स्क्रीन"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"सर्वात वरचे अ‍ॅप हे तळाशी असलेल्या अ‍ॅपने स्वॅप करा"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"डावीकडील अ‍ॅप हे उजवीकडील अ‍ॅपने स्वॅप करा"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"शीर्ष फुल स्क्रीन"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"शीर्ष 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"शीर्ष 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करा"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"पुन्हा दाखवू नका"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"हे ॲप हलवण्यासाठी\nदोनदा टॅप करा"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> मोठे करा"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> रिस्टोअर करा"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> लहान करा"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> बंद करा"</string>
     <string name="back_button_text" msgid="1469718707134137085">"मागे जा"</string>
     <string name="handle_text" msgid="4419667835599523257">"अ‍ॅपचे हँडल"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"अ‍ॅप आयकन"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"अ‍ॅप विंडोचा डावीकडे आकार बदला"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"अ‍ॅप विंडोचा उजवीकडे आकार बदला"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"अ‍ॅप विंडोचा आकार मोठा करा"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"विंडोचा आकार रिस्टोअर करा"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"अ‍ॅप विंडो लहान करा"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"अ‍ॅप विंडो बंद करा"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"बाय डीफॉल्ट सेटिंग्ज उघडा"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"या अ‍ॅपसाठीच्या वेब लिंक कशा उघडाव्यात हे निवडा"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ॲपमध्ये"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 3451701..2342564 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ဘယ်ဘက် မျက်နှာပြင် ၅၀%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ဘယ်ဘက် မျက်နှာပြင် ၃၀%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ညာဘက် မျက်နှာပြင်အပြည့်"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"အပေါ်အက်ပ်ကို အောက်သို့ ပြောင်းရန်"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ဘယ်ဘက်အက်ပ်ကို ညာဘက်သို့ ပြောင်းရန်"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"အပေါ်ဘက် မျက်နှာပြင်အပြည့်"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"အပေါ်ဘက် မျက်နှာပြင် ၇၀%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"အပေါ်ဘက် မျက်နှာပြင် ၅၀%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ပြန်စရန်"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"နောက်ထပ်မပြပါနှင့်"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ဤအက်ပ်ကို ရွှေ့ရန်\nနှစ်ချက်တို့ပါ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> ချဲ့ရန်"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ပြန်ယူရန်"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ချုံ့ရန်"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> ပိတ်ရန်"</string>
     <string name="back_button_text" msgid="1469718707134137085">"နောက်သို့"</string>
     <string name="handle_text" msgid="4419667835599523257">"အက်ပ်သုံးသူအမည်"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"အက်ပ်သင်္ကေတ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ဝင်းဒိုးကို ဘယ်ဘက်သို့ အရွယ်ပြင်ရန်"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ဝင်းဒိုးကို ညာဘက်သို့ အရွယ်ပြင်ရန်"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"အက်ပ်ဝင်းဒိုး အရွယ်အစားကို ချဲ့ရန်"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ဝင်းဒိုးအရွယ်အစား ပြန်ပြောင်းရန်"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"အက်ပ်ဝင်းဒိုးကို ချုံ့ရန်"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"အက်ပ်ဝင်းဒိုးကို ပိတ်ရန်"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"မူရင်းဆက်တင်ဖြင့် ဖွင့်ရန်"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ဤအက်ပ်အတွက် ဝဘ်လင့်ခ်များ မည်သို့ဖွင့်မည်ကို ရွေးပါ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"အက်ပ်တွင်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 3a4100c..fb61a10 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sett størrelsen på den venstre delen av skjermen til 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sett størrelsen på den venstre delen av skjermen til 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Utvid den høyre delen av skjermen til hele skjermen"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Bytt om på den øvre og nedre appen"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Bytt om på venstre og høyre app"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Utvid den øverste delen av skjermen til hele skjermen"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Sett størrelsen på den øverste delen av skjermen til 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Sett størrelsen på den øverste delen av skjermen til 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Start på nytt"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ikke vis dette igjen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dobbelttrykk for\nå flytte denne appen"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Gjenopprett <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Lukk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Tilbake"</string>
     <string name="handle_text" msgid="4419667835599523257">"Apphåndtak"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Endre størrelsen på vinduet til venstre"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Endre størrelsen på vinduet til høyre"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimer eller gjenopprett størrelsen på vinduet"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimer størrelsen på appvinduet"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Gjenopprett vindusstørrelsen"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimer appvinduet"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Lukk appvinduet"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Innstillinger for åpning som standard"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Velg hvordan nettlinker skal åpnes for denne appen"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index cc31e38..fdfa227 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बायाँ भाग ५०%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बायाँ भाग ३०%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दायाँ भाग फुल स्क्रिन"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"सिरान र पुछारको एप अदलबदल गर्नुहोस्"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"दायाँ र बायाँतिरको एप अदलबदल गर्नुहोस्"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"माथिल्लो भाग फुल स्क्रिन"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"माथिल्लो भाग ७०%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"माथिल्लो भाग ५०%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"रिस्टार्ट गर्नुहोस्"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फेरि नदेखाउनुहोस्"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"यो एप सार्न डबल\nट्याप गर्नुहोस्"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> म्याक्सिमाइज गर्नुहोस्"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> रिस्टोर गर्नुहोस्"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> मिनिमाइज गर्नुहोस्"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> बन्द गर्नुहोस्"</string>
     <string name="back_button_text" msgid="1469718707134137085">"पछाडि"</string>
     <string name="handle_text" msgid="4419667835599523257">"एपको ह्यान्डल"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"एपको आइकन"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विन्डोको आकार बदलेर बायाँतिर लैजानुहोस्"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विन्डोको आकार बदलेर दायाँतिर लैजानुहोस्"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"एपको विन्डोको आकार म्याक्सिमाइज गर्नुहोस्"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"विन्डोको आकार रिस्टोर गर्नुहोस्"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"एपको विन्डो मिनिमाइज गर्नुहोस्"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"एपको विन्डो बन्द गर्नुहोस्"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफल्ट सेटिङअनुसार खोल्नुहोस्"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"यो एपका वेब लिंकहरू खोल्ने तरिका छनौट गर्नुहोस्"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"एपमा"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 4234ddf..578877c 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Linkerscherm 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Linkerscherm 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Rechterscherm op volledig scherm"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Apps bovenaan en onderaan omwisselen"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Apps links en rechts omwisselen"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Bovenste scherm op volledig scherm"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Bovenste scherm 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bovenste scherm 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Opnieuw opstarten"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Niet opnieuw tonen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dubbeltik om\ndeze app te verplaatsen"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> maximaliseren"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> herstellen"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> minimaliseren"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> sluiten"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Terug"</string>
     <string name="handle_text" msgid="4419667835599523257">"App-handgreep"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App-icoon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Formaat van venster naar links aanpassen"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Formaat van venster naar rechts aanpassen"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Formaat van venster maximaliseren of herstellen"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Formaat van app-venster maximaliseren"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Vensterformaat herstellen"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"App-venster minimaliseren"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"App-venster sluiten"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Instellingen voor Standaard openen"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Kies hoe je weblinks voor deze app wilt openen"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In de app"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 59deb01..50861ba 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% lewej części ekranu"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% lewej części ekranu"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Prawa część ekranu na pełnym ekranie"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamień aplikację na górze z tą na dole"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamień aplikację po lewej z tą po prawej"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Górna część ekranu na pełnym ekranie"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% górnej części ekranu"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% górnej części ekranu"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Uruchom ponownie"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nie pokazuj ponownie"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Aby przenieść aplikację,\nkliknij dwukrotnie"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksymalizuj okno aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Przywróć rozmiar okna aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimalizuj okno aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zamknij <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Wstecz"</string>
     <string name="handle_text" msgid="4419667835599523257">"Uchwyt aplikacji"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacji"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Zmień rozmiar okna do lewej"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Zmień rozmiar okna do prawej"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Zmaksymalizuj lub przywróć rozmiar okna"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksymalizuj rozmiar okna aplikacji"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Przywróć rozmiar okna"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimalizuj okno aplikacji"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zamknij okno aplikacji"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ustawienia domyślnego otwierania"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Wybierz, gdzie chcesz otwierać linki z tej aplikacji"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"W aplikacji"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 593f830..a8f7403a 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Esquerda a 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Lado direito em tela cheia"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Trocar o app de cima pelo de baixo"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Trocar o app da esquerda pelo da direita"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Parte superior em tela cheia"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Parte superior a 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes para\nmover o app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fechar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Voltar"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamanho da janela"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar o tamanho da janela do app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar o tamanho da janela"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar janela do app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fechar janela do app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configurações \"Abrir por padrão\""</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para este app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"No app"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index fcf5916..04d40428 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% no ecrã esquerdo"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% no ecrã esquerdo"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ecrã direito inteiro"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Trocar app superior pela inferior"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Trocar app da esquerda pela da direita"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ecrã superior inteiro"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% no ecrã superior"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% no ecrã superior"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar de novo"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes\npara mover esta app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fechar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Anterior"</string>
     <string name="handle_text" msgid="4419667835599523257">"Indicador da app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ícone da app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar tamanho da janela"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar tamanho da janela da app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar tamanho da janela"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar janela da app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fechar janela da app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Definições de Abrir por predefinição"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para esta app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Na app"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 593f830..a8f7403a 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Esquerda a 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Lado direito em tela cheia"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Trocar o app de cima pelo de baixo"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Trocar o app da esquerda pelo da direita"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Parte superior em tela cheia"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Parte superior a 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes para\nmover o app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fechar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Voltar"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamanho da janela"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar o tamanho da janela do app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar o tamanho da janela"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar janela do app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fechar janela do app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configurações \"Abrir por padrão\""</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para este app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"No app"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 81db82a..d781d08 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Partea stângă: 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Partea stângă: 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Partea dreaptă pe ecran complet"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Schimbă aplicația de sus cu cea de jos"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Schimbă aplicația din stânga cu cea din dreapta"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Partea de sus pe ecran complet"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Partea de sus: 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Partea de sus: 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Repornește"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nu mai afișa"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Atinge de două ori\nca să muți aplicația"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizează <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restabilește <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizează <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Închide <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Înapoi"</string>
     <string name="handle_text" msgid="4419667835599523257">"Handle de aplicație"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Pictograma aplicației"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionează fereastra la stânga"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionează fereastra la dreapta"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizează sau restabilește dimensiunea ferestrei"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizează dimensiunea ferestrei aplicației"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restabilește dimensiunea ferestrei"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizează fereastra aplicației"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Închide fereastra aplicației"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Setări de deschidere în mod prestabilit"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Alege modul de deschidere a linkurilor web pentru aplicație"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"În aplicație"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index aa6f484..1837c31 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левый на 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левый на 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Правый во весь экран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Поменять местами приложения сверху и снизу"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Поменять местами приложения слева и справа"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхний во весь экран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхний на 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхний на 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перезапустить"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Больше не показывать"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Дважды нажмите, чтобы\nпереместить приложение."</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Развернуть окно приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Восстановить окно приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Свернуть окно приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Закрыть окно приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Обозначение приложения"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Значок приложения"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Растянуть окно влево"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Растянуть окно вправо"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Развернуть окно или восстановить его размер"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Развернуть окно приложения"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Восстановить размер окна"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Свернуть окно приложения"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Закрыть окно приложения"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Настройки, регулирующие, как по умолчанию открываются ссылки"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Выберите, где будут открываться ссылки из этого приложения"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"В приложении"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index efa978a..d2fc082 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"වම් 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"වම් 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"දකුණු පූර්ණ තිරය"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ඉහළ යෙදුම පහළ සමග මාරු කරන්න"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"වම් යෙදුම දකුණ සමග මාරු කරන්න"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ඉහළම පූර්ණ තිරය"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ඉහළම 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ඉහළම 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"යළි අරඹන්න"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"නැවත නොපෙන්වන්න"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"මෙම යෙදුම ගෙන යාමට\nදෙවරක් තට්ටු කරන්න"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> විහිදන්න"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ප්‍රතිසාධනය කරන්න"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> කුඩා කරන්න"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> වසන්න"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ආපසු"</string>
     <string name="handle_text" msgid="4419667835599523257">"යෙදුම් හසුරුව"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"යෙදුම් නිරූපකය"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"කවුළුව වමට ප්‍රතිප්‍රමාණ කරන්න"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"කවුළුව දකුණට ප්‍රතිප්‍රමාණ කරන්න"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"කවුළු ප්‍රමාණය උපරිම කරන්න හෝ ප්‍රතිසාධනය කරන්න"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"යෙදුම් කවුළු ප්‍රමාණය උපරිම කරන්න"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"කවුළු ප්‍රමාණය ප්‍රතිසාධනය කරන්න"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"යෙදුම් කවුළුව අවම කරන්න"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"යෙදුම් කවුළුව වසන්න"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"පෙරනිමි සැකසීම් මඟින් විවෘත කරන්න"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"මෙම යෙදුම සඳහා වෙබ් සබැඳි විවෘත කරන ආකාරය තෝරා ගන්න"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"යෙදුම තුළ"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index fac26b4..a9c81a2 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ľavá – 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ľavá – 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pravá– na celú obrazovku"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Vymeniť hornú aplikáciu za dolnú"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Vymeniť ľavú aplikáciu za pravú"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Horná – na celú obrazovku"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Horná – 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Horná – 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reštartovať"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Už nezobrazovať"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Túto aplikáciu\npresuniete dvojitým klepnutím"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximalizovať <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Obnoviť <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimalizovať <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zavrieť <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Späť"</string>
     <string name="handle_text" msgid="4419667835599523257">"Rukoväť aplikácie"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikácie"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Zmeniť veľkosť okna vľavo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Zmeniť veľkosť okna vpravo"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximalizovať alebo obnoviť veľkosť okna"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximalizovať veľkosť okna aplikácie"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Obnoviť veľkosť okna"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimalizovať okno aplikácie"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zavrieť okno aplikácie"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvárať podľa predvolených nastavení"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Vyberte, ako sa majú v tejto aplikácii otvárať webové odkazy"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikácii"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index f8dacc4..8dcca185 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Levi 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desni v celozaslonski način"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamenjava zgornje aplikacije s spodnjo"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamenjava leve aplikacije z desno"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Zgornji v celozaslonski način"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Zgornji 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Zgornji 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Znova zaženi"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikaži več"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvakrat se dotaknite\nza premik te aplikacije"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Povečanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Obnovitev aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Pomanjšava aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zapiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Nazaj"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Sprememba velikosti okna na levi"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Sprememba velikosti okna na desni"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Povečava ali obnovitev velikosti okna"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Povečanje velikosti okna aplikacije"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Obnovitev velikosti okna"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Pomanjšava okna aplikacije"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zapiranje okna aplikacije"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Nastavitve privzetega odpiranja"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Izberite način odpiranja spletnih povezav za to aplikacijo"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikaciji"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 3e88ed1..6f8bdef 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Majtas 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Majtas 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ekrani i plotë djathtas"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Ndërro aplikacionin lart me atë poshtë"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Ndërro aplikacionin majtas me atë djathtas"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ekrani i plotë lart"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Lart 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Lart 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Rinis"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Mos e shfaq përsëri"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Trokit dy herë për të\nlëvizur këtë aplikacion"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimizo \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restauro \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizo \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Mbyll \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="back_button_text" msgid="1469718707134137085">"Pas"</string>
     <string name="handle_text" msgid="4419667835599523257">"Emërtimi i aplikacionit"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona e aplikacionit"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ndrysho përmasat e dritares në të majtë"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ndrysho përmasat e dritares në të djathtë"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizo ose restauro madhësinë e dritares"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimizo madhësinë e dritares së aplikacionit"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restauro madhësinë e dritares"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizo dritaren e aplikacionit"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Mbyll dritaren e aplikacionit"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Hap sipas cilësimeve të parazgjedhura"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Zgjidh si do t\'i hapësh lidhjet e uebit për këtë aplikacion"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Në aplikacion"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 0105e15..d8893df 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vänster 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vänster 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Helskärm på höger skärm"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Byt plats på den översta och understa appen"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Byt plats på den vänstra och högra appen"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Helskärm på övre skärm"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Övre 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Övre 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Starta om"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Visa inte igen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tryck snabbt två gånger\nför att flytta denna app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Utöka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Återställ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimera <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Stäng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Tillbaka"</string>
     <string name="handle_text" msgid="4419667835599523257">"Apphandtag"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ändra storlek på fönstret åt vänster"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ändra storlek på fönstret åt höger"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximera eller återställ fönsterstorleken"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximera appfönstrets storlek"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Återställ fönsterstorlek"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimera appfönstret"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Stäng appfönstret"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Inställningar för Öppna som standard"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Välj hur webblänkar ska öppnas för den här appen"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index b4415cb..3ee43f3 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kushoto 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kushoto 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Skrini nzima ya kulia"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Badilisha nafasi ya programu ya juu na ya chini"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Badilisha nafasi ya programu ya kulia na ya kushoto"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Skrini nzima ya juu"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Juu 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Juu 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Zima kisha uwashe"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Usionyeshe tena"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Gusa mara mbili ili\nusogeze programu hii"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Panua <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Rejesha <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Punguza <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Funga <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Rudi nyuma"</string>
     <string name="handle_text" msgid="4419667835599523257">"Utambulisho wa programu"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Aikoni ya Programu"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Badilisha ukubwa wa dirisha kushoto"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Badilisha ukubwa wa dirisha kulia"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Panua au urejeshe ukubwa wa dirisha"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Panua ukubwa wa dirisha la programu"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Rejesha ukubwa wa dirisha"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Punguza dirisha la programu"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Funga dirisha la programu"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Fungua kwa mipangilio chaguomsingi"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chagua jinsi ya kufungua viungo vya wavuti vya programu hii"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Kwenye programu"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index ccc9f94..a0e7c6a 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"இடது புறம் 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"இடது புறம் 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"வலது புறம் முழுத் திரை"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"மேலுள்ள ஆப்ஸைக் கீழுள்ள ஆப்ஸ் கொண்டு மாற்றும்"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"இடதுபுற ஆப்ஸை வலதுபுற ஆப்ஸ் கொண்டு மாற்றும்"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"மேற்புறம் முழுத் திரை"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"மேலே 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"மேலே 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"மீண்டும் தொடங்கு"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"மீண்டும் காட்டாதே"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"இந்த ஆப்ஸை நகர்த்த\nஇருமுறை தட்டவும்"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸைப் பெரிதாக்கும்"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸை மீட்டெடுக்கும்"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸைச் சிறிதாக்கும்"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸை மூடும்"</string>
     <string name="back_button_text" msgid="1469718707134137085">"பின்செல்லும்"</string>
     <string name="handle_text" msgid="4419667835599523257">"ஆப்ஸ் ஹேண்டில்"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ஆப்ஸ் ஐகான்"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"சாளரத்தை இடதுபுறமாக அளவு மாற்றும்"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"சாளரத்தை வலதுபுறமாக அளவு மாற்றும்"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ஆப்ஸ் சாளரத்தின் அளவைப் பெரிதாக்கும்"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"சாளரத்தின் அளவை மீட்டெடுக்கும்"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ஆப்ஸ் சாளரத்தைச் சிறிதாக்கும்"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ஆப்ஸ் சாளரத்தை மூடும்"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"இயல்பாக அமைப்புகளைத் திறக்கும்"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"இந்த ஆப்ஸில் வலை இணைப்புகளைத் திறக்கும் வழிமுறையைத் தேர்வுசெய்யுங்கள்"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ஆப்ஸில்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 96ce40a..e093013 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ఎడమవైపు 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ఎడమవైపు 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"కుడివైపు ఫుల్-స్క్రీన్‌"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"పైన ఉన్న యాప్‌ను కింద ఉన్న యాప్‌తో మార్చండి"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ఎడమ వైపు ఉన్న యాప్‌ను కుడి వైపు ఉన్న యాప్‌తో మార్చండి"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ఎగువ ఫుల్-స్క్రీన్‌"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ఎగువ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ఎగువ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"రీస్టార్ట్ చేయండి"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"మళ్లీ చూపవద్దు"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ఈ యాప్‌ను తరలించడానికి\nడబుల్-ట్యాప్ చేయండి"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g>ను పెద్దదిగా చేయండి"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>ను రీస్టోర్ చేయండి"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g>ను చిన్నదిగా చేయండి"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g>‌ను మూసివేయండి"</string>
     <string name="back_button_text" msgid="1469718707134137085">"వెనుకకు"</string>
     <string name="handle_text" msgid="4419667835599523257">"యాప్ హ్యాండిల్"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"యాప్ చిహ్నం"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"విండో ఎడమ వైపునకు సైజ్‌ను మార్చండి"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"విండో కుడి వైపునకు సైజ్‌ను మార్చండి"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"విండో సైజ్‌ను మ్యాగ్జిమైజ్ చేయండి లేదా రీస్టోర్ చేయండి"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"యాప్ విండో సైజ్‌ను పెద్దదిగా చేయండి"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"విండో సైజ్‌ను రీస్టోర్ చేయండి"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"యాప్ విండోను చిన్నదిగా చేయండి"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"యాప్ విండోను మూసివేయండి"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ఆటోమేటిక్ సెట్టింగ్‌ల ద్వారా తెరవండి"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ఈ యాప్‌నకు సంబంధించిన వెబ్ లింక్‌లను ఎలా తెరవాలో ఎంచుకోండి"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"యాప్‌లో"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index ad38be8..f13de5b 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Gawing 50% ang nasa kaliwa"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Gawing 30% ang nasa kaliwa"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"I-full screen ang nasa kanan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Pagpalitin ang app sa itaas at ibaba"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Pagpalitin ang app sa kaliwa at kanan"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"I-full screen ang nasa itaas"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gawing 70% ang nasa itaas"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gawing 50% ang nasa itaas"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"I-restart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Huwag nang ipakita ulit"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"I-double tap para\nilipat ang app na ito"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"I-maximize ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"I-restore ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"I-minimize ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Isara ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Bumalik"</string>
     <string name="handle_text" msgid="4419667835599523257">"Handle ng app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icon ng App"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"I-resize pakaliwa ang window"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"I-resize pakanan ang window"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"I-maximize o i-restore ang laki ng window"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"I-maximize ang laki ng window ng app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"I-restore ang laki ng window"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"I-minimize ang window ng app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Isara ang window ng app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buksan sa pamamagitan ng mga default na setting"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Piliin kung paano magbukas ng web link para sa app na ito"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Sa app"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 2bc0a96..61fae05 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Solda %50"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Solda %30"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağda tam ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Üstteki uygulamayı alttaki uygulamayla değiştir"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Soldaki uygulamayı sağdakiyle değiştir"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Üstte tam ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Üstte %70"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Üstte %50"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Yeniden başlat"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Bir daha gösterme"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Bu uygulamayı taşımak için\niki kez dokunun"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını büyüt"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını geri yükle"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını küçült"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını kapat"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Geri"</string>
     <string name="handle_text" msgid="4419667835599523257">"Uygulama tanıtıcısı"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Uygulama Simgesi"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pencereyi sola yeniden boyutlandır"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pencereyi sağa yeniden boyutlandır"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Uygulama penceresini ekranı kaplayacak şekilde büyüt"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Pencere boyutunu geri yükle"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Uygulama penceresini küçült"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Uygulama penceresini kapat"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Varsayılan olarak açma ayarları"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu uygulama için web bağlantılarının nasıl açılacağını seçin"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Uygulamada"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index c1aa82e..ada82df 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ліве вікно на 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ліве вікно на 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Праве вікно на весь екран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Поміняти місцями додатки зверху й знизу"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Поміняти місцями додатки ліворуч і праворуч"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхнє вікно на весь екран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхнє вікно на 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхнє вікно на 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перезапустити"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Більше не показувати"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Двічі торкніться, щоб\nперемістити цей додаток"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Розгорнути додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Відновити додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Згорнути додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Закрити додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Дескриптор додатка"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Значок додатка"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Змінити розмір вікна ліворуч"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Змінити розмір вікна праворуч"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Розгорнути вікно або відновити його розмір"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Розгорнути вікно додатка"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Відновити розмір вікна"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Згорнути вікно додатка"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Закрити вікно додатка"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Налаштування \"Відкривати за умовчанням\""</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Виберіть, як відкривати вебпосилання в цьому додатку"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У додатку"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 1afb48d..ded104c 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"بائیں %50"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"بائیں %30"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"دائیں فل اسکرین"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"اوپری ایپ کو نیچے کے ساتھ سویپ کریں"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"بائیں ایپ کو دائیں کے ساتھ سویپ کریں"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"بالائی فل اسکرین"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"اوپر %70"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"اوپر %50"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ری اسٹارٹ کریں"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوبارہ نہ دکھائیں"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"اس ایپ کو منتقل کرنے کیلئے\nدو بار تھپتھپائیں"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> بڑا کریں"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> کو بحال کریں"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> چھوٹا کریں"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> بند کریں"</string>
     <string name="back_button_text" msgid="1469718707134137085">"پیچھے"</string>
     <string name="handle_text" msgid="4419667835599523257">"ایپ ہینڈل"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ایپ کا آئیکن"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"دائیں طرف ونڈو کا سائز تبدیل کریں"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ونڈو کا سائز بائیں طرف تبدیل کریں"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ایپ ونڈو سائز بڑا کریں"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ونڈو سائز بحال کریں"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ایپ ونڈو چھوٹا کریں"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ایپ ونڈو بند کریں"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"بطور ڈیفالٹ ترتیبات کھولیں"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اس ایپ کے لیے ویب لنکس کھولنے کا طریقہ منتخب کریں"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ایپ میں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 04fd429..8a9dad0 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Chapda 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Chapda 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"O‘ngda to‘liq ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Tepadagi ilovani pastkisi bilan almashtirish"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Chap ilovani oʻngdagisi bilan almashtirish"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Tepada to‘liq ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Tepada 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Tepada 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Qaytadan"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Boshqa chiqmasin"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Bu ilovani siljitish uchun\nikki marta bosing"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Yoyish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Tiklash: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Kichraytirish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Yopish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Orqaga"</string>
     <string name="handle_text" msgid="4419667835599523257">"Ilova identifikatori"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ilova belgisi"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Oyna oʻlchamini chapga oʻzgartirish"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Oyna oʻlchamini oʻngga oʻzgartirish"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Oyna oʻlchamini kengaytirish yoki asliga qaytarish"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Ilova oynasini kattartirish"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Oyna hajmini tiklash"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Ilova oynasini kichraytirish"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Ilova oynasini yopish"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Birlamchi sozlamalar asosida ochish"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu ilovalardagi veb havolalar qanday ochilishini tanlang"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Ilovada"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 169c2b7..d6c8bc6 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Trái 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Trái 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Toàn màn hình bên phải"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Hoán đổi ứng dụng ở trên cùng với ứng dụng ở dưới cùng"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Hoán đổi ứng dụng bên trái với ứng dụng bên phải"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Toàn màn hình phía trên"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Trên 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Trên 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Khởi động lại"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Không hiện lại"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Nhấn đúp để\ndi chuyển ứng dụng này"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Phóng to <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Khôi phục <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Thu nhỏ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Đóng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Quay lại"</string>
     <string name="handle_text" msgid="4419667835599523257">"Ô điều khiển ứng dụng"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Biểu tượng ứng dụng"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Đổi kích thước và chuyển cửa sổ sang trái"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Đổi kích thước và chuyển cửa sổ sang phải"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Phóng to hoặc khôi phục kích thước cửa sổ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Phóng to kích thước cửa sổ ứng dụng"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Khôi phục kích thước cửa sổ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Thu nhỏ cửa sổ ứng dụng"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Đóng cửa sổ ứng dụng"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Mở các chế độ cài đặt theo mặc định"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chọn cách mở đường liên kết trang web cho ứng dụng này"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Trong ứng dụng"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 942734a..1009afc 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左侧 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左侧 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右侧全屏"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"将顶部应用与底部应用互换"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"将左侧应用与右侧应用互换"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"顶部全屏"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"顶部 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"顶部 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"重启"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不再显示"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"点按两次\n即可移动此应用"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"将“<xliff:g id="APP_NAME">%1$s</xliff:g>”窗口最大化"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"恢复“<xliff:g id="APP_NAME">%1$s</xliff:g>”窗口大小"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"将“<xliff:g id="APP_NAME">%1$s</xliff:g>”窗口最小化"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"关闭“<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
     <string name="back_button_text" msgid="1469718707134137085">"返回"</string>
     <string name="handle_text" msgid="4419667835599523257">"应用手柄"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"应用图标"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"调整窗口大小并贴靠左侧"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"调整窗口大小并贴靠右侧"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"将窗口最大化或恢复大小"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"将应用窗口最大化"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"恢复窗口大小"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"将应用窗口最小化"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"关闭应用窗口"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"默认打开设置"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"选择如何打开此应用中的网页链接"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在此应用内"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index f897922..edd67c1 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左邊 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左邊 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右邊全螢幕"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"調換上下應用程式"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"調換左右應用程式"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"頂部全螢幕"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"頂部 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"頂部 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不要再顯示"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"輕按兩下\n即可移動此應用程式"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"將 <xliff:g id="APP_NAME">%1$s</xliff:g> 放到最大"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"還原 <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"將 <xliff:g id="APP_NAME">%1$s</xliff:g> 縮到最細"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"閂 <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"返去"</string>
     <string name="handle_text" msgid="4419667835599523257">"應用程式控點"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"將視窗移去左邊調整大小"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"將視窗移去右邊調整大小"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗放到最大或者還原視窗大小"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"將應用程式視窗放到最大"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"還原視窗大細"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"將應用程式視窗縮到最細"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"關閉應用程式視窗"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"採用預設設定打開"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇此應用程式開啟網絡連結的方式"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在應用程式內"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 3c6abec..32d87f3 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"以 50% 的螢幕空間顯示左側畫面"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"以 30% 的螢幕空間顯示左側畫面"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"以全螢幕顯示右側畫面"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"將頂端與底部的應用程式對調"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"將左側與右側的應用程式對調"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"以全螢幕顯示頂端畫面"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"以 70% 的螢幕空間顯示頂端畫面"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"以 50% 的螢幕空間顯示頂端畫面"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不要再顯示"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"輕觸兩下即可\n移動這個應用程式"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"最大化「<xliff:g id="APP_NAME">%1$s</xliff:g>」視窗"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"還原「<xliff:g id="APP_NAME">%1$s</xliff:g>」視窗"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"最小化「<xliff:g id="APP_NAME">%1$s</xliff:g>」視窗"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"關閉「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string>
     <string name="back_button_text" msgid="1469718707134137085">"返回"</string>
     <string name="handle_text" msgid="4419667835599523257">"應用程式控制代碼"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"調整應用程式視窗大小並向左貼齊"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"調整應用程式視窗大小並向右貼齊"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗最大化或還原大小"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"最大化應用程式視窗"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"還原視窗大小"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"最小化應用程式視窗"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"關閉應用程式視窗"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"開啟連結的預設設定"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇如何開啟這個應用程式的網頁連結"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"使用應用程式"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index b304299..94f0d34 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kwesokunxele ngo-50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kwesokunxele ngo-30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Isikrini esigcwele esingakwesokudla"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Shintshanisa i-app ephezulu ngengaphansi"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Shintshanisa i-app engakwesokunxele naleyo engakwesokudla"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Isikrini esigcwele esiphezulu"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Okuphezulu okungu-70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Okuphezulu okungu-50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Qala kabusha"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ungabonisi futhi"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Thepha kabili ukuze\nuhambise le-app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Khulisa i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Buyisela i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Nciphisa i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Vala i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Emuva"</string>
     <string name="handle_text" msgid="4419667835599523257">"Inkomba ye-App"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Isithonjana Se-app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Shintsha usayizi wewindi ngakwesokunxele"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Shintsha usayizi wewindi ngakwesokudla"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Khulisa noma buyisela usayizi wewindi"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Khulisa usayizi wewindi le-app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Buyisela usayizi wewindi"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Nciphisa iwindi le-app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Vala iwindi le-app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Vula amasethingi ngokuzenzakalela"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Khetha indlela yokuvula amalinki ewebhu ale app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Ku-app"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 32660e8..60044ad 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -619,13 +619,13 @@
     <dimen name="desktop_mode_header_app_chip_ripple_inset_vertical">4dp</dimen>
 
      <!-- The corner radius of the windowing actions pill buttons's ripple drawable -->
-     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_radius">24dp</dimen>
+     <dimen name="desktop_mode_handle_menu_icon_button_ripple_radius">24dp</dimen>
      <!-- The horizontal/vertical inset to apply to the ripple drawable effect of windowing
      actions pill central buttons -->
-     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_inset_base">2dp</dimen>
+     <dimen name="desktop_mode_handle_menu_icon_button_ripple_inset_base">2dp</dimen>
      <!-- The horizontal/vertical vertical inset to apply to the ripple drawable effect of windowing
      actions pill edge buttons -->
-     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_inset_shift">4dp</dimen>
+     <dimen name="desktop_mode_handle_menu_icon_button_ripple_inset_shift">4dp</dimen>
 
     <!-- The corner radius of the minimize button's ripple drawable -->
     <dimen name="desktop_mode_header_minimize_ripple_radius">18dp</dimen>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
index 1a80b0f..afeaf70 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
@@ -111,47 +111,28 @@
 
     /** Updates all dimensions after a configuration change. */
     fun onConfigurationUpdated() {
-        dismissDragZoneSize =
-            if (deviceConfig.isSmallTablet) {
-                context.resolveDimension(R.dimen.drag_zone_dismiss_fold)
-            } else {
-                context.resolveDimension(R.dimen.drag_zone_dismiss_tablet)
-            }
-        bubbleDragZoneTabletSize = context.resolveDimension(R.dimen.drag_zone_bubble_tablet)
-        bubbleDragZoneFoldableSize = context.resolveDimension(R.dimen.drag_zone_bubble_fold)
-        fullScreenDragZoneWidth = context.resolveDimension(R.dimen.drag_zone_full_screen_width)
-        fullScreenDragZoneHeight = context.resolveDimension(R.dimen.drag_zone_full_screen_height)
-        desktopWindowDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_desktop_window_width)
-        desktopWindowDragZoneHeight =
-            context.resolveDimension(R.dimen.drag_zone_desktop_window_height)
-        desktopWindowFromExpandedViewDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_desktop_window_expanded_view_width)
-        desktopWindowFromExpandedViewDragZoneHeight =
-            context.resolveDimension(R.dimen.drag_zone_desktop_window_expanded_view_height)
-        splitFromBubbleDragZoneHeight =
-            context.resolveDimension(R.dimen.drag_zone_split_from_bubble_height)
-        splitFromBubbleDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_split_from_bubble_width)
-        hSplitFromExpandedViewDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_h_split_from_expanded_view_width)
-        vSplitFromExpandedViewDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_width)
-        vSplitFromExpandedViewDragZoneHeightTablet =
-            context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_tablet)
-        vSplitFromExpandedViewDragZoneHeightFoldTall =
-            context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_fold_tall)
-        vSplitFromExpandedViewDragZoneHeightFoldShort =
-            context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_fold_short)
-        fullScreenDropTargetPadding =
-            context.resolveDimension(R.dimen.drop_target_full_screen_padding)
-        desktopWindowDropTargetPaddingSmall =
-            context.resolveDimension(R.dimen.drop_target_desktop_window_padding_small)
-        desktopWindowDropTargetPaddingLarge =
-            context.resolveDimension(R.dimen.drop_target_desktop_window_padding_large)
-
-        // TODO b/393172431: Use the shared xml resources once we can easily access them from
+        // TODO b/396539130: Use the shared xml resources once we can easily access them from
         //  launcher
+        dismissDragZoneSize =
+            if (deviceConfig.isSmallTablet) 140.dpToPx() else 200.dpToPx()
+        bubbleDragZoneTabletSize = 200.dpToPx()
+        bubbleDragZoneFoldableSize = 140.dpToPx()
+        fullScreenDragZoneWidth = 512.dpToPx()
+        fullScreenDragZoneHeight = 44.dpToPx()
+        desktopWindowDragZoneWidth = 880.dpToPx()
+        desktopWindowDragZoneHeight = 300.dpToPx()
+        desktopWindowFromExpandedViewDragZoneWidth = 200.dpToPx()
+        desktopWindowFromExpandedViewDragZoneHeight = 350.dpToPx()
+        splitFromBubbleDragZoneHeight = 100.dpToPx()
+        splitFromBubbleDragZoneWidth = 60.dpToPx()
+        hSplitFromExpandedViewDragZoneWidth = 60.dpToPx()
+        vSplitFromExpandedViewDragZoneWidth = 200.dpToPx()
+        vSplitFromExpandedViewDragZoneHeightTablet = 285.dpToPx()
+        vSplitFromExpandedViewDragZoneHeightFoldTall = 150.dpToPx()
+        vSplitFromExpandedViewDragZoneHeightFoldShort = 100.dpToPx()
+        fullScreenDropTargetPadding = 20.dpToPx()
+        desktopWindowDropTargetPaddingSmall = 100.dpToPx()
+        desktopWindowDropTargetPaddingLarge = 130.dpToPx()
         expandedViewDropTargetWidth = 364.dpToPx()
         expandedViewDropTargetHeight = 578.dpToPx()
         expandedViewDropTargetPaddingBottom = 108.dpToPx()
@@ -322,6 +303,7 @@
         val isVerticalSplit = deviceConfig.isSmallTablet == deviceConfig.isLandscape
         return if (isVerticalSplit) {
             when (splitScreenModeChecker.getSplitScreenMode()) {
+                SplitScreenMode.UNSUPPORTED -> emptyList()
                 SplitScreenMode.SPLIT_50_50,
                 SplitScreenMode.NONE ->
                     listOf(
@@ -379,6 +361,7 @@
             }
         } else {
             when (splitScreenModeChecker.getSplitScreenMode()) {
+                SplitScreenMode.UNSUPPORTED -> emptyList()
                 SplitScreenMode.SPLIT_50_50,
                 SplitScreenMode.NONE ->
                     listOf(
@@ -472,6 +455,7 @@
             // vertical split drag zones are aligned with the full screen drag zone width
             val splitZoneLeft = windowBounds.right / 2 - fullScreenDragZoneWidth / 2
             when (splitScreenModeChecker.getSplitScreenMode()) {
+                SplitScreenMode.UNSUPPORTED -> emptyList()
                 SplitScreenMode.SPLIT_50_50,
                 SplitScreenMode.NONE ->
                     listOf(
@@ -579,7 +563,8 @@
             NONE,
             SPLIT_50_50,
             SPLIT_10_90,
-            SPLIT_90_10
+            SPLIT_90_10,
+            UNSUPPORTED
         }
 
         fun getSplitScreenMode(): SplitScreenMode
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt
index 2bb6cf4..7327731 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt
@@ -20,6 +20,7 @@
 import android.graphics.Canvas
 import android.graphics.Paint
 import android.graphics.RectF
+import android.util.TypedValue
 import android.view.View
 import com.android.wm.shell.shared.R
 
@@ -37,14 +38,21 @@
     private val strokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
         color = context.getColor(com.android.internal.R.color.materialColorPrimaryContainer)
         style = Paint.Style.STROKE
-        strokeWidth = context.resources.getDimensionPixelSize(R.dimen.drop_target_stroke).toFloat()
+        strokeWidth = 1.dpToPx()
     }
 
-    private val cornerRadius = context.resources.getDimensionPixelSize(
-        R.dimen.drop_target_radius).toFloat()
+    private val cornerRadius = 28.dpToPx()
 
     private val rect = RectF(0f, 0f, 0f, 0f)
 
+    // TODO b/396539130: Use shared xml resources once we can access them in launcher
+    private fun Int.dpToPx() =
+        TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP,
+                this.toFloat(),
+                context.resources.displayMetrics
+            )
+
     override fun onDraw(canvas: Canvas) {
         canvas.save()
         canvas.drawRoundRect(rect, cornerRadius, cornerRadius, rectPaint)
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 2e33253..ed5e0c6 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -17,7 +17,9 @@
 package com.android.wm.shell.shared.desktopmode;
 
 import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
+import static android.window.DesktopExperienceFlags.ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE;
 
+import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper.enableBubbleToFullscreen;
 
 import android.annotation.NonNull;
@@ -224,7 +226,7 @@
     /**
      * Return {@code true} if the current device can host desktop sessions on its internal display.
      */
-    public static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
+    private static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
         return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
     }
 
@@ -269,6 +271,29 @@
     }
 
     /**
+     * Check to see if a display should have desktop mode enabled or not. Internal
+     * and external displays have separate logic.
+     */
+    public static boolean isDesktopModeSupportedOnDisplay(Context context, Display display) {
+        if (!canEnterDesktopMode(context)) {
+            return false;
+        }
+        if (display.getType() == Display.TYPE_INTERNAL) {
+            return canInternalDisplayHostDesktops(context);
+        }
+
+        // TODO (b/395014779): Change this to use WM API
+        if ((display.getType() == Display.TYPE_EXTERNAL
+                || display.getType() == Display.TYPE_OVERLAY)
+                && enableDisplayContentModeManagement()) {
+            final WindowManager wm = context.getSystemService(WindowManager.class);
+            return wm != null && wm.shouldShowSystemDecors(display.getDisplayId());
+        }
+
+        return false;
+    }
+
+    /**
      * Returns whether the multiple desktops feature is enabled for this device (both backend and
      * frontend implementations).
      */
@@ -341,8 +366,11 @@
         if (!enforceDeviceRestrictions()) {
             return true;
         }
-        final boolean desktopModeSupported = isDesktopModeSupported(context)
-                && canInternalDisplayHostDesktops(context);
+        // If projected display is enabled, #canInternalDisplayHostDesktops is no longer a
+        // requirement.
+        final boolean desktopModeSupported = ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE.isTrue()
+                ? isDesktopModeSupported(context) : (isDesktopModeSupported(context)
+                && canInternalDisplayHostDesktops(context));
         final boolean desktopModeSupportedByDevOptions =
                 Flags.enableDesktopModeThroughDevOption()
                     && isDesktopModeDevOptionSupported(context);
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/multiinstance/ManageWindowsViewContainer.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/multiinstance/ManageWindowsViewContainer.kt
index 0954b52..ac54ac7 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/multiinstance/ManageWindowsViewContainer.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/multiinstance/ManageWindowsViewContainer.kt
@@ -48,12 +48,14 @@
     lateinit var menuView: ManageWindowsView
 
     /** Creates the base menu view and fills it with icon views. */
-    fun createMenu(snapshotList: List<Pair<Int, TaskSnapshot>>,
+    fun createMenu(snapshotList: List<Pair<Int, TaskSnapshot?>>,
              onIconClickListener: ((Int) -> Unit),
              onOutsideClickListener: (() -> Unit)): ManageWindowsView {
-        val bitmapList = snapshotList.map { (index, snapshot) ->
-            index to Bitmap.wrapHardwareBuffer(snapshot.hardwareBuffer, snapshot.colorSpace)
-        }
+        val bitmapList = snapshotList
+            .filter { it.second != null }
+            .map { (index, snapshot) ->
+                index to Bitmap.wrapHardwareBuffer(snapshot!!.hardwareBuffer, snapshot.colorSpace)
+            }
         return createAndShowMenuView(
             bitmapList,
             onIconClickListener,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
index 5018fdb..8e78686 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
@@ -83,7 +83,11 @@
     private static final int ANIMATION_RESOLUTION = 1000;
 
     public SizeChangeAnimation(Rect startBounds, Rect endBounds) {
-        mAnimation = buildContainerAnimation(startBounds, endBounds);
+        this(startBounds, endBounds, 1f);
+    }
+
+    public SizeChangeAnimation(Rect startBounds, Rect endBounds, float initialScale) {
+        mAnimation = buildContainerAnimation(startBounds, endBounds, initialScale);
         mSnapshotAnim = buildSnapshotAnimation(startBounds, endBounds);
     }
 
@@ -167,7 +171,8 @@
     }
 
     /** Animation for the whole container (snapshot is inside this container). */
-    private static AnimationSet buildContainerAnimation(Rect startBounds, Rect endBounds) {
+    private static AnimationSet buildContainerAnimation(Rect startBounds, Rect endBounds,
+            float initialScale) {
         final long duration = ANIMATION_RESOLUTION;
         boolean growing = endBounds.width() - startBounds.width()
                 + endBounds.height() - startBounds.height() >= 0;
@@ -180,15 +185,27 @@
 
         final Animation scaleAnim = new ScaleAnimation(startScaleX, 1, startScaleY, 1);
         scaleAnim.setDuration(scalePeriod);
+        long scaleStartOffset = 0;
         if (!growing) {
-            scaleAnim.setStartOffset(duration - scalePeriod);
+            scaleStartOffset = duration - scalePeriod;
         }
+        scaleAnim.setStartOffset(scaleStartOffset);
         animSet.addAnimation(scaleAnim);
+
+        if (initialScale != 1f) {
+            final Animation initialScaleAnim = new ScaleAnimation(initialScale, 1f, initialScale,
+                    1f);
+            initialScaleAnim.setDuration(scalePeriod);
+            initialScaleAnim.setStartOffset(scaleStartOffset);
+            animSet.addAnimation(initialScaleAnim);
+        }
+
         final Animation translateAnim = new TranslateAnimation(startBounds.left,
                 endBounds.left, startBounds.top, endBounds.top);
         translateAnim.setDuration(duration);
         animSet.addAnimation(translateAnim);
         Rect startClip = new Rect(startBounds);
+        startClip.scale(initialScale);
         Rect endClip = new Rect(endBounds);
         startClip.offsetTo(0, 0);
         endClip.offsetTo(0, 0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index d1c7f7d..53dede6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -28,6 +28,7 @@
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_HOME;
+import static com.android.systemui.Flags.predictiveBackDelayWmTransition;
 import static com.android.window.flags.Flags.unifyBackNavigationTransition;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 
@@ -431,6 +432,11 @@
     @VisibleForTesting
     public void onThresholdCrossed() {
         mThresholdCrossed = true;
+        BackTouchTracker activeTracker = getActiveTracker();
+        if (predictiveBackDelayWmTransition() && activeTracker != null && mActiveCallback == null
+                && mBackGestureStarted) {
+            startBackNavigation(activeTracker);
+        }
         // There was no focus window when calling startBackNavigation, still pilfer pointers so
         // the next focus window won't receive motion events.
         if (mBackNavigationInfo == null && mReceivedNullNavigationInfo) {
@@ -488,9 +494,14 @@
                 if (swipeEdge == EDGE_NONE) {
                     // start animation immediately for non-gestural sources (without ACTION_MOVE
                     // events)
-                    mThresholdCrossed = true;
+                    if (!predictiveBackDelayWmTransition()) {
+                        mThresholdCrossed = true;
+                    }
                     mPointersPilfered = true;
                     onGestureStarted(touchX, touchY, swipeEdge);
+                    if (predictiveBackDelayWmTransition()) {
+                        onThresholdCrossed();
+                    }
                     mShouldStartOnNextMoveEvent = false;
                 } else {
                     mShouldStartOnNextMoveEvent = true;
@@ -544,14 +555,17 @@
             mPostCommitAnimationInProgress = false;
             mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable);
             startSystemAnimation();
-        } else if (touchTracker == mCurrentTracker) {
-            // Only start the back navigation if no other gesture is being processed. Otherwise,
-            // the back navigation will fall back to legacy back event injection.
-            startBackNavigation(mCurrentTracker);
+        } else if (!predictiveBackDelayWmTransition()) {
+            startBackNavigation(touchTracker);
         }
     }
 
     private void startBackNavigation(@NonNull BackTouchTracker touchTracker) {
+        if (touchTracker != mCurrentTracker) {
+            // Only start the back navigation if no other gesture is being processed. Otherwise,
+            // the back navigation will fall back to legacy back event injection.
+            return;
+        }
         try {
             startLatencyTracking();
             if (mBackAnimationAdapter != null
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 d948928..4f30a05 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
@@ -375,7 +375,7 @@
                 user,
                 icon,
                 BubbleType.TYPE_APP,
-                getAppBubbleKeyForApp(intent.getPackage(), user),
+                getAppBubbleKeyForApp(ComponentUtils.getPackageName(intent), user),
                 mainExecutor, bgExecutor);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
index 338ffe7..d5f2dbd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
@@ -30,6 +30,7 @@
 import android.app.ActivityManager;
 import android.app.TaskInfo;
 import android.content.Context;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.util.Slog;
@@ -155,28 +156,26 @@
      * Information about the task when it is being dragged to a bubble
      */
     public static class DragData {
-        private final Rect mBounds;
         private final WindowContainerTransaction mPendingWct;
         private final boolean mReleasedOnLeft;
+        private final float mTaskScale;
+        private final float mCornerRadius;
+        private final PointF mDragPosition;
 
         /**
-         * @param bounds bounds of the dragged task when the drag was released
-         * @param wct pending operations to be applied when finishing the drag
          * @param releasedOnLeft true if the bubble was released in the left drop target
+         * @param taskScale      the scale of the task when it was dragged to bubble
+         * @param cornerRadius   the corner radius of the task when it was dragged to bubble
+         * @param dragPosition   the position of the task when it was dragged to bubble
+         * @param wct            pending operations to be applied when finishing the drag
          */
-        public DragData(@Nullable Rect bounds, @Nullable WindowContainerTransaction wct,
-                boolean releasedOnLeft) {
-            mBounds = bounds;
+        public DragData(boolean releasedOnLeft, float taskScale, float cornerRadius,
+                @Nullable PointF dragPosition, @Nullable WindowContainerTransaction wct) {
             mPendingWct = wct;
             mReleasedOnLeft = releasedOnLeft;
-        }
-
-        /**
-         * @return bounds of the dragged task when the drag was released
-         */
-        @Nullable
-        public Rect getBounds() {
-            return mBounds;
+            mTaskScale = taskScale;
+            mCornerRadius = cornerRadius;
+            mDragPosition = dragPosition != null ? dragPosition : new PointF(0, 0);
         }
 
         /**
@@ -193,6 +192,27 @@
         public boolean isReleasedOnLeft() {
             return mReleasedOnLeft;
         }
+
+        /**
+         * @return the scale of the task when it was dragged to bubble
+         */
+        public float getTaskScale() {
+            return mTaskScale;
+        }
+
+        /**
+         * @return the corner radius of the task when it was dragged to bubble
+         */
+        public float getCornerRadius() {
+            return mCornerRadius;
+        }
+
+        /**
+         * @return position of the task when it was dragged to bubble
+         */
+        public PointF getDragPosition() {
+            return mDragPosition;
+        }
     }
 
     /**
@@ -347,29 +367,27 @@
             }
             mFinishCb = finishCallback;
 
-            if (mDragData != null && mDragData.getBounds() != null) {
-                // Override start bounds with the dragged task bounds
-                mStartBounds.set(mDragData.getBounds());
+            if (mDragData != null) {
+                mStartBounds.offsetTo((int) mDragData.getDragPosition().x,
+                        (int) mDragData.getDragPosition().y);
+                startTransaction.setScale(mSnapshot, mDragData.getTaskScale(),
+                        mDragData.getTaskScale());
+                startTransaction.setCornerRadius(mSnapshot, mDragData.getCornerRadius());
             }
 
             // Now update state (and talk to launcher) in parallel with snapshot stuff
             mBubbleData.notificationEntryUpdated(mBubble, /* suppressFlyout= */ true,
                     /* showInShade= */ false);
 
+            final int left = mStartBounds.left - info.getRoot(0).getOffset().x;
+            final int top = mStartBounds.top - info.getRoot(0).getOffset().y;
+            startTransaction.setPosition(mTaskLeash, left, top);
             startTransaction.show(mSnapshot);
             // Move snapshot to root so that it remains visible while task is moved to taskview
             startTransaction.reparent(mSnapshot, info.getRoot(0).getLeash());
-            startTransaction.setPosition(mSnapshot,
-                    mStartBounds.left - info.getRoot(0).getOffset().x,
-                    mStartBounds.top - info.getRoot(0).getOffset().y);
+            startTransaction.setPosition(mSnapshot, left, top);
             startTransaction.setLayer(mSnapshot, Integer.MAX_VALUE);
 
-            BubbleBarExpandedView bbev = mBubble.getBubbleBarExpandedView();
-            if (bbev != null) {
-                // Corners get reset during the animation. Add them back
-                startTransaction.setCornerRadius(mSnapshot, bbev.getRestingCornerRadius());
-            }
-
             startTransaction.apply();
 
             mTaskViewTransitions.onExternalDone(transition);
@@ -416,6 +434,8 @@
         private void playAnimation(boolean animate) {
             final TaskViewTaskController tv = mBubble.getTaskView().getController();
             final SurfaceControl.Transaction startT = new SurfaceControl.Transaction();
+            // Set task position to 0,0 as it will be placed inside the TaskView
+            startT.setPosition(mTaskLeash, 0, 0);
             mTaskViewTransitions.prepareOpenAnimation(tv, true /* new */, startT, mFinishT,
                     (ActivityManager.RunningTaskInfo) mTaskInfo, mTaskLeash, mFinishWct);
 
@@ -424,10 +444,12 @@
             }
 
             if (animate) {
-                mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> {
-                    mFinishCb.onTransitionFinished(mFinishWct);
-                    mFinishCb = null;
-                });
+                float startScale = mDragData != null ? mDragData.getTaskScale() : 1f;
+                mLayerView.animateConvert(startT, mStartBounds, startScale, mSnapshot, mTaskLeash,
+                        () -> {
+                            mFinishCb.onTransitionFinished(mFinishWct);
+                            mFinishCb = null;
+                        });
             } else {
                 startT.apply();
                 mFinishCb.onTransitionFinished(mFinishWct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 52f2064..fa22a39 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -580,6 +580,7 @@
     public void animateConvert(BubbleViewProvider expandedBubble,
             @NonNull SurfaceControl.Transaction startT,
             @NonNull Rect origBounds,
+            float origScale,
             @NonNull SurfaceControl snapshot,
             @NonNull SurfaceControl taskLeash,
             @Nullable Runnable afterAnimation) {
@@ -599,7 +600,7 @@
                 new SizeChangeAnimation(
                         new Rect(origBounds.left - position.x, origBounds.top - position.y,
                                 origBounds.right - position.x, origBounds.bottom - position.y),
-                        new Rect(0, 0, size.getWidth(), size.getHeight()));
+                        new Rect(0, 0, size.getWidth(), size.getHeight()), origScale);
         sca.initialize(bbev, taskLeash, snapshot, startT);
 
         Animator a = sca.buildViewAnimator(bbev, tvSf, snapshot, /* onFinish */ (va) -> {
@@ -614,6 +615,7 @@
 
         bbev.setSurfaceZOrderedOnTop(true);
         a.setDuration(EXPANDED_VIEW_ANIMATE_TO_REST_DURATION);
+        a.setInterpolator(Interpolators.EMPHASIZED);
         a.start();
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 99082f1..6c840f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -423,13 +423,13 @@
      * @param startT A transaction with first-frame work. this *will* be applied here!
      */
     public void animateConvert(@NonNull SurfaceControl.Transaction startT,
-            @NonNull Rect startBounds, @NonNull SurfaceControl snapshot, SurfaceControl taskLeash,
-            Runnable animFinish) {
+            @NonNull Rect startBounds, float startScale, @NonNull SurfaceControl snapshot,
+            SurfaceControl taskLeash, Runnable animFinish) {
         if (!mIsExpanded || mExpandedBubble == null) {
             throw new IllegalStateException("Can't animateExpand without expanded state");
         }
-        mAnimationHelper.animateConvert(mExpandedBubble, startT, startBounds, snapshot, taskLeash,
-                animFinish);
+        mAnimationHelper.animateConvert(mExpandedBubble, startT, startBounds, startScale, snapshot,
+                taskLeash, animFinish);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ComponentUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ComponentUtils.kt
index 0d0bc9b..9fefb51 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ComponentUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ComponentUtils.kt
@@ -25,7 +25,8 @@
 object ComponentUtils {
     /** Retrieves the package name from an [Intent].  */
     @JvmStatic
-    fun getPackageName(intent: Intent?): String? = intent?.component?.packageName
+    fun getPackageName(intent: Intent?): String? =
+        intent?.component?.packageName ?: intent?.`package`
 
     /** Retrieves the package name from a [PendingIntent].  */
     @JvmStatic
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HomeIntentProvider.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HomeIntentProvider.kt
new file mode 100644
index 0000000..8751b65
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HomeIntentProvider.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common
+
+import android.app.ActivityManager
+import android.app.ActivityOptions
+import android.app.PendingIntent
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.content.Context
+import android.content.Intent
+import android.os.UserHandle
+import android.view.Display.DEFAULT_DISPLAY
+import android.window.WindowContainerTransaction
+import com.android.window.flags.Flags
+
+/** Creates home intent **/
+class HomeIntentProvider(
+    private val context: Context,
+) {
+    fun addLaunchHomePendingIntent(
+        wct: WindowContainerTransaction, displayId: Int, userId: Int? = null
+    ) {
+        val userHandle =
+            if (userId != null) UserHandle.of(userId) else UserHandle.of(ActivityManager.getCurrentUser())
+
+        val launchHomeIntent = Intent(Intent.ACTION_MAIN).apply {
+            if (displayId != DEFAULT_DISPLAY) {
+                addCategory(Intent.CATEGORY_SECONDARY_HOME)
+            } else {
+                addCategory(Intent.CATEGORY_HOME)
+            }
+        }
+        val options = ActivityOptions.makeBasic().apply {
+            launchWindowingMode = WINDOWING_MODE_FULLSCREEN
+            pendingIntentBackgroundActivityStartMode =
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
+            if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
+                launchDisplayId = displayId
+            }
+        }
+        val pendingIntent = PendingIntent.getActivityAsUser(
+            context,
+            /* requestCode= */ 0,
+            launchHomeIntent,
+            PendingIntent.FLAG_IMMUTABLE,
+            /* options= */ null,
+            userHandle,
+        )
+        wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle())
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
index 214e6ad..aeef211 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
@@ -143,6 +143,9 @@
      */
     public final Rect mCachedLauncherShelfHeightKeepClearArea = new Rect();
 
+    private final List<OnPipComponentChangedListener> mOnPipComponentChangedListeners =
+            new ArrayList<>();
+
     // the size of the current bounds relative to the max size spec
     private float mBoundsScale;
 
@@ -156,9 +159,7 @@
         // Update the relative proportion of the bounds compared to max possible size. Max size
         // spec takes the aspect ratio of the bounds into account, so both width and height
         // scale by the same factor.
-        addPipExclusionBoundsChangeCallback((bounds) -> {
-            updateBoundsScale();
-        });
+        addPipExclusionBoundsChangeCallback((bounds) -> updateBoundsScale());
     }
 
     /** Reloads the resources. */
@@ -341,11 +342,14 @@
     /** Set the last {@link ComponentName} to enter PIP mode. */
     public void setLastPipComponentName(@Nullable ComponentName lastPipComponentName) {
         final boolean changed = !Objects.equals(mLastPipComponentName, lastPipComponentName);
+        if (!changed) return;
+        clearReentryState();
+        setHasUserResizedPip(false);
+        setHasUserMovedPip(false);
+        final ComponentName oldComponentName = mLastPipComponentName;
         mLastPipComponentName = lastPipComponentName;
-        if (changed) {
-            clearReentryState();
-            setHasUserResizedPip(false);
-            setHasUserMovedPip(false);
+        for (OnPipComponentChangedListener listener : mOnPipComponentChangedListeners) {
+            listener.onPipComponentChanged(oldComponentName, mLastPipComponentName);
         }
     }
 
@@ -616,6 +620,21 @@
         }
     }
 
+    /** Adds callback to listen on component change. */
+    public void addOnPipComponentChangedListener(@NonNull OnPipComponentChangedListener listener) {
+        if (!mOnPipComponentChangedListeners.contains(listener)) {
+            mOnPipComponentChangedListeners.add(listener);
+        }
+    }
+
+    /** Removes callback to listen on component change. */
+    public void removeOnPipComponentChangedListener(
+            @NonNull OnPipComponentChangedListener listener) {
+        if (mOnPipComponentChangedListeners.contains(listener)) {
+            mOnPipComponentChangedListeners.remove(listener);
+        }
+    }
+
     public LauncherState getLauncherState() {
         return mLauncherState;
     }
@@ -695,7 +714,7 @@
      * Represents the state of pip to potentially restore upon reentry.
      */
     @VisibleForTesting
-    public static final class PipReentryState {
+    static final class PipReentryState {
         private static final String TAG = PipReentryState.class.getSimpleName();
 
         private final float mSnapFraction;
@@ -722,6 +741,22 @@
         }
     }
 
+    /**
+     * Listener interface for PiP component change, i.e. the app in pip mode changes
+     * TODO: Move this out of PipBoundsState once pip1 is deprecated.
+     */
+    public interface OnPipComponentChangedListener {
+        /**
+         * Callback when the component in pip mode changes.
+         * @param oldPipComponent previous component in pip mode,
+         *                        {@code null} if this is the very first time PiP appears.
+         * @param newPipComponent new component that enters pip mode.
+         */
+        void onPipComponentChanged(
+                @Nullable ComponentName oldPipComponent,
+                @NonNull ComponentName newPipComponent);
+    }
+
     /** Dumps internal state. */
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
index 01fd344..453ca16 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
@@ -20,9 +20,10 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.window.DesktopExperienceFlags;
+import android.window.DesktopModeFlags;
 import android.window.DisplayAreaInfo;
 
-import com.android.window.flags.Flags;
+import com.android.wm.shell.Flags;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler;
@@ -48,18 +49,23 @@
 
     /**
      * Returns whether PiP in Desktop Windowing is enabled by checking the following:
-     * - Desktop Windowing in PiP flag is enabled
+     * - PiP in Desktop Windowing flag is enabled
      * - DesktopUserRepositories is injected
      * - DragToDesktopTransitionHandler is injected
      */
     public boolean isDesktopWindowingPipEnabled() {
-        return Flags.enableDesktopWindowingPip() && mDesktopUserRepositoriesOptional.isPresent()
+        return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue()
+                && mDesktopUserRepositoriesOptional.isPresent()
                 && mDragToDesktopTransitionHandlerOptional.isPresent();
     }
 
-    /** Returns whether PiP in Connected Displays is enabled by checking the flag. */
+    /**
+     * Returns whether PiP in Connected Displays is enabled by checking the following:
+     * - PiP in Connected Displays flag is enabled
+     * - PiP2 flag is enabled
+     */
     public boolean isConnectedDisplaysPipEnabled() {
-        return DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue();
+        return DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue() && Flags.enablePip2();
     }
 
     /** Returns whether the display with the PiP task is in freeform windowing mode. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index e20a3d8..fec1f56 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -1466,11 +1466,7 @@
                 // Freeze the configuration size with offset to prevent app get a configuration
                 // changed or relaunch. This is required to make sure client apps will calculate
                 // insets properly after layout shifted.
-                if (mTargetYOffset == 0) {
-                    mSplitLayoutHandler.setLayoutOffsetTarget(0, 0, SplitLayout.this);
-                } else {
-                    mSplitLayoutHandler.setLayoutOffsetTarget(0, mTargetYOffset, SplitLayout.this);
-                }
+                mSplitLayoutHandler.setLayoutOffsetTarget(0, mTargetYOffset, SplitLayout.this);
             }
 
             // Make {@link DividerView} non-interactive while IME showing in split mode. Listen to
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/OWNERS
new file mode 100644
index 0000000..007528e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-module crash handling owners
+uysalorhan@google.com
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/ShellCrashHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/ShellCrashHandler.kt
new file mode 100644
index 0000000..2e34d043
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/crashhandling/ShellCrashHandler.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.crashhandling
+
+import android.app.WindowConfiguration
+import android.content.Context
+import android.view.Display.DEFAULT_DISPLAY
+import android.window.DesktopExperienceFlags
+import android.window.WindowContainerTransaction
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.common.HomeIntentProvider
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.sysui.ShellInit
+
+/** [ShellCrashHandler] for shell to use when it's being initialized. Currently it only restores
+ *  the home task to top.
+ **/
+class ShellCrashHandler(
+    private val context: Context,
+    private val shellTaskOrganizer: ShellTaskOrganizer,
+    private val homeIntentProvider: HomeIntentProvider,
+    shellInit: ShellInit,
+) {
+    init {
+        shellInit.addInitCallback(::onInit, this)
+    }
+
+    private fun onInit() {
+        handleCrashIfNeeded()
+    }
+
+    private fun handleCrashIfNeeded() {
+        // For now only handle crashes when desktop mode is enabled on the device.
+        if (DesktopModeStatus.canEnterDesktopMode(context) &&
+            !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
+            var freeformTaskExists = false
+            // If there are running tasks at init, WMShell has crashed but WMCore is still alive.
+            for (task in shellTaskOrganizer.getRunningTasks()) {
+                if (task.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) {
+                    freeformTaskExists = true
+                }
+
+                if (freeformTaskExists) {
+                    shellTaskOrganizer.applyTransaction(
+                        addLaunchHomePendingIntent(WindowContainerTransaction(), DEFAULT_DISPLAY)
+                    )
+                    break
+                }
+            }
+        }
+    }
+
+    private fun addLaunchHomePendingIntent(
+        wct: WindowContainerTransaction, displayId: Int
+    ): WindowContainerTransaction {
+        // TODO: b/400462917 - Check that crashes are also handled correctly on HSUM devices. We
+        // might need to pass the [userId] here to launch the correct home.
+        homeIntentProvider.addLaunchHomePendingIntent(wct, displayId)
+        return wct
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 6b7f311..73be2d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -36,6 +36,7 @@
 import android.os.UserManager;
 import android.view.Choreographer;
 import android.view.IWindowManager;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.DesktopModeFlags;
 
@@ -68,6 +69,7 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.HomeIntentProvider;
 import com.android.wm.shell.common.LaunchAdjacentController;
 import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController;
 import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorSurface;
@@ -79,6 +81,7 @@
 import com.android.wm.shell.common.split.SplitState;
 import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler;
 import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver;
+import com.android.wm.shell.crashhandling.ShellCrashHandler;
 import com.android.wm.shell.dagger.back.ShellBackAnimationModule;
 import com.android.wm.shell.dagger.pip.PipModule;
 import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler;
@@ -93,6 +96,7 @@
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
 import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler;
 import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver;
+import com.android.wm.shell.desktopmode.DesktopModeMoveToDisplayTransitionHandler;
 import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger;
 import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -167,6 +171,7 @@
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer;
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper;
 import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader;
 import com.android.wm.shell.windowdecor.common.viewhost.DefaultWindowDecorViewHostSupplier;
 import com.android.wm.shell.windowdecor.common.viewhost.PooledWindowDecorViewHostSupplier;
@@ -448,7 +453,8 @@
             Optional<DesktopImmersiveController> desktopImmersiveController,
             WindowDecorViewModel windowDecorViewModel,
             Optional<TaskChangeListener> taskChangeListener,
-            FocusTransitionObserver focusTransitionObserver) {
+            FocusTransitionObserver focusTransitionObserver,
+            Optional<DesksTransitionObserver> desksTransitionObserver) {
         return new FreeformTaskTransitionObserver(
                 context,
                 shellInit,
@@ -456,7 +462,8 @@
                 desktopImmersiveController,
                 windowDecorViewModel,
                 taskChangeListener,
-                focusTransitionObserver);
+                focusTransitionObserver,
+                desksTransitionObserver);
     }
 
     @WMSingleton
@@ -722,9 +729,11 @@
     static DesksOrganizer provideDesksOrganizer(
             @NonNull ShellInit shellInit,
             @NonNull ShellCommandHandler shellCommandHandler,
-            @NonNull ShellTaskOrganizer shellTaskOrganizer
+            @NonNull ShellTaskOrganizer shellTaskOrganizer,
+            @NonNull LaunchAdjacentController launchAdjacentController
     ) {
-        return new RootTaskDesksOrganizer(shellInit, shellCommandHandler, shellTaskOrganizer);
+        return new RootTaskDesksOrganizer(shellInit, shellCommandHandler, shellTaskOrganizer,
+                launchAdjacentController);
     }
 
     @WMSingleton
@@ -769,10 +778,12 @@
             Optional<BubbleController> bubbleController,
             OverviewToDesktopTransitionObserver overviewToDesktopTransitionObserver,
             DesksOrganizer desksOrganizer,
-            DesksTransitionObserver desksTransitionObserver,
+            Optional<DesksTransitionObserver> desksTransitionObserver,
             UserProfileContexts userProfileContexts,
             DesktopModeCompatPolicy desktopModeCompatPolicy,
-            DragToDisplayTransitionHandler dragToDisplayTransitionHandler) {
+            DragToDisplayTransitionHandler dragToDisplayTransitionHandler,
+            DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler,
+            HomeIntentProvider homeIntentProvider) {
         return new DesktopTasksController(
                 context,
                 shellInit,
@@ -809,10 +820,12 @@
                 bubbleController,
                 overviewToDesktopTransitionObserver,
                 desksOrganizer,
-                desksTransitionObserver,
+                desksTransitionObserver.get(),
                 userProfileContexts,
                 desktopModeCompatPolicy,
-                dragToDisplayTransitionHandler);
+                dragToDisplayTransitionHandler,
+                moveToDisplayTransitionHandler,
+                homeIntentProvider);
     }
 
     @WMSingleton
@@ -869,12 +882,12 @@
             Transitions transitions,
             @DynamicOverride DesktopUserRepositories desktopUserRepositories,
             ShellTaskOrganizer shellTaskOrganizer,
+            DesksOrganizer desksOrganizer,
             InteractionJankMonitor interactionJankMonitor,
             @ShellMainThread Handler handler) {
         int maxTaskLimit = DesktopModeStatus.getMaxTaskLimit(context);
         if (!DesktopModeStatus.canEnterDesktopMode(context)
-                || !ENABLE_DESKTOP_WINDOWING_TASK_LIMIT.isTrue()
-                || maxTaskLimit <= 0) {
+                || !ENABLE_DESKTOP_WINDOWING_TASK_LIMIT.isTrue()) {
             return Optional.empty();
         }
         return Optional.of(
@@ -882,7 +895,8 @@
                         transitions,
                         desktopUserRepositories,
                         shellTaskOrganizer,
-                        maxTaskLimit,
+                        desksOrganizer,
+                        maxTaskLimit <= 0 ? null : maxTaskLimit,
                         interactionJankMonitor,
                         context,
                         handler));
@@ -950,6 +964,12 @@
 
     @WMSingleton
     @Provides
+    static DesktopModeMoveToDisplayTransitionHandler provideMoveToDisplayTransitionHandler() {
+        return new DesktopModeMoveToDisplayTransitionHandler(new SurfaceControl.Transaction());
+    }
+
+    @WMSingleton
+    @Provides
     static Optional<DesktopModeKeyGestureHandler> provideDesktopModeKeyGestureHandler(
             Context context,
             Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel,
@@ -1002,6 +1022,7 @@
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
             AppHandleEducationController appHandleEducationController,
             AppToWebEducationController appToWebEducationController,
+            AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             FocusTransitionObserver focusTransitionObserver,
@@ -1025,10 +1046,10 @@
                 rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser,
                 assistContentRequester, windowDecorViewHostSupplier, multiInstanceHelper,
                 desktopTasksLimiter, appHandleEducationController, appToWebEducationController,
-                windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
-                focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger,
-                taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy,
-                desktopTilingDecorViewModel,
+                appHandleAndHeaderVisibilityHelper, windowDecorCaptionHandleRepository,
+                activityOrientationChangeHandler, focusTransitionObserver, desktopModeEventLogger,
+                desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler,
+                desktopModeCompatPolicy, desktopTilingDecorViewModel,
                 multiDisplayDragMoveIndicatorController));
     }
 
@@ -1056,6 +1077,16 @@
 
     @WMSingleton
     @Provides
+    static AppHandleAndHeaderVisibilityHelper provideAppHandleAndHeaderVisibilityHelper(
+            @NonNull Context context,
+            @NonNull DisplayController displayController,
+            @NonNull DesktopModeCompatPolicy desktopModeCompatPolicy) {
+        return new AppHandleAndHeaderVisibilityHelper(context, displayController,
+                desktopModeCompatPolicy);
+    }
+
+    @WMSingleton
+    @Provides
     static WindowDecorTaskResourceLoader provideWindowDecorTaskResourceLoader(
             @NonNull Context context, @NonNull ShellInit shellInit,
             @NonNull ShellController shellController,
@@ -1194,7 +1225,6 @@
             Optional<DesktopMixedTransitionHandler> desktopMixedTransitionHandler,
             Optional<BackAnimationController> backAnimationController,
             DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider,
-            @NonNull DesksTransitionObserver desksTransitionObserver,
             ShellInit shellInit) {
         return desktopUserRepositories.flatMap(
                 repository ->
@@ -1207,17 +1237,21 @@
                                         desktopMixedTransitionHandler.get(),
                                         backAnimationController.get(),
                                         desktopWallpaperActivityTokenProvider,
-                                        desksTransitionObserver,
                                         shellInit)));
     }
 
     @WMSingleton
     @Provides
-    static DesksTransitionObserver provideDesksTransitionObserver(
-            @NonNull @DynamicOverride DesktopUserRepositories desktopUserRepositories,
+    static Optional<DesksTransitionObserver> provideDesksTransitionObserver(
+            Context context,
+            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
             @NonNull DesksOrganizer desksOrganizer
     ) {
-        return new DesksTransitionObserver(desktopUserRepositories, desksOrganizer);
+        if (DesktopModeStatus.canEnterDesktopMode(context)) {
+            return Optional.of(
+                    new DesksTransitionObserver(desktopUserRepositories, desksOrganizer));
+        }
+        return Optional.empty();
     }
 
     @WMSingleton
@@ -1526,7 +1560,8 @@
             Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional,
             Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler,
             Optional<DesktopModeKeyGestureHandler> desktopModeKeyGestureHandler,
-            Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler) {
+            Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler,
+            ShellCrashHandler shellCrashHandler) {
         return new Object();
     }
 
@@ -1546,4 +1581,20 @@
         return new UserProfileContexts(context, shellController, shellInit);
     }
 
+    @WMSingleton
+    @Provides
+    static ShellCrashHandler provideShellCrashHandler(
+            Context context,
+            ShellTaskOrganizer shellTaskOrganizer,
+            HomeIntentProvider homeIntentProvider,
+            ShellInit shellInit) {
+        return new ShellCrashHandler(context, shellTaskOrganizer, homeIntentProvider, shellInit);
+    }
+
+    @WMSingleton
+    @Provides
+    static HomeIntentProvider provideHomeIntentProvider(Context context) {
+        return new HomeIntentProvider(context);
+    }
+
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandler.kt
new file mode 100644
index 0000000..91bd3c9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandler.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.animation.Animator
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.os.IBinder
+import android.view.Choreographer
+import android.view.SurfaceControl
+import android.window.TransitionInfo
+import android.window.TransitionRequestInfo
+import android.window.WindowContainerTransaction
+import com.android.wm.shell.shared.animation.Interpolators
+import com.android.wm.shell.transition.Transitions
+import kotlin.time.Duration.Companion.milliseconds
+
+/** Transition handler for moving a window to a different display. */
+class DesktopModeMoveToDisplayTransitionHandler(
+    private val animationTransaction: SurfaceControl.Transaction
+) : Transitions.TransitionHandler {
+
+    override fun handleRequest(
+        transition: IBinder,
+        request: TransitionRequestInfo,
+    ): WindowContainerTransaction? = null
+
+    override fun startAnimation(
+        transition: IBinder,
+        info: TransitionInfo,
+        startTransaction: SurfaceControl.Transaction,
+        finishTransaction: SurfaceControl.Transaction,
+        finishCallback: Transitions.TransitionFinishCallback,
+    ): Boolean {
+        val changes = info.changes.filter { it.startDisplayId != it.endDisplayId }
+        if (changes.isEmpty()) return false
+        for (change in changes) {
+            val endBounds = change.endAbsBounds
+            // The position should be relative to the parent. For example, in ActivityEmbedding, the
+            // leash surface for the embedded Activity is parented to the container.
+            val endPosition = change.endRelOffset
+            startTransaction
+                .setPosition(change.leash, endPosition.x.toFloat(), endPosition.y.toFloat())
+                .setWindowCrop(change.leash, endBounds.width(), endBounds.height())
+        }
+        startTransaction.apply()
+
+        val animator = AnimatorSet()
+        animator.playTogether(
+            changes.map {
+                ValueAnimator.ofFloat(0f, 1f).apply {
+                    duration = ANIM_DURATION.inWholeMilliseconds
+                    interpolator = Interpolators.LINEAR
+                    addUpdateListener { animation ->
+                        animationTransaction
+                            .setAlpha(it.leash, animation.animatedValue as Float)
+                            .setFrameTimeline(Choreographer.getInstance().vsyncId)
+                            .apply()
+                    }
+                }
+            }
+        )
+        animator.addListener(
+            object : Animator.AnimatorListener {
+                override fun onAnimationStart(animation: Animator) = Unit
+
+                override fun onAnimationEnd(animation: Animator) {
+                    finishTransaction.apply()
+                    finishCallback.onTransitionFinished(null)
+                }
+
+                override fun onAnimationCancel(animation: Animator) {
+                    finishTransaction.apply()
+                    finishCallback.onTransitionFinished(null)
+                }
+
+                override fun onAnimationRepeat(animation: Animator) = Unit
+            }
+        )
+        animator.start()
+        return true
+    }
+
+    private companion object {
+        val ANIM_DURATION = 100.milliseconds
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 8c27487..f64bd75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -235,6 +235,10 @@
     /** Returns the default desk in the given display. */
     private fun getDefaultDesk(displayId: Int): Desk? = desktopData.getDefaultDesk(displayId)
 
+    /** Returns whether the given desk is active in its display. */
+    fun isDeskActive(deskId: Int): Boolean =
+        desktopData.getAllActiveDesks().any { desk -> desk.deskId == deskId }
+
     /** Sets the given desk as the active one in the given display. */
     fun setActiveDesk(displayId: Int, deskId: Int) {
         logD("setActiveDesk for displayId=%d and deskId=%d", displayId, deskId)
@@ -485,7 +489,7 @@
     fun getExpandedTasksOrdered(displayId: Int): List<Int> =
         getFreeformTasksInZOrder(displayId).filter { !isMinimizedTask(it) }
 
-    @VisibleForTesting
+    /** Returns all active non-minimized tasks for [deskId] ordered from top to bottom. */
     fun getExpandedTasksIdsInDeskOrdered(deskId: Int): List<Int> =
         getFreeformTasksIdsInDeskInZOrder(deskId).filter { !isMinimizedTask(it) }
 
@@ -733,7 +737,8 @@
         desktopData.getActiveDesk(displayId)?.topTransparentFullscreenTaskId = null
     }
 
-    private fun notifyVisibleTaskListeners(displayId: Int, visibleTasksCount: Int) {
+    @VisibleForTesting
+    public fun notifyVisibleTaskListeners(displayId: Int, visibleTasksCount: Int) {
         visibleTasksListeners.forEach { (listener, executor) ->
             executor.execute { listener.onTasksVisibilityChanged(displayId, visibleTasksCount) }
         }
@@ -915,6 +920,7 @@
         val wasActive = desktopData.getActiveDesk(desk.displayId)?.deskId == desk.deskId
         val activeTasks = ArraySet(desk.activeTasks)
         desktopData.remove(desk.deskId)
+        notifyVisibleTaskListeners(desk.displayId, getVisibleTaskCount(displayId = desk.displayId))
         deskChangeListeners.forEach { (listener, executor) ->
             executor.execute {
                 if (wasActive) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
index 70a648f..e04d14459 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
@@ -53,24 +53,12 @@
         // Case 1: When the task change is from a task in the desktop repository which is now
         // fullscreen,
         // remove the task from the desktop repository since it is no longer a freeform task.
-        if (!isFreeformTask(taskInfo)) {
-            if (desktopRepository.isActiveTask(taskInfo.taskId)) {
-                desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId)
-            }
-        } else { // Task change is a freeform task
-            if (!desktopRepository.isActiveTask(taskInfo.taskId)) {
-                // Case 2: When the task change is a freeform visible task, but the task is not
-                // yet active in the desktop repository, adds task to desktop repository.
-                desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible)
-            } else {
-                // Case 3: When the task change is a freeform task which already exists as an active
-                // task in the desktop repository, updates the task state.
-                desktopRepository.updateTask(
-                    taskInfo.displayId,
-                    taskInfo.taskId,
-                    taskInfo.isVisible,
-                )
-            }
+        if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) {
+            desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId)
+        } else if (isFreeformTask(taskInfo)) {
+            // If the task is already active in the repository, then moves task to the front,
+            // else adds the task.
+            desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible)
         }
     }
 
@@ -109,7 +97,7 @@
             desktopUserRepositories.getProfile(taskInfo.userId)
         if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
         logD("onTaskMovingToBack for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId)
-        // TODO: b/367268953 - Connect this with DesktopRepository.
+        desktopRepository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */ false)
     }
 
     override fun onTaskClosing(taskInfo: RunningTaskInfo) {
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 5d3cb86..99606d0 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
@@ -22,6 +22,7 @@
 import android.app.ActivityOptions
 import android.app.KeyguardManager
 import android.app.PendingIntent
+import android.app.TaskInfo
 import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
 import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
@@ -47,6 +48,7 @@
 import android.view.MotionEvent
 import android.view.SurfaceControl
 import android.view.SurfaceControl.Transaction
+import android.view.WindowManager
 import android.view.WindowManager.TRANSIT_CHANGE
 import android.view.WindowManager.TRANSIT_CLOSE
 import android.view.WindowManager.TRANSIT_NONE
@@ -83,6 +85,7 @@
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.common.ExternalInterfaceBinder
+import com.android.wm.shell.common.HomeIntentProvider
 import com.android.wm.shell.common.MultiInstanceHelper
 import com.android.wm.shell.common.MultiInstanceHelper.Companion.getComponent
 import com.android.wm.shell.common.RemoteCallable
@@ -208,6 +211,8 @@
     private val userProfileContexts: UserProfileContexts,
     private val desktopModeCompatPolicy: DesktopModeCompatPolicy,
     private val dragToDisplayTransitionHandler: DragToDisplayTransitionHandler,
+    private val moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler,
+    private val homeIntentProvider: HomeIntentProvider,
 ) :
     RemoteCallable<DesktopTasksController>,
     Transitions.TransitionHandler,
@@ -520,7 +525,8 @@
             return false
         }
         logV("moveBackgroundTaskToDesktop with taskId=%d", taskId)
-        val taskIdToMinimize = bringDesktopAppsToFront(task.displayId, wct, taskId)
+        val deskId = getDefaultDeskId(task.displayId)
+        val runOnTransitStart = addDeskActivationChanges(deskId, wct, task)
         val exitResult =
             desktopImmersiveController.exitImmersiveIfApplicable(
                 wct = wct,
@@ -549,9 +555,7 @@
         desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
             FREEFORM_ANIMATION_DURATION
         )
-        taskIdToMinimize?.let {
-            addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT)
-        }
+        runOnTransitStart?.invoke(transition)
         exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
         return true
     }
@@ -761,7 +765,9 @@
     fun minimizeTask(taskInfo: RunningTaskInfo, minimizeReason: MinimizeReason) {
         val wct = WindowContainerTransaction()
 
-        val isMinimizingToPip = taskInfo.pictureInPictureParams?.isAutoEnterEnabled() ?: false
+        val isMinimizingToPip =
+            DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue &&
+                (taskInfo.pictureInPictureParams?.isAutoEnterEnabled() ?: false)
         // If task is going to PiP, start a PiP transition instead of a minimize transition
         if (isMinimizingToPip) {
             val requestInfo =
@@ -960,10 +966,13 @@
                 .apply { launchWindowingMode = WINDOWING_MODE_FREEFORM }
                 .toBundle(),
         )
+        val deskId = taskRepository.getDeskIdForTask(taskId) ?: getDefaultDeskId(DEFAULT_DISPLAY)
         startLaunchTransition(
             TRANSIT_OPEN,
             wct,
             taskId,
+            deskId = deskId,
+            displayId = DEFAULT_DISPLAY,
             remoteTransition = remoteTransition,
             unminimizeReason = unminimizeReason,
         )
@@ -981,19 +990,26 @@
         remoteTransition: RemoteTransition? = null,
         unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN,
     ) {
-        logV("moveTaskToFront taskId=%s", taskInfo.taskId)
+        val deskId =
+            taskRepository.getDeskIdForTask(taskInfo.taskId) ?: getDefaultDeskId(taskInfo.displayId)
+        logV("moveTaskToFront taskId=%s deskId=%s", taskInfo.taskId, deskId)
         // If a task is tiled, another task should be brought to foreground with it so let
         // tiling controller handle the request.
         if (snapEventHandler.moveTaskToFrontIfTiled(taskInfo)) {
             return
         }
         val wct = WindowContainerTransaction()
-        wct.reorder(taskInfo.token, /* onTop= */ true, /* includingParents= */ true)
+        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
+            desksOrganizer.reorderTaskToFront(wct, deskId, taskInfo)
+        } else {
+            wct.reorder(taskInfo.token, /* onTop= */ true, /* includingParents= */ true)
+        }
         startLaunchTransition(
             transitionType = TRANSIT_TO_FRONT,
             wct = wct,
             launchingTaskId = taskInfo.taskId,
             remoteTransition = remoteTransition,
+            deskId = deskId,
             displayId = taskInfo.displayId,
             unminimizeReason = unminimizeReason,
         )
@@ -1005,14 +1021,22 @@
         wct: WindowContainerTransaction,
         launchingTaskId: Int?,
         remoteTransition: RemoteTransition? = null,
-        displayId: Int = DEFAULT_DISPLAY,
+        deskId: Int,
+        displayId: Int,
         unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN,
     ): IBinder {
+        logV(
+            "startLaunchTransition type=%s launchingTaskId=%d deskId=%d displayId=%d",
+            WindowManager.transitTypeToString(transitionType),
+            launchingTaskId,
+            deskId,
+            displayId,
+        )
         // TODO: b/397619806 - Consolidate sharable logic with [handleFreeformTaskLaunch].
         var launchTransaction = wct
         val taskIdToMinimize =
             addAndGetMinimizeChanges(
-                displayId,
+                deskId,
                 launchTransaction,
                 newTaskId = launchingTaskId,
                 launchingNewIntent = launchingTaskId == null,
@@ -1026,21 +1050,20 @@
             )
         var activationRunOnTransitStart: RunOnTransitStart? = null
         val shouldActivateDesk =
-            (DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue ||
-                DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) &&
-                !isDesktopModeShowing(displayId)
+            when {
+                DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ->
+                    !taskRepository.isDeskActive(deskId)
+                DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue -> {
+                    !isDesktopModeShowing(displayId)
+                }
+                else -> false
+            }
         if (shouldActivateDesk) {
-            val deskIdToActivate =
-                checkNotNull(
-                    launchingTaskId?.let { taskRepository.getDeskIdForTask(it) }
-                        ?: getDefaultDeskId(displayId)
-                )
             val activateDeskWct = WindowContainerTransaction()
             // TODO: b/391485148 - pass in the launching task here to apply task-limit policy,
             //  but make sure to not do it twice since it is also done at the start of this
             //  function.
-            activationRunOnTransitStart =
-                addDeskActivationChanges(deskIdToActivate, activateDeskWct)
+            activationRunOnTransitStart = addDeskActivationChanges(deskId, activateDeskWct)
             // Desk activation must be handled before app launch-related transactions.
             activateDeskWct.merge(launchTransaction, /* transfer= */ true)
             launchTransaction = activateDeskWct
@@ -1151,7 +1174,14 @@
             }
 
         wct.sendPendingIntent(pendingIntent, intent, ops.toBundle())
-        startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
+        val deskId = getDefaultDeskId(displayId)
+        startLaunchTransition(
+            TRANSIT_OPEN,
+            wct,
+            launchingTaskId = null,
+            deskId = deskId,
+            displayId = displayId,
+        )
     }
 
     /**
@@ -1168,6 +1198,11 @@
             return
         }
 
+        if (splitScreenController.isTaskInSplitScreen(task.taskId)) {
+            moveSplitPairToDisplay(task, displayId)
+            return
+        }
+
         val wct = WindowContainerTransaction()
         val displayAreaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
         if (displayAreaInfo == null) {
@@ -1175,38 +1210,6 @@
             return
         }
 
-        // check if the task is part of splitscreen
-        if (
-            Flags.enableNonDefaultDisplaySplit() &&
-                Flags.enableMoveToNextDisplayShortcut() &&
-                splitScreenController.isTaskInSplitScreen(task.taskId)
-        ) {
-            val activeDeskId = taskRepository.getActiveDeskId(displayId)
-            logV("moveToDisplay: moving split root to displayId=%d", displayId)
-            val stageCoordinatorRootTaskToken =
-                splitScreenController.multiDisplayProvider.getDisplayRootForDisplayId(
-                    DEFAULT_DISPLAY
-                )
-            wct.reparent(stageCoordinatorRootTaskToken, displayAreaInfo.token, true /* onTop */)
-            val deactivationRunnable =
-                if (activeDeskId != null) {
-                    // Split is being placed on top of an existing desk in the target display. Make
-                    // sure it is cleaned up.
-                    performDesktopExitCleanUp(
-                        wct = wct,
-                        deskId = activeDeskId,
-                        displayId = displayId,
-                        willExitDesktop = true,
-                        shouldEndUpAtHome = false,
-                    )
-                } else {
-                    null
-                }
-            val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
-            deactivationRunnable?.invoke(transition)
-            return
-        }
-
         val destinationDeskId = taskRepository.getDefaultDeskId(displayId)
         if (destinationDeskId == null) {
             logW("moveToDisplay: desk not found for display: $displayId")
@@ -1261,12 +1264,60 @@
             } else {
                 null
             }
-        val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
+        val transition =
+            transitions.startTransition(TRANSIT_CHANGE, wct, moveToDisplayTransitionHandler)
         deactivationRunnable?.invoke(transition)
         activationRunnable?.invoke(transition)
     }
 
     /**
+     * Move split pair associated with the [task] to display with [displayId].
+     *
+     * No-op if task is already on that display per [RunningTaskInfo.displayId].
+     */
+    private fun moveSplitPairToDisplay(task: RunningTaskInfo, displayId: Int) {
+        if (!splitScreenController.isTaskInSplitScreen(task.taskId)) {
+            return
+        }
+
+        if (!Flags.enableNonDefaultDisplaySplit() || !Flags.enableMoveToNextDisplayShortcut()) {
+            return
+        }
+
+        val wct = WindowContainerTransaction()
+        val displayAreaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
+        if (displayAreaInfo == null) {
+            logW("moveSplitPairToDisplay: display not found")
+            return
+        }
+
+        val activeDeskId = taskRepository.getActiveDeskId(displayId)
+        logV("moveSplitPairToDisplay: moving split root to displayId=%d", displayId)
+
+        val stageCoordinatorRootTaskToken =
+            splitScreenController.multiDisplayProvider.getDisplayRootForDisplayId(DEFAULT_DISPLAY)
+        wct.reparent(stageCoordinatorRootTaskToken, displayAreaInfo.token, true /* onTop */)
+
+        val deactivationRunnable =
+            if (activeDeskId != null) {
+                // Split is being placed on top of an existing desk in the target display. Make
+                // sure it is cleaned up.
+                performDesktopExitCleanUp(
+                    wct = wct,
+                    deskId = activeDeskId,
+                    displayId = displayId,
+                    willExitDesktop = true,
+                    shouldEndUpAtHome = false,
+                )
+            } else {
+                null
+            }
+        val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
+        deactivationRunnable?.invoke(transition)
+        return
+    }
+
+    /**
      * Quick-resizes a desktop task, toggling between a fullscreen state (represented by the stable
      * bounds) and a free floating state (either the last saved bounds if available or the default
      * bounds otherwise).
@@ -1626,7 +1677,10 @@
         }
     }
 
-    @Deprecated("Use activeDesk() instead.", ReplaceWith("activateDesk()"))
+    @Deprecated(
+        "Use addDeskActivationChanges() instead.",
+        ReplaceWith("addDeskActivationChanges()"),
+    )
     private fun bringDesktopAppsToFront(
         displayId: Int,
         wct: WindowContainerTransaction,
@@ -1685,34 +1739,7 @@
     }
 
     private fun addLaunchHomePendingIntent(wct: WindowContainerTransaction, displayId: Int) {
-        val userHandle = UserHandle.of(userId)
-        val launchHomeIntent =
-            Intent(Intent.ACTION_MAIN).apply {
-                if (displayId != DEFAULT_DISPLAY) {
-                    addCategory(Intent.CATEGORY_SECONDARY_HOME)
-                } else {
-                    addCategory(Intent.CATEGORY_HOME)
-                }
-            }
-        val options =
-            ActivityOptions.makeBasic().apply {
-                launchWindowingMode = WINDOWING_MODE_FULLSCREEN
-                pendingIntentBackgroundActivityStartMode =
-                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
-                if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
-                    launchDisplayId = displayId
-                }
-            }
-        val pendingIntent =
-            PendingIntent.getActivityAsUser(
-                context,
-                /* requestCode= */ 0,
-                launchHomeIntent,
-                PendingIntent.FLAG_IMMUTABLE,
-                /* options= */ null,
-                userHandle,
-            )
-        wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle())
+        homeIntentProvider.addLaunchHomePendingIntent(wct, displayId, userId)
     }
 
     private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) {
@@ -2097,6 +2124,7 @@
         // TODO(b/337915660): Add a transition handler for these; animations
         //  need updates in some cases.
         val baseActivity = callingTaskInfo.baseActivity ?: return
+        val userHandle = UserHandle.of(callingTaskInfo.userId)
         val fillIn: Intent =
             userProfileContexts
                 .getOrCreate(callingTaskInfo.userId)
@@ -2104,11 +2132,13 @@
                 .getLaunchIntentForPackage(baseActivity.packageName) ?: return
         fillIn.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
         val launchIntent =
-            PendingIntent.getActivity(
+            PendingIntent.getActivityAsUser(
                 context,
                 /* requestCode= */ 0,
                 fillIn,
                 PendingIntent.FLAG_IMMUTABLE,
+                /* options= */ null,
+                userHandle,
             )
         val options = createNewWindowOptions(callingTaskInfo)
         when (options.launchWindowingMode) {
@@ -2135,10 +2165,14 @@
             WINDOWING_MODE_FREEFORM -> {
                 val wct = WindowContainerTransaction()
                 wct.sendPendingIntent(launchIntent, fillIn, options.toBundle())
+                val deskId =
+                    taskRepository.getDeskIdForTask(callingTaskInfo.taskId)
+                        ?: getDefaultDeskId(callingTaskInfo.displayId)
                 startLaunchTransition(
                     transitionType = TRANSIT_OPEN,
                     wct = wct,
                     launchingTaskId = null,
+                    deskId = deskId,
                     displayId = callingTaskInfo.displayId,
                 )
             }
@@ -2218,6 +2252,7 @@
             logV("skip keyguard is locked")
             return null
         }
+        val deskId = getDefaultDeskId(task.displayId)
         val wct = WindowContainerTransaction()
         if (shouldFreeformTaskLaunchSwitchToFullscreen(task)) {
             logD("Bring desktop tasks to front on transition=taskId=%d", task.taskId)
@@ -2240,7 +2275,8 @@
                 runOnTransitStart?.invoke(transition)
                 return wct
             }
-            bringDesktopAppsToFront(task.displayId, wct, task.taskId)
+            val runOnTransitStart = addDeskActivationChanges(deskId, wct, task)
+            runOnTransitStart?.invoke(transition)
             wct.reorder(task.token, true)
             return wct
         }
@@ -2280,7 +2316,7 @@
             reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
         )
         // 2) minimize a Task if needed.
-        val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
+        val taskIdToMinimize = addAndGetMinimizeChanges(deskId, wct, task.taskId)
         addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
         if (taskIdToMinimize != null) {
             addPendingMinimizeTransition(transition, taskIdToMinimize, MinimizeReason.TASK_LIMIT)
@@ -2303,25 +2339,42 @@
             return WindowContainerTransaction().also { wct ->
                 val deskId = getDefaultDeskId(task.displayId)
                 addMoveToDeskTaskChanges(wct = wct, task = task, deskId = deskId)
-                // In some launches home task is moved behind new task being launched. Make sure
-                // that's not the case for launches in desktop. Also, if this launch is the first
-                // one to trigger the desktop mode (e.g., when [forceEnterDesktop()]), activate the
-                // desktop mode here.
-                if (
-                    task.baseIntent.flags.and(Intent.FLAG_ACTIVITY_TASK_ON_HOME) != 0 ||
-                        !isDesktopModeShowing(task.displayId)
-                ) {
-                    bringDesktopAppsToFront(task.displayId, wct, task.taskId)
-                    wct.reorder(task.token, true)
-                }
-
-                // Desktop Mode is already showing and we're launching a new Task - we might need to
-                // minimize another Task.
-                val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
-                taskIdToMinimize?.let {
-                    addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT)
-                }
-                addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
+                val runOnTransitStart: RunOnTransitStart? =
+                    if (
+                        task.baseIntent.flags.and(Intent.FLAG_ACTIVITY_TASK_ON_HOME) != 0 ||
+                            !isDesktopModeShowing(task.displayId)
+                    ) {
+                        // In some launches home task is moved behind new task being launched. Make
+                        // sure that's not the case for launches in desktop. Also, if this launch is
+                        // the first one to trigger the desktop mode (e.g., when
+                        // [forceEnterDesktop()]), activate the desk here.
+                        val activationRunnable =
+                            addDeskActivationChanges(
+                                deskId = deskId,
+                                wct = wct,
+                                newTask = task,
+                                addPendingLaunchTransition = true,
+                            )
+                        wct.reorder(task.token, true)
+                        activationRunnable
+                    } else {
+                        { transition: IBinder ->
+                            // The desk was already showing and we're launching a new Task - we
+                            // might need to minimize another Task.
+                            val taskIdToMinimize =
+                                addAndGetMinimizeChanges(deskId, wct, task.taskId)
+                            taskIdToMinimize?.let { minimizingTaskId ->
+                                addPendingMinimizeTransition(
+                                    transition,
+                                    minimizingTaskId,
+                                    MinimizeReason.TASK_LIMIT,
+                                )
+                            }
+                            // Also track the pending launching task.
+                            addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
+                        }
+                    }
+                runOnTransitStart?.invoke(transition)
                 desktopImmersiveController.exitImmersiveIfApplicable(
                     transition,
                     wct,
@@ -2645,7 +2698,7 @@
 
     /** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */
     private fun addAndGetMinimizeChanges(
-        displayId: Int,
+        deskId: Int,
         wct: WindowContainerTransaction,
         newTaskId: Int?,
         launchingNewIntent: Boolean = false,
@@ -2654,7 +2707,7 @@
         require(newTaskId == null || !launchingNewIntent)
         return desktopTasksLimiter
             .get()
-            .addAndGetMinimizeTaskChanges(displayId, wct, newTaskId, launchingNewIntent)
+            .addAndGetMinimizeTaskChanges(deskId, wct, newTaskId, launchingNewIntent)
     }
 
     private fun addPendingMinimizeTransition(
@@ -2716,11 +2769,20 @@
         activateDesk(deskId, remoteTransition)
     }
 
-    /** Activates the given desk but without starting a transition. */
+    /**
+     * Applies the necessary [wct] changes to activate the given desk.
+     *
+     * When a task is being brought into a desk together with the activation, then [newTask] is not
+     * null and may be used to run other desktop policies, such as minimizing another task if the
+     * task limit has been exceeded.
+     */
     fun addDeskActivationChanges(
         deskId: Int,
         wct: WindowContainerTransaction,
-        newTask: RunningTaskInfo? = null,
+        newTask: TaskInfo? = null,
+        // TODO: b/362720497 - should this be true in other places? Can it be calculated locally
+        //  without having to specify the value?
+        addPendingLaunchTransition: Boolean = false,
     ): RunOnTransitStart? {
         logV("addDeskActivationChanges newTaskId=%d deskId=%d", newTask?.taskId, deskId)
         val newTaskIdInFront = newTask?.taskId
@@ -2735,6 +2797,9 @@
                         minimizeReason = MinimizeReason.TASK_LIMIT,
                     )
                 }
+                if (newTask != null && addPendingLaunchTransition) {
+                    addPendingAppLaunchTransition(transition, newTask.taskId, taskIdToMinimize)
+                }
             }
         }
         prepareForDeskActivation(displayId, wct)
@@ -2745,9 +2810,20 @@
         taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
             doesAnyTaskRequireTaskbarRounding(displayId)
         )
-        // TODO: b/362720497 - activating a desk with the intention to move a new task to
-        //  it means we may need to minimize something in the activating desk. Do so here
-        //  similar to how it's done in #bringDesktopAppsToFront.
+        val expandedTasksOrderedFrontToBack =
+            taskRepository.getExpandedTasksIdsInDeskOrdered(deskId = deskId)
+        // If we're adding a new Task we might need to minimize an old one
+        val taskIdToMinimize =
+            desktopTasksLimiter
+                .getOrNull()
+                ?.getTaskIdToMinimize(expandedTasksOrderedFrontToBack, newTaskIdInFront)
+        if (taskIdToMinimize != null) {
+            val taskToMinimize = shellTaskOrganizer.getRunningTaskInfo(taskIdToMinimize)
+            // TODO(b/365725441): Handle non running task minimization
+            if (taskToMinimize != null) {
+                desksOrganizer.minimizeTask(wct, deskId, taskToMinimize)
+            }
+        }
         return { transition ->
             val activateDeskTransition =
                 if (newTaskIdInFront != null) {
@@ -2765,6 +2841,9 @@
                     )
                 }
             desksTransitionObserver.addPendingTransition(activateDeskTransition)
+            taskIdToMinimize?.let { minimizingTask ->
+                addPendingMinimizeTransition(transition, minimizingTask, MinimizeReason.TASK_LIMIT)
+            }
         }
     }
 
@@ -3344,7 +3423,14 @@
         if (windowingMode == WINDOWING_MODE_FREEFORM) {
             if (DesktopModeFlags.ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX.isTrue()) {
                 // TODO b/376389593: Use a custom tab tearing transition/animation
-                startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
+                val deskId = getDefaultDeskId(DEFAULT_DISPLAY)
+                startLaunchTransition(
+                    TRANSIT_OPEN,
+                    wct,
+                    launchingTaskId = null,
+                    deskId = deskId,
+                    displayId = DEFAULT_DISPLAY,
+                )
             } else {
                 desktopModeDragAndDropTransitionHandler.handleDropEvent(wct)
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
index b9b4d9e..4ca5882 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
@@ -22,6 +22,7 @@
 import android.os.IBinder
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_TO_BACK
+import android.window.DesktopExperienceFlags
 import android.window.DesktopModeFlags
 import android.window.TransitionInfo
 import android.window.WindowContainerTransaction
@@ -31,6 +32,7 @@
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
+import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.shared.annotations.ShellMainThread
 import com.android.wm.shell.sysui.UserChangeListener
@@ -38,17 +40,18 @@
 import com.android.wm.shell.transition.Transitions.TransitionObserver
 
 /**
- * Limits the number of tasks shown in Desktop Mode.
+ * Keeps track of minimized tasks and limits the number of tasks shown in Desktop Mode.
  *
- * This class should only be used if
- * [android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT] is enabled and
- * [maxTasksLimit] is strictly greater than 0.
+ * [maxTasksLimit] must be strictly greater than 0 if it's given.
+ *
+ * TODO(b/400634379): Separate two responsibilities of this class into two classes.
  */
 class DesktopTasksLimiter(
     transitions: Transitions,
     private val desktopUserRepositories: DesktopUserRepositories,
     private val shellTaskOrganizer: ShellTaskOrganizer,
-    private val maxTasksLimit: Int,
+    private val desksOrganizer: DesksOrganizer,
+    private val maxTasksLimit: Int?,
     private val interactionJankMonitor: InteractionJankMonitor,
     private val context: Context,
     @ShellMainThread private val handler: Handler,
@@ -59,13 +62,19 @@
     private var userId: Int
 
     init {
-        require(maxTasksLimit > 0) {
-            "DesktopTasksLimiter: maxTasksLimit should be greater than 0. Current value: $maxTasksLimit."
+        maxTasksLimit?.let {
+            require(it > 0) {
+                "DesktopTasksLimiter: maxTasksLimit should be greater than 0. Current value: $it."
+            }
         }
         transitions.registerObserver(minimizeTransitionObserver)
         userId = ActivityManager.getCurrentUser()
         desktopUserRepositories.current.addActiveTaskListener(leftoverMinimizedTasksRemover)
-        logV("Starting limiter with a maximum of %d tasks", maxTasksLimit)
+        if (maxTasksLimit != null) {
+            logV("Starting limiter with a maximum of %d tasks", maxTasksLimit)
+        } else {
+            logV("Starting limiter without the task limit")
+        }
     }
 
     data class TaskDetails(
@@ -252,7 +261,7 @@
      * returning the task to minimize.
      */
     fun addAndGetMinimizeTaskChanges(
-        displayId: Int,
+        deskId: Int,
         wct: WindowContainerTransaction,
         newFrontTaskId: Int?,
         launchingNewIntent: Boolean = false,
@@ -261,15 +270,19 @@
         val taskRepository = desktopUserRepositories.current
         val taskIdToMinimize =
             getTaskIdToMinimize(
-                taskRepository.getExpandedTasksOrdered(displayId),
+                taskRepository.getExpandedTasksIdsInDeskOrdered(deskId),
                 newFrontTaskId,
                 launchingNewIntent,
             )
-        // If it's a running task, reorder it to back.
         taskIdToMinimize
             ?.let { shellTaskOrganizer.getRunningTaskInfo(it) }
-            // TODO: b/391485148 - this won't really work with multi-desks enabled.
-            ?.let { wct.reorder(it.token, /* onTop= */ false) }
+            ?.let { task ->
+                if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
+                    wct.reorder(task.token, /* onTop= */ false)
+                } else {
+                    desksOrganizer.minimizeTask(wct, deskId, task)
+                }
+            }
         return taskIdToMinimize
     }
 
@@ -325,7 +338,7 @@
         launchingNewIntent: Boolean,
     ): Int? {
         val newTasksOpening = if (launchingNewIntent) 1 else 0
-        if (visibleOrderedTasks.size + newTasksOpening <= maxTasksLimit) {
+        if (visibleOrderedTasks.size + newTasksOpening <= (maxTasksLimit ?: Int.MAX_VALUE)) {
             logV("No need to minimize; tasks below limit")
             // No need to minimize anything
             return null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index 26a5d5b..7dabeb7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -32,12 +32,10 @@
 import android.window.TransitionInfo
 import android.window.WindowContainerTransaction
 import com.android.internal.protolog.ProtoLog
-import com.android.window.flags.Flags
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.back.BackAnimationController
 import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.isExitDesktopModeTransition
 import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider
-import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.shared.TransitionUtil
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
@@ -59,7 +57,6 @@
     private val desktopMixedTransitionHandler: DesktopMixedTransitionHandler,
     private val backAnimationController: BackAnimationController,
     private val desktopWallpaperActivityTokenProvider: DesktopWallpaperActivityTokenProvider,
-    private val desksTransitionObserver: DesksTransitionObserver,
     shellInit: ShellInit,
 ) : Transitions.TransitionObserver {
 
@@ -89,7 +86,6 @@
         finishTransaction: SurfaceControl.Transaction,
     ) {
         // TODO: b/332682201 Update repository state
-        desksTransitionObserver.onTransitionReady(transition, info)
         if (
             DesktopModeFlags.INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC
                 .isTrue() && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue()
@@ -107,7 +103,7 @@
         info.changes.forEach { change ->
             change.taskInfo?.let { taskInfo ->
                 if (
-                    Flags.enableDesktopWindowingPip() &&
+                    DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue &&
                         desktopRepository.isTaskMinimizedPipInDisplay(
                             taskInfo.displayId,
                             taskInfo.taskId,
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 c8f7ea9..4f511a9 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
@@ -281,6 +281,7 @@
         val state = requireTransitionState()
         val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
         val animatedTaskBounds = getAnimatedTaskBounds()
+        state.dragAnimator.cancelAnimator()
         requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds)
     }
 
@@ -292,7 +293,6 @@
         val scaledWidth = taskBounds.width() * taskScale
         val scaledHeight = taskBounds.height() * taskScale
         val dragPosition = PointF(state.dragAnimator.position)
-        state.dragAnimator.cancelAnimator()
         return Rect(
             dragPosition.x.toInt(),
             dragPosition.y.toInt(),
@@ -325,22 +325,26 @@
         // TODO(b/391928049): update density once we can drag from desktop to bubble
         val state = requireTransitionState()
         val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
-        val taskBounds = getAnimatedTaskBounds()
+        val dragPosition = PointF(state.dragAnimator.position)
+        val scale = state.dragAnimator.scale
+        val cornerRadius = state.dragAnimator.cornerRadius
         state.dragAnimator.cancelAnimator()
-        requestBubble(wct, taskInfo, onLeft, taskBounds)
+        requestBubble(wct, taskInfo, onLeft, scale, cornerRadius, dragPosition)
     }
 
     private fun requestBubble(
         wct: WindowContainerTransaction,
         taskInfo: RunningTaskInfo,
         onLeft: Boolean,
-        taskBounds: Rect = Rect(taskInfo.configuration.windowConfiguration.bounds),
+        taskScale: Float = 1f,
+        cornerRadius: Float = 0f,
+        dragPosition: PointF = PointF(0f, 0f),
     ) {
         val controller =
             bubbleController.orElseThrow { IllegalStateException("BubbleController not set") }
         controller.expandStackAndSelectBubble(
             taskInfo,
-            BubbleTransitions.DragData(taskBounds, wct, onLeft),
+            BubbleTransitions.DragData(onLeft, taskScale, cornerRadius, dragPosition, wct),
         )
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
index fc359d7..8c4bc25 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
@@ -40,6 +40,13 @@
         task: ActivityManager.RunningTaskInfo,
     )
 
+    /** Reorders a desk's task to the front. */
+    fun reorderTaskToFront(
+        wct: WindowContainerTransaction,
+        deskId: Int,
+        task: ActivityManager.RunningTaskInfo,
+    )
+
     /** Minimizes the given task of the given deskId. */
     fun minimizeTask(
         wct: WindowContainerTransaction,
@@ -47,6 +54,13 @@
         task: ActivityManager.RunningTaskInfo,
     )
 
+    /** Unminimize the given task of the given desk. */
+    fun unminimizeTask(
+        wct: WindowContainerTransaction,
+        deskId: Int,
+        task: ActivityManager.RunningTaskInfo,
+    )
+
     /** Whether the change is for the given desk id. */
     fun isDeskChange(change: TransitionInfo.Change, deskId: Int): Boolean
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
index f576258..49ca58e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
@@ -33,6 +33,7 @@
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.protolog.ProtoLog
 import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.common.LaunchAdjacentController
 import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer.OnCreateCallback
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.sysui.ShellCommandHandler
@@ -44,6 +45,7 @@
     shellInit: ShellInit,
     shellCommandHandler: ShellCommandHandler,
     private val shellTaskOrganizer: ShellTaskOrganizer,
+    private val launchAdjacentController: LaunchAdjacentController,
 ) : DesksOrganizer, ShellTaskOrganizer.TaskListener {
 
     private val createDeskRootRequests = mutableListOf<CreateDeskRequest>()
@@ -110,7 +112,31 @@
         wct.reparent(task.token, root.taskInfo.token, /* onTop= */ true)
     }
 
+    override fun reorderTaskToFront(
+        wct: WindowContainerTransaction,
+        deskId: Int,
+        task: RunningTaskInfo,
+    ) {
+        logV("reorderTaskToFront task=${task.taskId} desk=$deskId")
+        val root = deskRootsByDeskId[deskId] ?: error("Root not found for desk: $deskId")
+        if (task.taskId in root.children) {
+            wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true)
+            return
+        }
+        val minimizationRoot =
+            checkNotNull(deskMinimizationRootsByDeskId[deskId]) {
+                "Minimization root not found for desk: $deskId"
+            }
+        if (task.taskId in minimizationRoot.children) {
+            unminimizeTask(wct, deskId, task)
+            wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true)
+            return
+        }
+        logE("Attempted to reorder task=${task.taskId} in desk=$deskId but it was not a child")
+    }
+
     override fun minimizeTask(wct: WindowContainerTransaction, deskId: Int, task: RunningTaskInfo) {
+        logV("minimizeTask task=${task.taskId} desk=$deskId")
         val deskRoot =
             checkNotNull(deskRootsByDeskId[deskId]) { "Root not found for desk: $deskId" }
         val minimizationRoot =
@@ -129,6 +155,30 @@
         wct.reparent(task.token, minimizationRoot.token, /* onTop= */ true)
     }
 
+    override fun unminimizeTask(
+        wct: WindowContainerTransaction,
+        deskId: Int,
+        task: RunningTaskInfo,
+    ) {
+        val taskId = task.taskId
+        logV("unminimizeTask task=$taskId desk=$deskId")
+        val deskRoot =
+            checkNotNull(deskRootsByDeskId[deskId]) { "Root not found for desk: $deskId" }
+        val minimizationRoot =
+            checkNotNull(deskMinimizationRootsByDeskId[deskId]) {
+                "Minimization root not found for desk: $deskId"
+            }
+        if (taskId in deskRoot.children) {
+            logV("Task #$taskId is already unminimized in desk=$deskId")
+            return
+        }
+        if (taskId !in minimizationRoot.children) {
+            logE("Attempted to unminimize task=$taskId in desk=$deskId but it was not a child")
+            return
+        }
+        wct.reparent(task.token, deskRoot.token, /* onTop= */ true)
+    }
+
     override fun isDeskChange(change: TransitionInfo.Change, deskId: Int): Boolean =
         (isDeskRootChange(change) && change.taskId == deskId) ||
             (getDeskMinimizationRootInChange(change)?.deskId == deskId)
@@ -164,6 +214,21 @@
             change.mode == TRANSIT_TO_FRONT
 
     override fun onTaskAppeared(taskInfo: RunningTaskInfo, leash: SurfaceControl) {
+        handleTaskAppeared(taskInfo, leash)
+        updateLaunchAdjacentController()
+    }
+
+    override fun onTaskInfoChanged(taskInfo: RunningTaskInfo) {
+        handleTaskInfoChanged(taskInfo)
+        updateLaunchAdjacentController()
+    }
+
+    override fun onTaskVanished(taskInfo: RunningTaskInfo) {
+        handleTaskVanished(taskInfo)
+        updateLaunchAdjacentController()
+    }
+
+    private fun handleTaskAppeared(taskInfo: RunningTaskInfo, leash: SurfaceControl) {
         // Check whether this task is appearing inside a desk.
         if (taskInfo.parentTaskId in deskRootsByDeskId) {
             val deskId = taskInfo.parentTaskId
@@ -216,7 +281,7 @@
         hideMinimizationRoot(deskMinimizationRoot)
     }
 
-    override fun onTaskInfoChanged(taskInfo: RunningTaskInfo) {
+    private fun handleTaskInfoChanged(taskInfo: RunningTaskInfo) {
         if (deskRootsByDeskId.contains(taskInfo.taskId)) {
             val deskId = taskInfo.taskId
             deskRootsByDeskId[deskId] = deskRootsByDeskId[deskId].copy(taskInfo = taskInfo)
@@ -254,7 +319,7 @@
         logE("onTaskInfoChanged: unknown task: ${taskInfo.taskId}")
     }
 
-    override fun onTaskVanished(taskInfo: RunningTaskInfo) {
+    private fun handleTaskVanished(taskInfo: RunningTaskInfo) {
         if (deskRootsByDeskId.contains(taskInfo.taskId)) {
             val deskId = taskInfo.taskId
             val deskRoot = deskRootsByDeskId[deskId]
@@ -336,6 +401,18 @@
         deskRootsByDeskId.forEach { _, deskRoot -> deskRoot.children -= taskId }
     }
 
+    private fun updateLaunchAdjacentController() {
+        deskRootsByDeskId.forEach { deskId, root ->
+            if (root.taskInfo.isVisible) {
+                // Disable launch adjacent handling if any desk is active, otherwise the split
+                // launch root and the desk root will both be eligible to take launching tasks.
+                launchAdjacentController.launchAdjacentEnabled = false
+                return
+            }
+        }
+        launchAdjacentController.launchAdjacentEnabled = true
+    }
+
     @VisibleForTesting
     data class DeskRoot(
         val deskId: Int,
@@ -377,6 +454,9 @@
     override fun dump(pw: PrintWriter, prefix: String) {
         val innerPrefix = "$prefix  "
         pw.println("$prefix$TAG")
+        pw.println(
+            "${innerPrefix}launchAdjacentEnabled=" + launchAdjacentController.launchAdjacentEnabled
+        )
         pw.println("${innerPrefix}Desk Roots:")
         deskRootsByDeskId.forEach { deskId, root ->
             val minimizationRoot = deskMinimizationRootsByDeskId[deskId]
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 897e2d1..2fe7865 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.util.SparseArray;
 import android.view.SurfaceControl;
+import android.window.DesktopExperienceFlags;
 import android.window.DesktopModeFlags;
 
 import com.android.internal.protolog.ProtoLog;
@@ -167,6 +168,11 @@
     }
 
     private void updateLaunchAdjacentController() {
+        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) {
+            // With multiple desks, freeform tasks are children of a root task controlled by
+            // DesksOrganizer, so toggling launch-adjacent should be managed there.
+            return;
+        }
         for (int i = 0; i < mTasks.size(); i++) {
             if (mTasks.valueAt(i).mTaskInfo.isVisible) {
                 mLaunchAdjacentController.setLaunchAdjacentEnabled(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index 8059b94..f89ba0a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -29,6 +29,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.wm.shell.desktopmode.DesktopImmersiveController;
+import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.Transitions;
@@ -52,6 +53,7 @@
     private final WindowDecorViewModel mWindowDecorViewModel;
     private final Optional<TaskChangeListener> mTaskChangeListener;
     private final FocusTransitionObserver mFocusTransitionObserver;
+    private final Optional<DesksTransitionObserver> mDesksTransitionObserver;
 
     private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> mTransitionToTaskInfo =
             new HashMap<>();
@@ -63,12 +65,14 @@
             Optional<DesktopImmersiveController> desktopImmersiveController,
             WindowDecorViewModel windowDecorViewModel,
             Optional<TaskChangeListener> taskChangeListener,
-            FocusTransitionObserver focusTransitionObserver) {
+            FocusTransitionObserver focusTransitionObserver,
+            Optional<DesksTransitionObserver> desksTransitionObserver) {
         mTransitions = transitions;
         mDesktopImmersiveController = desktopImmersiveController;
         mWindowDecorViewModel = windowDecorViewModel;
         mTaskChangeListener = taskChangeListener;
         mFocusTransitionObserver = focusTransitionObserver;
+        mDesksTransitionObserver = desksTransitionObserver;
         if (FreeformComponents.requiresFreeformComponents(context)) {
             shellInit.addInitCallback(this::onInit, this);
         }
@@ -85,6 +89,10 @@
             @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction startT,
             @NonNull SurfaceControl.Transaction finishT) {
+        // Update desk state first, otherwise [TaskChangeListener] may update desktop task state
+        // under an outdated active desk if a desk switch and a task update happen in the same
+        // transition, such as when unminimizing a task from an inactive desk.
+        mDesksTransitionObserver.ifPresent(o -> o.onTransitionReady(transition, info));
         if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()) {
             // TODO(b/367268953): Remove when DesktopTaskListener is introduced and the repository
             //  is updated from there **before** the |mWindowDecorViewModel| methods are invoked.
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 04f0336..0966110 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
@@ -70,6 +70,7 @@
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.window.DesktopModeFlags;
 import android.window.DisplayAreaInfo;
 import android.window.TaskOrganizer;
 import android.window.TaskSnapshot;
@@ -78,7 +79,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLog;
-import com.android.window.flags.Flags;
 import com.android.wm.shell.R;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -781,7 +781,7 @@
     // TODO(b/377581840): Update this check to include non-minimized cases, e.g. split to PiP etc.
     private boolean isPipExitingToDesktopMode() {
         DesktopRepository currentRepo = getCurrentRepo();
-        return Flags.enableDesktopWindowingPip() && currentRepo != null
+        return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue() && currentRepo != null
                 && (currentRepo.isAnyDeskActive(mTaskInfo.displayId)
                     || isDisplayInFreeform());
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 242f7fa..5706f19 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -39,11 +39,11 @@
 import android.view.InputMonitor;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
+import android.window.DesktopModeFlags;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.policy.TaskResizingAlgorithm;
-import com.android.window.flags.Flags;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
@@ -183,7 +183,7 @@
     private void reloadResources() {
         final Resources res = mContext.getResources();
         mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size);
-        mEnableDragCornerResize = Flags.enableDesktopWindowingPip();
+        mEnableDragCornerResize = DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue();
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
     }
 
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
index 65099c2..671eae3 100644
--- 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
@@ -153,7 +153,12 @@
         mPipUiEventLogger = pipUiEventLogger;
 
         mPipTransitionState.addPipTransitionStateChangedListener(this);
-
+        // Clear actions after exit PiP. Otherwise, next PiP could accidentally inherit the
+        // actions provided by the previous app in PiP mode.
+        mPipBoundsState.addOnPipComponentChangedListener(((oldPipComponent, newPipComponent) -> {
+            if (mAppActions != null) mAppActions.clear();
+            mCloseAction = null;
+        }));
         mPipTaskListener.addParamsChangedListener(new PipTaskListener.PipParamsChangedCallback() {
             @Override
             public void onActionsChanged(List<RemoteAction> actions, RemoteAction closeAction) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
index d663484..294ef48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
@@ -61,7 +61,7 @@
     private final PipBoundsState mPipBoundsState;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final ShellExecutor mMainExecutor;
-    private final PictureInPictureParams mPictureInPictureParams =
+    private PictureInPictureParams mPictureInPictureParams =
             new PictureInPictureParams.Builder().build();
 
     private boolean mWaitingForAspectRatioChange = false;
@@ -92,6 +92,11 @@
         }
         mPipResizeAnimatorSupplier = PipResizeAnimator::new;
         mPipScheduler.setPipParamsSupplier(this::getPictureInPictureParams);
+        // Reset {@link #mPictureInPictureParams} after exiting PiP. For instance, next Activity
+        // with null aspect ratio would accidentally inherit the aspect ratio from a previous
+        // PiP Activity.
+        mPipBoundsState.addOnPipComponentChangedListener(((oldPipComponent, newPipComponent) ->
+                mPictureInPictureParams = new PictureInPictureParams.Builder().build()));
     }
 
     void setPictureInPictureParams(@Nullable PictureInPictureParams params) {
@@ -138,9 +143,8 @@
         if (mPictureInPictureParams.hasSetAspectRatio()
                 && mPipBoundsAlgorithm.isValidPictureInPictureAspectRatio(newAspectRatio)
                 && PipUtils.aspectRatioChanged(newAspectRatio, mPipBoundsState.getAspectRatio())) {
-            mPipTransitionState.setOnIdlePipTransitionStateRunnable(() -> {
-                onAspectRatioChanged(newAspectRatio);
-            });
+            mPipTransitionState.setOnIdlePipTransitionStateRunnable(
+                    () -> onAspectRatioChanged(newAspectRatio));
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 7472b0e..c370c0c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -2920,7 +2920,7 @@
                     prepareEnterSplitScreen(out);
                     mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
                             TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering, SNAP_TO_2_50_50);
-                } else if (isSplitScreenVisible() && isOpening) {
+                } else if (enableFlexibleTwoAppSplit() && isSplitScreenVisible() && isOpening) {
                     // launching into an existing split stage; possibly launchAdjacent
                     // If we're replacing a pip-able app, we need to let mixed handler take care of
                     // it. Otherwise we'll just treat it as an enter+resize
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
index 01fc644..adc5cdf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
@@ -43,7 +43,7 @@
     private val captionWidth: Int,
     private val windowManagerWrapper: WindowManagerWrapper,
     context: Context,
-    snapshotList: List<Pair<Int, TaskSnapshot>>,
+    snapshotList: List<Pair<Int, TaskSnapshot?>>,
     onIconClickListener: ((Int) -> Unit),
     onOutsideClickListener: (() -> Unit)
 ) : ManageWindowsViewContainer(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
index 02a5433..3a75933 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
@@ -54,7 +54,7 @@
     private val desktopUserRepositories: DesktopUserRepositories,
     private val surfaceControlBuilderSupplier: Supplier<SurfaceControl.Builder>,
     private val surfaceControlTransactionSupplier: Supplier<SurfaceControl.Transaction>,
-    snapshotList: List<Pair<Int, TaskSnapshot>>,
+    snapshotList: List<Pair<Int, TaskSnapshot?>>,
     onIconClickListener: ((Int) -> Unit),
     onOutsideClickListener: (() -> Unit)
 ) : ManageWindowsViewContainer(
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 7ef1a93..a1d2774 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
@@ -17,11 +17,9 @@
 package com.android.wm.shell.windowdecor;
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 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;
 import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
 import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_HOVER_ENTER;
@@ -79,7 +77,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewRootImpl;
-import android.view.WindowManager;
 import android.window.DesktopModeFlags;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerToken;
@@ -121,7 +118,6 @@
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
 import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
 import com.android.wm.shell.desktopmode.DesktopUserRepositories;
-import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
 import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
 import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction;
 import com.android.wm.shell.desktopmode.common.ToggleTaskSizeUtilsKt;
@@ -146,6 +142,7 @@
 import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper;
 import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader;
 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
@@ -207,6 +204,7 @@
     private final Optional<DesktopTasksLimiter> mDesktopTasksLimiter;
     private final AppHandleEducationController mAppHandleEducationController;
     private final AppToWebEducationController mAppToWebEducationController;
+    private final AppHandleAndHeaderVisibilityHelper mAppHandleAndHeaderVisibilityHelper;
     private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory;
     private boolean mTransitionDragActive;
 
@@ -294,6 +292,7 @@
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
             AppHandleEducationController appHandleEducationController,
             AppToWebEducationController appToWebEducationController,
+            AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             FocusTransitionObserver focusTransitionObserver,
@@ -338,6 +337,7 @@
                 desktopTasksLimiter,
                 appHandleEducationController,
                 appToWebEducationController,
+                appHandleAndHeaderVisibilityHelper,
                 windowDecorCaptionHandleRepository,
                 activityOrientationChangeHandler,
                 new TaskPositionerFactory(),
@@ -386,6 +386,7 @@
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
             AppHandleEducationController appHandleEducationController,
             AppToWebEducationController appToWebEducationController,
+            AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             TaskPositionerFactory taskPositionerFactory,
@@ -431,6 +432,7 @@
         mDesktopTasksLimiter = desktopTasksLimiter;
         mAppHandleEducationController = appHandleEducationController;
         mAppToWebEducationController = appToWebEducationController;
+        mAppHandleAndHeaderVisibilityHelper = appHandleAndHeaderVisibilityHelper;
         mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository;
         mActivityOrientationChangeHandler = activityOrientationChangeHandler;
         mAssistContentRequester = assistContentRequester;
@@ -528,6 +530,7 @@
     @Override
     public void setSplitScreenController(SplitScreenController splitScreenController) {
         mSplitScreenController = splitScreenController;
+        mAppHandleAndHeaderVisibilityHelper.setSplitScreenController(splitScreenController);
     }
 
     @Override
@@ -1215,7 +1218,7 @@
             if (id == R.id.caption_handle) {
                 handleCaptionThroughStatusBar(e, decoration);
                 final boolean wasDragging = mIsDragging;
-                updateDragStatus(e.getActionMasked());
+                updateDragStatus(decoration, e);
                 final boolean upOrCancel = e.getActionMasked() == ACTION_UP
                         || e.getActionMasked() == ACTION_CANCEL;
                 if (wasDragging && upOrCancel) {
@@ -1231,6 +1234,13 @@
             return false;
         }
 
+        private void setIsDragging(
+                @Nullable DesktopModeWindowDecoration decor, boolean isDragging) {
+            mIsDragging = isDragging;
+            if (decor == null) return;
+            decor.setIsDragging(isDragging);
+        }
+
         private boolean handleFreeformMotionEvent(DesktopModeWindowDecoration decoration,
                 RunningTaskInfo taskInfo, View v, MotionEvent e) {
             final int id = v.getId();
@@ -1250,7 +1260,7 @@
                         final Rect initialBounds = mDragPositioningCallback.onDragPositioningStart(
                                 0 /* ctrlType */, e.getDisplayId(), e.getRawX(0),
                                 e.getRawY(0));
-                        updateDragStatus(e.getActionMasked());
+                        updateDragStatus(decoration, e);
                         mOnDragStartInitialBounds.set(initialBounds);
                     }
                     // Do not consume input event if a button is touched, otherwise it would
@@ -1277,7 +1287,7 @@
                             newTaskBounds);
                     //  Flip mIsDragging only if the bounds actually changed.
                     if (mIsDragging || !newTaskBounds.equals(mOnDragStartInitialBounds)) {
-                        updateDragStatus(e.getActionMasked());
+                        updateDragStatus(decoration, e);
                     }
                     return true;
                 }
@@ -1310,7 +1320,7 @@
                         // onClick call that results.
                         return false;
                     } else {
-                        updateDragStatus(e.getActionMasked());
+                        updateDragStatus(decoration, e);
                         return true;
                     }
                 }
@@ -1318,16 +1328,16 @@
             return true;
         }
 
-        private void updateDragStatus(int eventAction) {
-            switch (eventAction) {
+        private void updateDragStatus(DesktopModeWindowDecoration decor, MotionEvent e) {
+            switch (e.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL: {
-                    mIsDragging = false;
+                    setIsDragging(decor, false /* isDragging */);
                     break;
                 }
                 case MotionEvent.ACTION_MOVE: {
-                    mIsDragging = true;
+                    setIsDragging(decor, true /* isDragging */);
                     break;
                 }
             }
@@ -1717,32 +1727,7 @@
     }
 
     private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
-        if (mDisplayController.getDisplay(taskInfo.displayId) == null) {
-            // If DisplayController doesn't have it tracked, it could be a private/managed display.
-            return false;
-        }
-        if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
-        if (mSplitScreenController != null
-                && mSplitScreenController.isTaskRootOrStageRoot(taskInfo.taskId)) {
-            return false;
-        }
-        if (mDesktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(taskInfo)) {
-            return false;
-        }
-        final boolean isOnLargeScreen =
-                mDisplayController.getDisplay(taskInfo.displayId).getMinSizeDimensionDp()
-                        >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
-        if (!DesktopModeStatus.canEnterDesktopMode(mContext)
-                && DesktopModeStatus.overridesShowAppHandle(mContext) && !isOnLargeScreen) {
-            // Devices with multiple screens may enable the app handle but it should not show on
-            // small screens
-            return false;
-        }
-        return DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(mContext)
-                && !DesktopWallpaperActivity.isWallpaperTask(taskInfo)
-                && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
-                && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
-                && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop();
+        return mAppHandleAndHeaderVisibilityHelper.shouldShowAppHandleOrHeader(taskInfo);
     }
 
     private void createWindowDecoration(
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 2a53157..2ebe67b 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
@@ -207,7 +207,7 @@
     private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
     private final DesktopUserRepositories mDesktopUserRepositories;
     private boolean mIsRecentsTransitionRunning = false;
-
+    private boolean mIsDragging = false;
     private Runnable mLoadAppInfoRunnable;
     private Runnable mSetAppInfoRunnable;
 
@@ -513,7 +513,7 @@
         updateRelayoutParams(mRelayoutParams, mContext, taskInfo, mSplitScreenController,
                 applyStartTransactionOnDraw, shouldSetTaskVisibilityPositionAndCrop,
                 mIsStatusBarVisible, mIsKeyguardVisibleAndOccluded, inFullImmersive,
-                mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus,
+                mIsDragging, mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus,
                 displayExclusionRegion, mIsRecentsTransitionRunning,
                 mDesktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(taskInfo));
 
@@ -911,6 +911,7 @@
             boolean isStatusBarVisible,
             boolean isKeyguardVisibleAndOccluded,
             boolean inFullImmersiveMode,
+            boolean isDragging,
             @NonNull InsetsState displayInsetsState,
             boolean hasGlobalFocus,
             @NonNull Region displayExclusionRegion,
@@ -933,9 +934,13 @@
         relayoutParams.mAsyncViewHost = isAppHandle;
 
         final boolean showCaption;
-        if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()) {
+        if (DesktopModeFlags.ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX.isTrue() && isDragging) {
+            // If the task is being dragged, the caption should not be hidden so that it continues
+            // receiving input
+            showCaption = true;
+        } else if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()) {
             if (inFullImmersiveMode) {
-                showCaption = isStatusBarVisible && !isKeyguardVisibleAndOccluded;
+                showCaption = (isStatusBarVisible && !isKeyguardVisibleAndOccluded);
             } else {
                 showCaption = taskInfo.isFreeform()
                         || (isStatusBarVisible && !isKeyguardVisibleAndOccluded);
@@ -1799,6 +1804,13 @@
     }
 
     /**
+     * Declares whether the window decoration is being dragged.
+     */
+    void setIsDragging(boolean isDragging) {
+        mIsDragging = isDragging;
+    }
+
+    /**
      * Called when there is a {@link MotionEvent#ACTION_HOVER_EXIT} on the maximize window button.
      */
     void onMaximizeButtonHoverExit() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index d36fc12..a9df4bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -28,6 +28,7 @@
 
 import android.annotation.NonNull;
 import android.graphics.PointF;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 
@@ -43,6 +44,8 @@
  * All touch events must be passed through this class to track a drag event.
  */
 public class DragDetector {
+    private static final String TAG = "DragDetector";
+
     private final MotionEventHandler mEventHandler;
 
     private final PointF mInputDownPoint = new PointF();
@@ -109,8 +112,12 @@
                     return mResultOfDownAction;
                 }
                 final int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
+                // TODO(b/400635953): Separate the app header and its buttons'
+                // touch listeners so they're not handled by the same DragDetector.
                 if (dragPointerIndex == -1) {
-                    throw new IllegalStateException("Failed to find primary pointer!");
+                    Log.w(TAG, "Invalid pointer index on ACTION_MOVE. Drag"
+                        + " pointer id: " + mDragPointerId);
+                    return mResultOfDownAction;
                 }
                 if (!mIsDragEvent) {
                     float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index ad2e23c..c544468 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -39,7 +39,6 @@
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.Space
-import android.widget.TextView
 import android.window.DesktopModeFlags
 import android.window.SurfaceSyncGroup
 import androidx.annotation.StringRes
@@ -59,10 +58,10 @@
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
 import com.android.wm.shell.windowdecor.common.DecorThemeUtil
+import com.android.wm.shell.windowdecor.common.DrawableInsets
 import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
 import com.android.wm.shell.windowdecor.common.calculateMenuPosition
-import com.android.wm.shell.windowdecor.common.DrawableInsets
-import com.android.wm.shell.windowdecor.common.createRippleDrawable
+import com.android.wm.shell.windowdecor.common.createBackgroundDrawable
 import com.android.wm.shell.windowdecor.extension.isFullscreen
 import com.android.wm.shell.windowdecor.extension.isMultiWindow
 import com.android.wm.shell.windowdecor.extension.isPinned
@@ -471,32 +470,20 @@
         val rootView = LayoutInflater.from(context)
             .inflate(R.layout.desktop_mode_window_decor_handle_menu, null /* root */) as View
 
-        private val windowingButtonRippleRadius = context.resources
-            .getDimensionPixelSize(R.dimen.desktop_mode_handle_menu_windowing_action_ripple_radius)
-        private val windowingButtonDrawableInsets = DrawableInsets(
-            vertical = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
-            horizontal = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base)
-        )
-        private val windowingButtonDrawableInsetsLeft = DrawableInsets(
-            vertical = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
-            horizontalLeft = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_shift),
-        )
-        private val windowingButtonDrawableInsetsRight = DrawableInsets(
-            vertical = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
-            horizontalRight = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_shift)
-        )
+        // Insets for ripple effect of App Info Pill. and Windowing Pill. buttons
+        val iconButtondrawableShiftInset = context.resources.getDimensionPixelSize(
+            R.dimen.desktop_mode_handle_menu_icon_button_ripple_inset_shift)
+        val iconButtondrawableBaseInset = context.resources.getDimensionPixelSize(
+            R.dimen.desktop_mode_handle_menu_icon_button_ripple_inset_base)
+        private val iconButtonRippleRadius = context.resources.getDimensionPixelSize(
+            R.dimen.desktop_mode_handle_menu_icon_button_ripple_radius)
+        private val iconButtonDrawableInsetsBase = DrawableInsets(t = iconButtondrawableBaseInset,
+            b = iconButtondrawableBaseInset, l = iconButtondrawableBaseInset,
+            r = iconButtondrawableBaseInset)
+        private val iconButtonDrawableInsetsLeft = DrawableInsets(t = iconButtondrawableBaseInset,
+            b = iconButtondrawableBaseInset, l = iconButtondrawableShiftInset, r = 0)
+        private val iconButtonDrawableInsetsRight = DrawableInsets(t = iconButtondrawableBaseInset,
+            b = iconButtondrawableBaseInset, l = 0, r = iconButtondrawableShiftInset)
 
         // App Info Pill.
         private val appInfoPill = rootView.requireViewById<View>(R.id.app_info_pill)
@@ -713,6 +700,12 @@
             collapseMenuButton.apply {
                 imageTintList = ColorStateList.valueOf(style.textColor)
                 this.taskInfo = this@HandleMenuView.taskInfo
+
+                background = createBackgroundDrawable(
+                    color = style.textColor,
+                    cornerRadius = iconButtonRippleRadius,
+                    drawableInsets = iconButtonDrawableInsetsBase
+                )
             }
             appNameView.setTextColor(style.textColor)
             appNameView.startMarquee()
@@ -740,45 +733,39 @@
             desktopBtn.isEnabled = !taskInfo.isFreeform
             desktopBtn.imageTintList = style.windowingButtonColor
 
-            val startInsets = if (context.isRtl) {
-                windowingButtonDrawableInsetsRight
-            } else {
-                windowingButtonDrawableInsetsLeft
-            }
-            val endInsets = if (context.isRtl) {
-                windowingButtonDrawableInsetsLeft
-            } else {
-                windowingButtonDrawableInsetsRight
-            }
+            val startInsets = if (context.isRtl) iconButtonDrawableInsetsRight
+                else iconButtonDrawableInsetsLeft
+            val endInsets = if (context.isRtl) iconButtonDrawableInsetsLeft
+                else iconButtonDrawableInsetsRight
 
             fullscreenBtn.apply {
-                background = createRippleDrawable(
+                background = createBackgroundDrawable(
                     color = style.textColor,
-                    cornerRadius = windowingButtonRippleRadius,
+                    cornerRadius = iconButtonRippleRadius,
                     drawableInsets = startInsets
                 )
             }
 
             splitscreenBtn.apply {
-                background = createRippleDrawable(
+                background = createBackgroundDrawable(
                     color = style.textColor,
-                    cornerRadius = windowingButtonRippleRadius,
-                    drawableInsets = windowingButtonDrawableInsets
+                    cornerRadius = iconButtonRippleRadius,
+                    drawableInsets = iconButtonDrawableInsetsBase
                 )
             }
 
             floatingBtn.apply {
-                background = createRippleDrawable(
+                background = createBackgroundDrawable(
                     color = style.textColor,
-                    cornerRadius = windowingButtonRippleRadius,
-                    drawableInsets = windowingButtonDrawableInsets
+                    cornerRadius = iconButtonRippleRadius,
+                    drawableInsets = iconButtonDrawableInsetsBase
                 )
             }
 
             desktopBtn.apply {
-                background = createRippleDrawable(
+                background = createBackgroundDrawable(
                     color = style.textColor,
-                    cornerRadius = windowingButtonRippleRadius,
+                    cornerRadius = iconButtonRippleRadius,
                     drawableInsets = endInsets
                 )
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
index bdde096d..e8aac39 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
@@ -22,7 +22,7 @@
 import android.content.Context
 import android.content.res.ColorStateList
 import android.graphics.Color
-import android.graphics.drawable.RippleDrawable
+import android.graphics.drawable.Drawable
 import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.view.View
@@ -30,11 +30,11 @@
 import android.widget.FrameLayout
 import android.widget.ImageButton
 import android.widget.ProgressBar
+import android.window.DesktopModeFlags
 import androidx.core.animation.doOnEnd
 import androidx.core.animation.doOnStart
 import androidx.core.content.ContextCompat
 import com.android.wm.shell.R
-import android.window.DesktopModeFlags
 
 private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350
 private const val MAX_DRAWABLE_ALPHA = 255
@@ -109,14 +109,14 @@
         darkMode: Boolean,
         iconForegroundColor: ColorStateList? = null,
         baseForegroundColor: Int? = null,
-        rippleDrawable: RippleDrawable? = null
+        backgroundDrawable: Drawable? = null
     ) {
         if (DesktopModeFlags.ENABLE_THEMED_APP_HEADERS.isTrue()) {
             requireNotNull(iconForegroundColor) { "Icon foreground color must be non-null" }
             requireNotNull(baseForegroundColor) { "Base foreground color must be non-null" }
-            requireNotNull(rippleDrawable) { "Ripple drawable must be non-null" }
+            requireNotNull(backgroundDrawable) { "Background drawable must be non-null" }
             maximizeWindow.imageTintList = iconForegroundColor
-            maximizeWindow.background = rippleDrawable
+            maximizeWindow.background = backgroundDrawable
             stubProgressBarContainer.setOnInflateListener { _, inflated ->
                 val progressBar = (inflated as FrameLayout)
                     .requireViewById(R.id.progress_bar) as ProgressBar
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt
index 22bc978..cf536eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt
@@ -42,8 +42,6 @@
             .setDuration(ANIMATION_DURATION.toLong())
             .apply {
                 val t = SurfaceControl.Transaction()
-                val cornerRadius = context.resources
-                    .getDimensionPixelSize(R.dimen.desktop_mode_dragged_task_radius).toFloat()
                 addUpdateListener {
                     setTaskPosition(mostRecentInput.x, mostRecentInput.y)
                     t.setScale(taskSurface, scale, scale)
@@ -57,6 +55,8 @@
 
     val taskId get() = taskInfo.taskId
     val position: PointF = PointF(0.0f, 0.0f)
+    val cornerRadius: Float = context.resources
+        .getDimensionPixelSize(R.dimen.desktop_mode_dragged_task_radius).toFloat()
 
     /**
      * Whether motion events from the drag gesture should affect the dragged surface or not. Used
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt
new file mode 100644
index 0000000..39ccf5b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor.common
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import android.content.Context
+import android.view.WindowManager
+import android.window.DesktopExperienceFlags.ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.desktopmode.DesktopWallpaperActivity.Companion.isWallpaperTask
+import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.splitscreen.SplitScreenController
+
+/**
+ * Resolves whether, given a task and its associated display that it is currently on, to show the
+ * app handle/header or not.
+ */
+class AppHandleAndHeaderVisibilityHelper (
+    private val context: Context,
+    private val displayController: DisplayController,
+    private val desktopModeCompatPolicy: DesktopModeCompatPolicy
+) {
+    var splitScreenController: SplitScreenController? = null
+
+    /**
+     * Returns, given a task's attribute and its display attribute, whether the app
+     * handle/header should show or not for this task.
+     */
+    fun shouldShowAppHandleOrHeader(taskInfo: ActivityManager.RunningTaskInfo): Boolean {
+        if (!ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY.isTrue) {
+            return allowedForTask(taskInfo)
+        }
+        return allowedForTask(taskInfo) && allowedForDisplay(taskInfo.displayId)
+    }
+
+    private fun allowedForTask(taskInfo: ActivityManager.RunningTaskInfo): Boolean {
+        // TODO (b/382023296): Remove once we no longer rely on
+        //  Flags.enableBugFixesForSecondaryDisplay as it is taken care of in #allowedForDisplay
+        if (displayController.getDisplay(taskInfo.displayId) == null) {
+            // If DisplayController doesn't have it tracked, it could be a private/managed display.
+            return false
+        }
+        if (taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) return true
+        if (splitScreenController?.isTaskRootOrStageRoot(taskInfo.taskId) == true) {
+            return false
+        }
+
+        if (desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(taskInfo)) {
+            return false
+        }
+
+        // TODO (b/382023296): Remove once we no longer rely on
+        //  Flags.enableBugFixesForSecondaryDisplay as it is taken care of in #allowedForDisplay
+        val isOnLargeScreen =
+            displayController.getDisplay(taskInfo.displayId).minSizeDimensionDp >=
+                    WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
+        if (!DesktopModeStatus.canEnterDesktopMode(context)
+            && DesktopModeStatus.overridesShowAppHandle(context)
+            && !isOnLargeScreen
+        ) {
+            // Devices with multiple screens may enable the app handle but it should not show on
+            // small screens
+            return false
+        }
+        return DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)
+                && !isWallpaperTask(taskInfo)
+                && taskInfo.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED
+                && taskInfo.activityType == WindowConfiguration.ACTIVITY_TYPE_STANDARD
+                && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop
+    }
+
+    private fun allowedForDisplay(displayId: Int): Boolean {
+        // If DisplayController doesn't have it tracked, it could be a private/managed display.
+        val display = displayController.getDisplay(displayId)
+        if (display == null) return false
+
+        if (DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display)) {
+            return true
+        }
+        // If on default display and on Large Screen (unfolded), show app handle
+        return DesktopModeStatus.overridesShowAppHandle(context)
+                && display.minSizeDimensionDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ButtonBackgroundDrawableUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ButtonBackgroundDrawableUtils.kt
index e18239d..f08cfa9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ButtonBackgroundDrawableUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ButtonBackgroundDrawableUtils.kt
@@ -16,14 +16,12 @@
 package com.android.wm.shell.windowdecor.common
 
 import android.annotation.ColorInt
+import android.content.res.ColorStateList
 import android.graphics.Color
+import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
-import android.graphics.drawable.RippleDrawable
 import android.graphics.drawable.ShapeDrawable
 import android.graphics.drawable.shapes.RoundRectShape
-import com.android.wm.shell.windowdecor.common.OPACITY_11
-import com.android.wm.shell.windowdecor.common.OPACITY_15
-import android.content.res.ColorStateList
 
 /**
  * Represents drawable insets, specifying the number of pixels to inset a drawable from its bounds.
@@ -49,40 +47,30 @@
 }
 
 /**
- * Creates a RippleDrawable with specified color, corner radius, and insets.
+ * Creates a background drawable with specified color, corner radius, and insets.
  */
-fun createRippleDrawable(
-            @ColorInt color: Int,
-            cornerRadius: Int,
-            drawableInsets: DrawableInsets,
-): RippleDrawable {
-    return RippleDrawable(
-        ColorStateList(
+fun createBackgroundDrawable(
+    @ColorInt color: Int, cornerRadius: Int, drawableInsets: DrawableInsets
+): Drawable = LayerDrawable(arrayOf(
+    ShapeDrawable().apply {
+        shape = RoundRectShape(
+            FloatArray(8) { cornerRadius.toFloat() },
+            /* inset= */ null,
+            /* innerRadii= */ null
+        )
+        setTintList(ColorStateList(
             arrayOf(
                 intArrayOf(android.R.attr.state_hovered),
                 intArrayOf(android.R.attr.state_pressed),
-                intArrayOf(),
             ),
             intArrayOf(
                 replaceColorAlpha(color, OPACITY_11),
                 replaceColorAlpha(color, OPACITY_15),
-                Color.TRANSPARENT,
             )
-        ),
-        null /* content */,
-        LayerDrawable(arrayOf(
-            ShapeDrawable().apply {
-                shape = RoundRectShape(
-                    FloatArray(8) { cornerRadius.toFloat() },
-                    null /* inset */,
-                    null /* innerRadii */
-                )
-                paint.color = Color.WHITE
-            }
-        )).apply {
-            require(numberOfLayers == 1) { "Must only contain one layer" }
-            setLayerInset(0 /* index */,
-                drawableInsets.l, drawableInsets.t, drawableInsets.r, drawableInsets.b)
-        }
-    )
+        ))
+    }
+)).apply {
+    require(numberOfLayers == 1) { "Must only contain one layer" }
+    setLayerInset(/* index= */ 0,
+        drawableInsets.l, drawableInsets.t, drawableInsets.r, drawableInsets.b)
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
index 8b05433..30712b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
@@ -23,10 +23,6 @@
 import android.graphics.Bitmap
 import android.graphics.Color
 import android.graphics.Rect
-import android.graphics.drawable.LayerDrawable
-import android.graphics.drawable.RippleDrawable
-import android.graphics.drawable.ShapeDrawable
-import android.graphics.drawable.shapes.RoundRectShape
 import android.os.Bundle
 import android.view.View
 import android.view.View.OnLongClickListener
@@ -55,14 +51,12 @@
 import com.android.wm.shell.R
 import com.android.wm.shell.windowdecor.MaximizeButtonView
 import com.android.wm.shell.windowdecor.common.DecorThemeUtil
+import com.android.wm.shell.windowdecor.common.DrawableInsets
 import com.android.wm.shell.windowdecor.common.OPACITY_100
-import com.android.wm.shell.windowdecor.common.OPACITY_11
-import com.android.wm.shell.windowdecor.common.OPACITY_15
 import com.android.wm.shell.windowdecor.common.OPACITY_55
 import com.android.wm.shell.windowdecor.common.OPACITY_65
 import com.android.wm.shell.windowdecor.common.Theme
-import com.android.wm.shell.windowdecor.common.DrawableInsets
-import com.android.wm.shell.windowdecor.common.createRippleDrawable
+import com.android.wm.shell.windowdecor.common.createBackgroundDrawable
 import com.android.wm.shell.windowdecor.extension.isLightCaptionBarAppearance
 import com.android.wm.shell.windowdecor.extension.isTransparentCaptionBarAppearance
 
@@ -385,7 +379,7 @@
         val colorStateList = ColorStateList.valueOf(foregroundColor).withAlpha(foregroundAlpha)
         // App chip.
         openMenuButton.apply {
-            background = createRippleDrawable(
+            background = createBackgroundDrawable(
                 color = foregroundColor,
                 cornerRadius = headerButtonsRippleRadius,
                 drawableInsets = appChipDrawableInsets,
@@ -396,11 +390,12 @@
                 setTextColor(colorStateList)
             }
             appIconImageView.imageAlpha = foregroundAlpha
+            defaultFocusHighlightEnabled = false
         }
         // Minimize button.
         minimizeWindowButton.apply {
             imageTintList = colorStateList
-            background = createRippleDrawable(
+            background = createBackgroundDrawable(
                 color = foregroundColor,
                 cornerRadius = headerButtonsRippleRadius,
                 drawableInsets = minimizeDrawableInsets
@@ -413,7 +408,7 @@
                 darkMode = header.appTheme == Theme.DARK,
                 iconForegroundColor = colorStateList,
                 baseForegroundColor = foregroundColor,
-                rippleDrawable = createRippleDrawable(
+                backgroundDrawable = createBackgroundDrawable(
                     color = foregroundColor,
                     cornerRadius = headerButtonsRippleRadius,
                     drawableInsets = maximizeDrawableInsets
@@ -451,7 +446,7 @@
         // Close button.
         closeWindowButton.apply {
             imageTintList = colorStateList
-            background = createRippleDrawable(
+            background = createBackgroundDrawable(
                 color = foregroundColor,
                 cornerRadius = headerButtonsRippleRadius,
                 drawableInsets = closeDrawableInsets
@@ -471,11 +466,7 @@
 
     override fun onHandleMenuOpened() {}
 
-    override fun onHandleMenuClosed() {
-        openMenuButton.post {
-            openMenuButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
-        }
-    }
+    override fun onHandleMenuClosed() {}
 
     fun onMaximizeWindowHoverExit() {
         maximizeButtonView.cancelHoverAnimation()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromTaskbar.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromTaskbar.kt
index 3e98e43..7d9f2bf 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromTaskbar.kt
@@ -19,7 +19,7 @@
 import android.app.Instrumentation
 import android.tools.NavBar
 import android.tools.Rotation
-import android.tools.device.apphelpers.BrowserAppHelper
+import android.tools.device.apphelpers.GmailAppHelper
 import android.tools.flicker.rules.ChangeDisplayOrientationRule
 import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
@@ -44,8 +44,8 @@
     private val wmHelper = WindowManagerStateHelper(instrumentation)
     private val device = UiDevice.getInstance(instrumentation)
     private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
-    private val browserHelper = BrowserAppHelper(instrumentation)
-    private val browserApp = DesktopModeAppHelper(browserHelper)
+    private val gmailHelper = GmailAppHelper(instrumentation)
+    private val gmailApp = DesktopModeAppHelper(gmailHelper)
 
     @Rule
     @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@@ -59,20 +59,20 @@
         ChangeDisplayOrientationRule.setRotation(rotation)
         testApp.enterDesktopMode(wmHelper, device)
         tapl.showTaskbarIfHidden()
-        browserApp.launchViaIntent(wmHelper)
-        browserApp.minimizeDesktopApp(wmHelper, device)
+        gmailApp.launchViaIntent(wmHelper)
+        gmailApp.minimizeDesktopApp(wmHelper, device)
     }
 
     @Test
     open fun unminimizeApp() {
         tapl.launchedAppState.taskbar
-            .getAppIcon(browserHelper.appName)
-            .launch(browserHelper.packageName)
+            .getAppIcon(gmailHelper.appName)
+            .launch(gmailHelper.packageName)
     }
 
     @After
     fun teardown() {
         testApp.exit(wmHelper)
-        browserApp.exit(wmHelper)
+        gmailApp.exit(wmHelper)
     }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
index 6a6aa1a..fa9864b 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -17,15 +17,15 @@
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
 import android.tools.NavBar
-import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.helpers.WindowUtils
 import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.UiDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils.isLeftRightSplit
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -37,6 +37,8 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 abstract class SwitchAppByDoubleTapDividerBenchmark(override val flicker: LegacyFlickerTest) :
     SplitScreenBase(flicker) {
+    private val device = UiDevice.getInstance(instrumentation)
+
     protected val thisTransition: FlickerBuilder.() -> Unit
         get() = {
             setup {
@@ -73,7 +75,8 @@
                     }
                         ?: return@add false
 
-                if (isLandscape(flicker.scenario.endRotation)) {
+                if (isLeftRightSplit(instrumentation.context, flicker.scenario.endRotation,
+                        device.displaySizeDp)) {
                     return@add if (flicker.scenario.isTablet) {
                         secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
                     } else {
@@ -109,7 +112,8 @@
                 val secondaryVisibleRegion =
                     secondaryAppLayer.visibleRegion?.bounds ?: return@add false
 
-                if (isLandscape(flicker.scenario.endRotation)) {
+                if (isLeftRightSplit(instrumentation.context, flicker.scenario.endRotation,
+                        device.displaySizeDp)) {
                     return@add if (flicker.scenario.isTablet) {
                         secondaryVisibleRegion.right <= primaryVisibleRegion.left
                     } else {
@@ -126,11 +130,6 @@
             .waitForAndVerify()
     }
 
-    private fun isLandscape(rotation: Rotation): Boolean {
-        val displayBounds = WindowUtils.getDisplayBounds(rotation)
-        return displayBounds.width() > displayBounds.height()
-    }
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchAppByDoubleTapDivider.kt
index 26203d4..3fd93d3 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchAppByDoubleTapDivider.kt
@@ -17,16 +17,16 @@
 package com.android.wm.shell.scenarios
 
 import android.app.Instrumentation
-import android.graphics.Point
 import android.tools.NavBar
 import android.tools.Rotation
-import android.tools.helpers.WindowUtils
 import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.wm.shell.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils.isLeftRightSplit
+import com.android.wm.shell.flicker.utils.SplitScreenUtils.isTablet
 import org.junit.After
 import org.junit.Before
 import org.junit.Ignore
@@ -89,14 +89,14 @@
                     }
                         ?: return@add false
 
-                if (isLandscape(rotation)) {
-                    return@add if (isTablet()) {
+                if (isLeftRightSplit(instrumentation.context, rotation, device.displaySizeDp)) {
+                    return@add if (isTablet(device.displaySizeDp)) {
                         secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
                     } else {
                         primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
                     }
                 } else {
-                    return@add if (isTablet()) {
+                    return@add if (isTablet(device.displaySizeDp)) {
                         primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
                     } else {
                         primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
@@ -125,14 +125,14 @@
                 val secondaryVisibleRegion =
                     secondaryAppLayer.visibleRegion?.bounds ?: return@add false
 
-                if (isLandscape(rotation)) {
-                    return@add if (isTablet()) {
+                if (isLeftRightSplit(instrumentation.context, rotation, device.displaySizeDp)) {
+                    return@add if (isTablet(device.displaySizeDp)) {
                         secondaryVisibleRegion.right <= primaryVisibleRegion.left
                     } else {
                         primaryVisibleRegion.right <= secondaryVisibleRegion.left
                     }
                 } else {
-                    return@add if (isTablet()) {
+                    return@add if (isTablet(device.displaySizeDp)) {
                         primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
                     } else {
                         primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
@@ -141,15 +141,4 @@
             }
             .waitForAndVerify()
     }
-
-    private fun isLandscape(rotation: Rotation): Boolean {
-        val displayBounds = WindowUtils.getDisplayBounds(rotation)
-        return displayBounds.width() > displayBounds.height()
-    }
-
-    private fun isTablet(): Boolean {
-        val sizeDp: Point = device.displaySizeDp
-        val LARGE_SCREEN_DP_THRESHOLD = 600
-        return sizeDp.x >= LARGE_SCREEN_DP_THRESHOLD && sizeDp.y >= LARGE_SCREEN_DP_THRESHOLD
-    }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
index feb3edc..49d6877 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
@@ -17,12 +17,14 @@
 package com.android.wm.shell.flicker.utils
 
 import android.app.Instrumentation
+import android.content.Context
 import android.graphics.Point
 import android.os.SystemClock
 import android.tools.Rotation
 import android.tools.device.apphelpers.IStandardAppHelper
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.helpers.WindowUtils
 import android.tools.traces.component.ComponentNameMatcher
 import android.tools.traces.component.IComponentMatcher
 import android.tools.traces.component.IComponentNameMatcher
@@ -393,4 +395,24 @@
             error("Fail to copy content in split")
         }
     }
+
+    fun isLeftRightSplit(context: Context, rotation: Rotation, displaySizeDp: Point): Boolean {
+        val allowLeftRightSplit = context.resources.getBoolean(
+            com.android.internal.R.bool.config_leftRightSplitInPortrait)
+        val displayBounds = WindowUtils.getDisplayBounds(rotation)
+        val isLandscape = displayBounds.width() > displayBounds.height()
+        if (allowLeftRightSplit && isTablet(displaySizeDp)) {
+            // Certain devices allow left/right split in portrait, so they end up with top/bottom
+            // split in landscape
+            return !isLandscape
+        } else {
+            return isLandscape
+        }
+    }
+
+    fun isTablet(displaySizeDp: Point): Boolean {
+        val LARGE_SCREEN_DP_THRESHOLD = 600
+        return displaySizeDp.x >= LARGE_SCREEN_DP_THRESHOLD
+                && displaySizeDp.y >= LARGE_SCREEN_DP_THRESHOLD
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
index 42310ca..925ca0f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
@@ -25,6 +25,7 @@
 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.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
@@ -35,6 +36,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.view.SurfaceControl;
@@ -138,13 +140,14 @@
         return taskInfo;
     }
 
-    private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo) {
+    private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo,
+            SurfaceControl taskLeash, SurfaceControl snapshot) {
         final TransitionInfo info = new TransitionInfo(TRANSIT_CONVERT_TO_BUBBLE, 0);
-        final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token,
-                mock(SurfaceControl.class));
+        final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token, taskLeash);
         chg.setTaskInfo(taskInfo);
         chg.setMode(TRANSIT_CHANGE);
         chg.setStartAbsBounds(new Rect(0, 0, FULLSCREEN_TASK_WIDTH, FULLSCREEN_TASK_HEIGHT));
+        chg.setSnapshot(snapshot, /* luma= */ 0f);
         info.addChange(chg);
         info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0));
         return info;
@@ -172,7 +175,9 @@
         // Ensure we are communicating with the taskviewtransitions queue
         assertTrue(mTaskViewTransitions.hasPending());
 
-        final TransitionInfo info = setupFullscreenTaskTransition(taskInfo);
+        SurfaceControl taskLeash = new SurfaceControl.Builder().setName("taskLeash").build();
+        SurfaceControl snapshot = new SurfaceControl.Builder().setName("snapshot").build();
+        final TransitionInfo info = setupFullscreenTaskTransition(taskInfo, taskLeash, snapshot);
         SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
         SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
         final boolean[] finishCalled = new boolean[]{false};
@@ -183,7 +188,8 @@
         ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb);
         assertFalse(mTaskViewTransitions.hasPending());
 
-        verify(startT).setPosition(any(), eq(0f), eq(0f));
+        verify(startT).setPosition(taskLeash, 0, 0);
+        verify(startT).setPosition(snapshot, 0, 0);
 
         verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean());
 
@@ -194,7 +200,7 @@
         // Check that preparing transition is not reset before continueExpand is called
         verify(mBubble, never()).setPreparingTransition(any());
         ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class);
-        verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture());
+        verify(mLayerView).animateConvert(any(), any(), anyFloat(), any(), any(), animCb.capture());
 
         // continueExpand is now called, check that preparing transition is cleared
         ctb.continueExpand();
@@ -209,14 +215,14 @@
     public void testConvertToBubble_drag() {
         ActivityManager.RunningTaskInfo taskInfo = setupBubble();
 
-        Rect draggedTaskBounds = new Rect(10, 20, 30, 40);
         WindowContainerTransaction pendingWct = new WindowContainerTransaction();
         WindowContainerToken pendingDragOpToken = createMockToken();
         pendingWct.reorder(pendingDragOpToken, /* onTop= */ false);
 
+        PointF dragPosition = new PointF(10f, 20f);
         BubbleTransitions.DragData dragData = new BubbleTransitions.DragData(
-                draggedTaskBounds, pendingWct, /* releasedOnLeft= */ false
-        );
+                /* releasedOnLeft= */ false, /* taskScale= */ 0.5f, /* cornerRadius= */ 10f,
+                dragPosition, pendingWct);
 
         final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertToBubble(
                 mBubble, taskInfo, mExpandedViewManager, mTaskViewFactory, mBubblePositioner,
@@ -234,15 +240,21 @@
                 == WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
                 && op.getContainer() == pendingDragOpToken.asBinder())).isTrue();
 
-        final TransitionInfo info = setupFullscreenTaskTransition(taskInfo);
+        SurfaceControl taskLeash = new SurfaceControl.Builder().setName("taskLeash").build();
+        SurfaceControl snapshot = new SurfaceControl.Builder().setName("snapshot").build();
+        final TransitionInfo info = setupFullscreenTaskTransition(taskInfo, taskLeash, snapshot);
         SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
         SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
         Transitions.TransitionFinishCallback finishCb = wct -> {};
         ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb);
 
-        // Verify that dragged task bounds are used for the position
-        verify(startT).setPosition(any(), eq((float) draggedTaskBounds.left),
-                eq((float) draggedTaskBounds.top));
+        // Verify that snapshot and task are placed at where the drag ended
+        verify(startT).setPosition(taskLeash, dragPosition.x, dragPosition.y);
+        verify(startT).setPosition(snapshot, dragPosition.x, dragPosition.y);
+        // Snapshot has the scale of the dragged task
+        verify(startT).setScale(snapshot, dragData.getTaskScale(), dragData.getTaskScale());
+        // Snapshot has dragged task corner radius
+        verify(startT).setCornerRadius(snapshot, dragData.getCornerRadius());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsStateTest.java
index 01b76ed..1066276 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsStateTest.java
@@ -19,6 +19,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -128,6 +130,31 @@
     }
 
     @Test
+    public void setLastPipComponentName_notChanged_doesNotCallbackComponentChangedListener() {
+        mPipBoundsState.setLastPipComponentName(mTestComponentName1);
+        PipBoundsState.OnPipComponentChangedListener mockListener =
+                mock(PipBoundsState.OnPipComponentChangedListener.class);
+
+        mPipBoundsState.addOnPipComponentChangedListener(mockListener);
+        mPipBoundsState.setLastPipComponentName(mTestComponentName1);
+
+        verify(mockListener, never()).onPipComponentChanged(any(), any());
+    }
+
+    @Test
+    public void setLastPipComponentName_changed_callbackComponentChangedListener() {
+        mPipBoundsState.setLastPipComponentName(mTestComponentName1);
+        PipBoundsState.OnPipComponentChangedListener mockListener =
+                mock(PipBoundsState.OnPipComponentChangedListener.class);
+
+        mPipBoundsState.addOnPipComponentChangedListener(mockListener);
+        mPipBoundsState.setLastPipComponentName(mTestComponentName2);
+
+        verify(mockListener).onPipComponentChanged(
+                eq(mTestComponentName1), eq(mTestComponentName2));
+    }
+
+    @Test
     public void testSetLastPipComponentName_notChanged_doesNotClearReentryState() {
         mPipBoundsState.setLastPipComponentName(mTestComponentName1);
         mPipBoundsState.saveReentryState(DEFAULT_SNAP_FRACTION);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/crashhandling/ShellCrashHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/crashhandling/ShellCrashHandlerTest.kt
new file mode 100644
index 0000000..5c77f78
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/crashhandling/ShellCrashHandlerTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.crashhandling
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.PendingIntent
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.platform.test.annotations.DisableFlags
+import android.view.Display.DEFAULT_DISPLAY
+import android.window.IWindowContainerToken
+import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
+import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT
+import com.android.modules.utils.testing.ExtendedMockitoRule
+import com.android.window.flags.Flags
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.HomeIntentProvider
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.sysui.ShellInit
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.junit.Before
+import org.junit.Rule
+import org.mockito.ArgumentCaptor
+import org.mockito.Mockito
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+class ShellCrashHandlerTest : ShellTestCase() {
+    @JvmField
+    @Rule
+    val extendedMockitoRule =
+        ExtendedMockitoRule.Builder(this)
+            .mockStatic(DesktopModeStatus::class.java)
+            .mockStatic(PendingIntent::class.java)
+            .build()!!
+
+    private val testExecutor = mock<ShellExecutor>()
+    private val context = mock<Context>()
+    private val shellTaskOrganizer = mock<ShellTaskOrganizer>()
+
+    private lateinit var homeIntentProvider: HomeIntentProvider
+    private lateinit var crashHandler: ShellCrashHandler
+    private lateinit var shellInit: ShellInit
+
+
+    @Before
+    fun setup() {
+        whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
+        whenever(PendingIntent.getActivity(any(), any(), any(), any(), any())).thenReturn(mock())
+
+        shellInit = spy(ShellInit(testExecutor))
+
+        homeIntentProvider = HomeIntentProvider(context)
+        crashHandler = ShellCrashHandler(context, shellTaskOrganizer, homeIntentProvider, shellInit)
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun init_freeformTaskExists_sendsHomeIntent() {
+        val wctCaptor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(createTaskInfo(1)))
+
+        shellInit.init()
+
+        verify(shellTaskOrganizer).applyTransaction(
+            wctCaptor.capture()
+        )
+        wctCaptor.value.assertPendingIntentAt(0, launchHomeIntent(DEFAULT_DISPLAY))
+    }
+
+    private fun launchHomeIntent(displayId: Int): Intent {
+        return Intent(Intent.ACTION_MAIN).apply {
+            if (displayId != DEFAULT_DISPLAY) {
+                addCategory(Intent.CATEGORY_SECONDARY_HOME)
+            } else {
+                addCategory(Intent.CATEGORY_HOME)
+            }
+        }
+    }
+
+    private fun createTaskInfo(id: Int, windowingMode: Int = WINDOWING_MODE_FREEFORM) =
+        RunningTaskInfo().apply {
+            taskId = id
+            displayId = DEFAULT_DISPLAY
+            configuration.windowConfiguration.windowingMode = windowingMode
+            token = WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java))
+            baseIntent = Intent().apply { component = ComponentName("package", "component.name") }
+        }
+
+    private fun WindowContainerTransaction.assertPendingIntentAt(index: Int, intent: Intent) {
+        val op = hierarchyOps[index]
+        assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_PENDING_INTENT)
+        assertThat(op.activityIntent?.component).isEqualTo(intent.component)
+        assertThat(op.activityIntent?.categories).isEqualTo(intent.categories)
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandlerTest.kt
new file mode 100644
index 0000000..6a99d47
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandlerTest.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.SurfaceControl
+import android.view.WindowManager
+import android.window.TransitionInfo
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.util.StubTransaction
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class DesktopModeMoveToDisplayTransitionHandlerTest : ShellTestCase() {
+    private lateinit var handler: DesktopModeMoveToDisplayTransitionHandler
+
+    @Before
+    fun setUp() {
+        handler = DesktopModeMoveToDisplayTransitionHandler(StubTransaction())
+    }
+
+    @Test
+    fun handleRequest_returnsNull() {
+        assertNull(handler.handleRequest(mock(), mock()))
+    }
+
+    @Test
+    fun startAnimation_changeWithinDisplay_returnsFalse() {
+        val animates =
+            handler.startAnimation(
+                transition = mock(),
+                info =
+                    TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
+                        addChange(
+                            TransitionInfo.Change(mock(), mock()).apply {
+                                setDisplayId(/* start= */ 1, /* end= */ 1)
+                            }
+                        )
+                    },
+                startTransaction = StubTransaction(),
+                finishTransaction = StubTransaction(),
+                finishCallback = mock(),
+            )
+
+        assertFalse("Should not animate open transition", animates)
+    }
+
+    @Test
+    fun startAnimation_changeMoveToDisplay_returnsTrue() {
+        val animates =
+            handler.startAnimation(
+                transition = mock(),
+                info =
+                    TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
+                        addChange(
+                            TransitionInfo.Change(mock(), mock()).apply {
+                                setDisplayId(/* start= */ 1, /* end= */ 2)
+                            }
+                        )
+                    },
+                startTransaction = StubTransaction(),
+                finishTransaction = StubTransaction(),
+                finishCallback = mock(),
+            )
+
+        assertTrue("Should animate display change transition", animates)
+    }
+
+    @Test
+    fun startAnimation_movingActivityEmbedding_shouldSetCorrectBounds() {
+        val leashLeft = mock<SurfaceControl>()
+        val leashRight = mock<SurfaceControl>()
+        val leashContainer = mock<SurfaceControl>()
+        val startTransaction = spy(StubTransaction())
+
+        handler.startAnimation(
+            transition = mock(),
+            info =
+                TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
+                    addChange(
+                        TransitionInfo.Change(mock(), mock()).apply {
+                            flags = TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY
+                            leash = leashLeft
+                            setDisplayId(/* start= */ 1, /* end= */ 2)
+                            setEndAbsBounds(
+                                Rect(
+                                    /* left= */ 100,
+                                    /* top= */ 100,
+                                    /* right= */ 500,
+                                    /* bottom= */ 700,
+                                )
+                            )
+                            setEndRelOffset(/* left= */ 0, /* top= */ 0)
+                        }
+                    )
+                    addChange(
+                        TransitionInfo.Change(mock(), mock()).apply {
+                            flags = TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY
+                            leash = leashRight
+                            setDisplayId(1, 2)
+                            setEndAbsBounds(
+                                Rect(
+                                    /* left= */ 500,
+                                    /* top= */ 100,
+                                    /* right= */ 900,
+                                    /* bottom= */ 700,
+                                )
+                            )
+                            setEndRelOffset(/* left= */ 400, /* top= */ 0)
+                        }
+                    )
+                    addChange(
+                        TransitionInfo.Change(mock(), mock()).apply {
+                            flags = TransitionInfo.FLAG_TRANSLUCENT
+                            leash = leashContainer
+                            setDisplayId(/* start= */ 1, /* end= */ 2)
+                            setEndAbsBounds(
+                                Rect(
+                                    /* left= */ 100,
+                                    /* top= */ 100,
+                                    /* right= */ 900,
+                                    /* bottom= */ 700,
+                                )
+                            )
+                            setEndRelOffset(/* left= */ 100, /* top= */ 100)
+                        }
+                    )
+                },
+            startTransaction = startTransaction,
+            finishTransaction = StubTransaction(),
+            finishCallback = mock(),
+        )
+
+        verify(startTransaction).setPosition(leashLeft, 0f, 0f)
+        verify(startTransaction).setPosition(leashRight, 400f, 0f)
+        verify(startTransaction).setPosition(leashContainer, 100f, 100f)
+        verify(startTransaction).setWindowCrop(leashLeft, 400, 600)
+        verify(startTransaction).setWindowCrop(leashRight, 400, 600)
+        verify(startTransaction).setWindowCrop(leashContainer, 800, 600)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
index 2e74d43..de92d39 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
@@ -88,7 +88,7 @@
         datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
         shellInit = spy(ShellInit(testExecutor))
 
-        repo = DesktopRepository(persistentRepository, datastoreScope, DEFAULT_USER_ID)
+        repo = spy(DesktopRepository(persistentRepository, datastoreScope, DEFAULT_USER_ID))
         whenever(runBlocking { persistentRepository.readDesktop(any(), any()) })
             .thenReturn(Desktop.getDefaultInstance())
         shellInit.init()
@@ -1171,6 +1171,7 @@
 
         val tasksBeforeRemoval = repo.removeDesk(deskId = DEFAULT_DISPLAY)
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         assertThat(tasksBeforeRemoval).containsExactly(1, 2, 3).inOrder()
         assertThat(repo.getActiveTasks(displayId = DEFAULT_DISPLAY)).isEmpty()
     }
@@ -1184,6 +1185,7 @@
 
         repo.removeDesk(deskId = 3)
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         assertThat(repo.getDeskIds(displayId = DEFAULT_DISPLAY)).doesNotContain(3)
     }
 
@@ -1196,6 +1198,7 @@
 
         repo.removeDesk(deskId = 2)
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         assertThat(repo.getDeskIds(displayId = DEFAULT_DISPLAY)).doesNotContain(2)
     }
 
@@ -1424,6 +1427,7 @@
         repo.removeDesk(deskId = 1)
         executor.flushAll()
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         val lastRemoval = assertNotNull(listener.lastRemoval)
         assertThat(lastRemoval.displayId).isEqualTo(0)
         assertThat(lastRemoval.deskId).isEqualTo(1)
@@ -1440,6 +1444,7 @@
         repo.removeDesk(deskId = 2)
         executor.flushAll()
 
+        verify(repo, times(0)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         assertThat(listener.lastRemoval).isNull()
     }
 
@@ -1455,6 +1460,7 @@
         repo.removeDesk(deskId = 1)
         executor.flushAll()
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         val lastActivationChange = assertNotNull(listener.lastActivationChange)
         assertThat(lastActivationChange.displayId).isEqualTo(0)
         assertThat(lastActivationChange.oldActive).isEqualTo(1)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
index 6b0ee5b..4ace1b2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
@@ -119,9 +119,8 @@
     }
 
     @Test
-    fun onTaskChanging_freeformTask_nonActiveTaskInDesktopRepo_addsTaskToDesktopRepo() {
+    fun onTaskChanging_freeformTask_addsTaskToDesktopRepo() {
         val task = createFreeformTask().apply { isVisible = true }
-        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false)
 
         desktopTaskChangeListener.onTaskChanging(task)
 
@@ -129,28 +128,6 @@
     }
 
     @Test
-    fun onTaskChanging_freeformTask_activeVisibleTaskInDesktopRepo_updatesTaskVisibility() {
-        val task = createFreeformTask().apply { isVisible = true }
-        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true)
-
-        desktopTaskChangeListener.onTaskChanging(task)
-
-        verify(desktopUserRepositories.current)
-            .updateTask(task.displayId, task.taskId, task.isVisible)
-    }
-
-    @Test
-    fun onTaskChanging_freeformTask_activeNonVisibleTask_updatesTaskVisibility() {
-        val task = createFreeformTask().apply { isVisible = false }
-        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true)
-
-        desktopTaskChangeListener.onTaskChanging(task)
-
-        verify(desktopUserRepositories.current)
-            .updateTask(task.displayId, task.taskId, task.isVisible)
-    }
-
-    @Test
     fun onTaskMovingToFront_fullscreenTask_activeTaskInDesktopRepo_removesTaskFromRepo() {
         val task = createFullscreenTask().apply { isVisible = true }
         whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true)
@@ -180,6 +157,28 @@
     }
 
     @Test
+    fun onTaskMovingToBack_activeTaskInRepo_updatesTask() {
+        val task = createFreeformTask().apply { isVisible = true }
+        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true)
+
+        desktopTaskChangeListener.onTaskMovingToBack(task)
+
+        verify(desktopUserRepositories.current)
+            .updateTask(task.displayId, task.taskId, /* isVisible= */ false)
+    }
+
+    @Test
+    fun onTaskMovingToBack_nonActiveTaskInRepo_noop() {
+        val task = createFreeformTask().apply { isVisible = true }
+        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false)
+
+        desktopTaskChangeListener.onTaskMovingToBack(task)
+
+        verify(desktopUserRepositories.current, never())
+            .updateTask(task.displayId, task.taskId, /* isVisible= */ false)
+    }
+
+    @Test
     @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
     fun onTaskClosing_backNavEnabled_nonClosingTask_minimizesTaskInRepo() {
         val task = createFreeformTask().apply { isVisible = true }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 8fdad06..d093629 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -101,6 +101,7 @@
 import com.android.wm.shell.bubbles.BubbleController
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.common.HomeIntentProvider
 import com.android.wm.shell.common.MultiInstanceHelper
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.common.SyncTransactionQueue
@@ -263,6 +264,8 @@
     @Mock private lateinit var packageManager: PackageManager
     @Mock private lateinit var mockDisplayContext: Context
     @Mock private lateinit var dragToDisplayTransitionHandler: DragToDisplayTransitionHandler
+    @Mock
+    private lateinit var moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler
 
     private lateinit var controller: DesktopTasksController
     private lateinit var shellInit: ShellInit
@@ -273,6 +276,7 @@
     private lateinit var testScope: CoroutineScope
     private lateinit var desktopModeCompatPolicy: DesktopModeCompatPolicy
     private lateinit var spyContext: TestableContext
+    private lateinit var homeIntentProvider: HomeIntentProvider
 
     private val shellExecutor = TestShellExecutor()
     private val bgExecutor = TestShellExecutor()
@@ -321,12 +325,14 @@
                 transitions,
                 userRepositories,
                 shellTaskOrganizer,
+                desksOrganizer,
                 MAX_TASK_LIMIT,
                 mockInteractionJankMonitor,
                 mContext,
                 mockHandler,
             )
         desktopModeCompatPolicy = spy(DesktopModeCompatPolicy(spyContext))
+        homeIntentProvider = HomeIntentProvider(context)
 
         whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
         whenever(transitions.startTransition(anyInt(), any(), anyOrNull())).thenAnswer { Binder() }
@@ -445,6 +451,8 @@
             userProfileContexts,
             desktopModeCompatPolicy,
             dragToDisplayTransitionHandler,
+            moveToDisplayTransitionHandler,
+            homeIntentProvider,
         )
 
     @After
@@ -2360,6 +2368,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
     fun moveTaskToFront_postsWctWithReorderOp() {
         val task1 = setUpFreeformTask()
         setUpFreeformTask()
@@ -2382,9 +2391,34 @@
     }
 
     @Test
-    fun moveTaskToFront_bringsTasksOverLimit_minimizesBackTask() {
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun moveTaskToFront_reordersToFront() {
+        val task1 = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
+        setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
+        whenever(
+                desktopMixedTransitionHandler.startLaunchTransition(
+                    eq(TRANSIT_TO_FRONT),
+                    any(),
+                    eq(task1.taskId),
+                    anyOrNull(),
+                    anyOrNull(),
+                )
+            )
+            .thenReturn(Binder())
+
+        controller.moveTaskToFront(task1, remoteTransition = null)
+
+        verify(desksOrganizer).reorderTaskToFront(any(), eq(0), eq(task1))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun moveTaskToFront_bringsTasksOverLimit_multiDesksDisabled_minimizesBackTask() {
         setUpHomeTask()
-        val freeformTasks = (1..MAX_TASK_LIMIT + 1).map { _ -> setUpFreeformTask() }
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT + 1).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
+            }
         whenever(
                 desktopMixedTransitionHandler.startLaunchTransition(
                     eq(TRANSIT_TO_FRONT),
@@ -2405,6 +2439,32 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun moveTaskToFront_bringsTasksOverLimit_multiDesksEnabled_minimizesBackTask() {
+        val deskId = 0
+        setUpHomeTask()
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT + 1).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+            }
+        whenever(
+                desktopMixedTransitionHandler.startLaunchTransition(
+                    eq(TRANSIT_TO_FRONT),
+                    any(),
+                    eq(freeformTasks[0].taskId),
+                    anyOrNull(),
+                    anyOrNull(),
+                )
+            )
+            .thenReturn(Binder())
+
+        controller.moveTaskToFront(freeformTasks[0], remoteTransition = null)
+
+        val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
+        verify(desksOrganizer).minimizeTask(wct, deskId, freeformTasks[1])
+    }
+
+    @Test
     fun moveTaskToFront_minimizedTask_marksTaskAsUnminimized() {
         val transition = Binder()
         val freeformTask = setUpFreeformTask()
@@ -2493,8 +2553,13 @@
     }
 
     @Test
-    fun moveTaskToFront_backgroundTaskBringsTasksOverLimit_minimizesBackTask() {
-        val freeformTasks = (1..MAX_TASK_LIMIT).map { _ -> setUpFreeformTask() }
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun moveTaskToFront_backgroundTaskBringsTasksOverLimit_multiDesksDisabled_minimizesBackTask() {
+        val deskId = 0
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+            }
         val task = createRecentTaskInfo(1001)
         whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(null)
         whenever(
@@ -2517,11 +2582,38 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun moveTaskToFront_backgroundTaskBringsTasksOverLimit_multiDesksEnabled_minimizesBackTask() {
+        val deskId = 0
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+            }
+        val task = createRecentTaskInfo(1001)
+        whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(null)
+        whenever(
+                desktopMixedTransitionHandler.startLaunchTransition(
+                    eq(TRANSIT_OPEN),
+                    any(),
+                    eq(task.taskId),
+                    anyOrNull(),
+                    anyOrNull(),
+                )
+            )
+            .thenReturn(Binder())
+
+        controller.moveTaskToFront(task.taskId, unminimizeReason = UnminimizeReason.UNKNOWN)
+
+        val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
+        verify(desksOrganizer).minimizeTask(wct, deskId, freeformTasks[0])
+    }
+
+    @Test
     fun moveToNextDisplay_noOtherDisplays() {
         whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY))
         val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
         controller.moveToNextDisplay(task.taskId)
-        verifyWCTNotExecuted()
+        verify(transitions, never()).startTransition(anyInt(), any(), anyOrNull())
     }
 
     @Test
@@ -2539,9 +2631,12 @@
         controller.moveToNextDisplay(task.taskId)
 
         val taskChange =
-            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
-                it.container == task.token.asBinder() && it.isReparent
-            }
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .hierarchyOps
+                .find { it.container == task.token.asBinder() && it.isReparent }
         assertNotNull(taskChange)
         assertThat(taskChange.newParent).isEqualTo(secondDisplayArea.token.asBinder())
         assertThat(taskChange.toTop).isTrue()
@@ -2562,9 +2657,12 @@
         controller.moveToNextDisplay(task.taskId)
 
         val taskChange =
-            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
-                it.container == task.token.asBinder() && it.isReparent
-            }
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .hierarchyOps
+                .find { it.container == task.token.asBinder() && it.isReparent }
         assertNotNull(taskChange)
         assertThat(taskChange.newParent).isEqualTo(defaultDisplayArea.token.asBinder())
         assertThat(taskChange.toTop).isTrue()
@@ -2589,7 +2687,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        with(getLatestWct(type = TRANSIT_CHANGE)) {
+        with(
+            getLatestWct(
+                type = TRANSIT_CHANGE,
+                handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+            )
+        ) {
             val wallpaperChange =
                 hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() }
             assertNotNull(wallpaperChange)
@@ -2615,9 +2718,12 @@
         controller.moveToNextDisplay(task.taskId)
 
         val wallpaperChange =
-            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { op ->
-                op.container == wallpaperToken.asBinder()
-            }
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .hierarchyOps
+                .find { op -> op.container == wallpaperToken.asBinder() }
         assertNotNull(wallpaperChange)
         assertThat(wallpaperChange.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK)
     }
@@ -2649,7 +2755,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()]
+        val taskChange =
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .changes[task.token.asBinder()]
         assertNotNull(taskChange)
         // To preserve DP size, pixel size is changed to 320x240. The ratio of the left margin
         // to the right margin and the ratio of the top margin to bottom margin are also
@@ -2686,7 +2797,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()]
+        val taskChange =
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .changes[task.token.asBinder()]
         assertNotNull(taskChange)
         assertThat(taskChange.configuration.windowConfiguration.bounds)
             .isEqualTo(Rect(960, 480, 1280, 720))
@@ -2717,7 +2833,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()]
+        val taskChange =
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .changes[task.token.asBinder()]
         assertNotNull(taskChange)
         // DP size is preserved. The window is centered in the destination display.
         assertThat(taskChange.configuration.windowConfiguration.bounds)
@@ -2755,7 +2876,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()]
+        val taskChange =
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .changes[task.token.asBinder()]
         assertNotNull(taskChange)
         assertThat(taskChange.configuration.windowConfiguration.bounds.left).isAtLeast(0)
         assertThat(taskChange.configuration.windowConfiguration.bounds.top).isAtLeast(0)
@@ -2782,9 +2908,14 @@
         controller.moveToNextDisplay(task.taskId)
 
         val taskChange =
-            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
-                it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER
-            }
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .hierarchyOps
+                .find {
+                    it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER
+                }
         assertNotNull(taskChange)
         assertThat(taskChange.toTop).isTrue()
         assertThat(taskChange.includingParents()).isTrue()
@@ -3488,7 +3619,8 @@
     }
 
     @Test
-    fun handleRequest_fullscreenTaskToFreeform_underTaskLimit_dontMinimize() {
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskToDesk_underTaskLimit_multiDesksDisabled_dontMinimize() {
         val freeformTask = setUpFreeformTask()
         markTaskVisible(freeformTask)
         val fullscreenTask = createFullscreenTask()
@@ -3501,7 +3633,29 @@
     }
 
     @Test
-    fun handleRequest_fullscreenTaskToFreeform_bringsTasksOverLimit_otherTaskIsMinimized() {
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskToDesk_underTaskLimit_multiDesksEnabled_dontMinimize() {
+        val deskId = 5
+        taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        val freeformTask =
+            setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId).also {
+                markTaskVisible(it)
+            }
+
+        // Launch a fullscreen task while in the desk.
+        val fullscreenTask = createFullscreenTask()
+        val transition = Binder()
+        val wct = controller.handleRequest(transition, createTransition(fullscreenTask))
+
+        assertNotNull(wct)
+        verify(desksOrganizer, never()).minimizeTask(eq(wct), eq(deskId), any())
+        assertNull(desktopTasksLimiter.getMinimizingTask(transition))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskToDesk_bringsTasksOverLimit_multiDesksDisabled_otherTaskIsMinimized() {
         val freeformTasks = (1..MAX_TASK_LIMIT).map { _ -> setUpFreeformTask() }
         freeformTasks.forEach { markTaskVisible(it) }
         val fullscreenTask = createFullscreenTask()
@@ -3515,7 +3669,34 @@
     }
 
     @Test
-    fun handleRequest_fullscreenTaskWithTaskOnHome_bringsTasksOverLimit_otherTaskIsMinimized() {
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskToDesk_bringsTasksOverLimit_multiDesksEnabled_otherTaskIsMinimized() {
+        val deskId = 5
+        taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId).also {
+                    markTaskVisible(it)
+                }
+            }
+
+        // Launch a fullscreen task while in the desk.
+        setUpHomeTask()
+        val fullscreenTask = createFullscreenTask()
+        val transition = Binder()
+        val wct = controller.handleRequest(transition, createTransition(fullscreenTask))
+
+        assertNotNull(wct)
+        verify(desksOrganizer).minimizeTask(wct, deskId, freeformTasks[0])
+        val minimizingTask =
+            assertNotNull(desktopTasksLimiter.getMinimizingTask(transition)?.taskId)
+        assertThat(minimizingTask).isEqualTo(freeformTasks[0].taskId)
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskWithTaskOnHome_bringsTasksOverLimit_multiDesksDisabled_otherTaskIsMinimized() {
         val freeformTasks = (1..MAX_TASK_LIMIT).map { _ -> setUpFreeformTask() }
         freeformTasks.forEach { markTaskVisible(it) }
         val fullscreenTask = createFullscreenTask()
@@ -3524,13 +3705,43 @@
         val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
 
         // Make sure we reorder the new task to top, and the back task to the bottom
-        assertThat(wct!!.hierarchyOps.size).isEqualTo(9)
+        assertThat(wct!!.hierarchyOps.size).isEqualTo(8)
         wct.assertReorderAt(0, fullscreenTask, toTop = true)
-        wct.assertReorderAt(8, freeformTasks[0], toTop = false)
+        // Oldest task that needs to minimized is never reordered to top over Home.
+        val taskToMinimize = freeformTasks[0]
+        wct.assertWithoutHop { hop ->
+            hop.container == taskToMinimize.token &&
+                hop.type == HIERARCHY_OP_TYPE_REORDER &&
+                hop.toTop == true
+        }
     }
 
     @Test
-    fun handleRequest_fullscreenTaskWithTaskOnHome_beyondLimit_existingAndNewTasksAreMinimized() {
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskWithTaskOnHome_bringsTasksOverLimit_multiDesksEnabled_otherTaskIsMinimized() {
+        val deskId = 5
+        taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+            }
+        freeformTasks.forEach { markTaskVisible(it) }
+        val fullscreenTask = createFullscreenTask()
+        fullscreenTask.baseIntent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME)
+
+        val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+
+        assertNotNull(wct)
+        // The launching task is moved to the desk.
+        verify(desksOrganizer).moveTaskToDesk(wct, deskId, fullscreenTask)
+        // The bottom-most task is minimized.
+        verify(desksOrganizer).minimizeTask(wct, deskId, freeformTasks[0])
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskWithTaskOnHome_beyondLimit_multiDesksDisabled_existingAndNewTasksAreMinimized() {
         val minimizedTask = setUpFreeformTask()
         taskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = minimizedTask.taskId)
         val freeformTasks = (1..MAX_TASK_LIMIT).map { _ -> setUpFreeformTask() }
@@ -3541,12 +3752,100 @@
 
         val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
 
-        assertThat(wct!!.hierarchyOps.size).isEqualTo(10)
+        assertThat(wct!!.hierarchyOps.size).isEqualTo(9)
         wct.assertReorderAt(0, fullscreenTask, toTop = true)
         // Make sure we reorder the home task to the top, desktop tasks to top of them and minimized
         // task is under the home task.
         wct.assertReorderAt(1, homeTask, toTop = true)
-        wct.assertReorderAt(9, freeformTasks[0], toTop = false)
+        // Oldest task that needs to minimized is never reordered to top over Home.
+        val taskToMinimize = freeformTasks[0]
+        wct.assertWithoutHop { hop ->
+            hop.container == taskToMinimize.token &&
+                hop.type == HIERARCHY_OP_TYPE_REORDER &&
+                hop.toTop == true
+        }
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskWithTaskOnHome_beyondLimit_multiDesksEnabled_existingAndNewTasksAreMinimized() {
+        // A desk with a minimized tasks, and non-minimized tasks already at the task limit.
+        val deskId = 5
+        taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        val minimizedTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        taskRepository.minimizeTaskInDesk(
+            displayId = DEFAULT_DISPLAY,
+            deskId = deskId,
+            taskId = minimizedTask.taskId,
+        )
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId).also {
+                    markTaskVisible(it)
+                }
+            }
+
+        // Launch a fullscreen task that brings Home to front with it.
+        setUpHomeTask()
+        val fullscreenTask = createFullscreenTask()
+        fullscreenTask.baseIntent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME)
+        val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+
+        assertNotNull(wct)
+        verify(desksOrganizer).minimizeTask(wct, deskId, freeformTasks[0])
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_fullscreenTaskWithTaskOnHome_taskAddedToDesk() {
+        // A desk with a minimized tasks, and non-minimized tasks already at the task limit.
+        val deskId = 5
+        taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+
+        // Launch a fullscreen task that brings Home to front with it.
+        setUpHomeTask()
+        val fullscreenTask = createFullscreenTask()
+        fullscreenTask.baseIntent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME)
+        val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+
+        assertNotNull(wct)
+        verify(desksOrganizer).moveTaskToDesk(wct, deskId, fullscreenTask)
+    }
+
+    @Test
+    @EnableFlags(
+        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+        Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY,
+        Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+    )
+    fun handleRequest_fullscreenTaskWithTaskOnHome_activatesDesk() {
+        val deskId = 5
+        taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+        taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId)
+
+        // Launch a fullscreen task that brings Home to front with it.
+        val homeTask = setUpHomeTask()
+        val fullscreenTask = createFullscreenTask()
+        fullscreenTask.baseIntent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME)
+        val transition = Binder()
+        val wct = controller.handleRequest(transition, createTransition(fullscreenTask))
+
+        assertNotNull(wct)
+        wct.assertReorder(homeTask, toTop = true)
+        wct.assertReorder(wallpaperToken, toTop = true)
+        verify(desksOrganizer).activateDesk(wct, deskId)
+        verify(desksTransitionsObserver)
+            .addPendingTransition(
+                DeskTransition.ActiveDeskWithTask(
+                    token = transition,
+                    displayId = DEFAULT_DISPLAY,
+                    deskId = deskId,
+                    enterTaskId = fullscreenTask.taskId,
+                )
+            )
     }
 
     @Test
@@ -3609,8 +3908,13 @@
     }
 
     @Test
-    fun handleRequest_freeformTask_freeformVisible_aboveTaskLimit_minimize() {
-        val freeformTasks = (1..MAX_TASK_LIMIT).map { _ -> setUpFreeformTask() }
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_freeformTask_freeformVisible_aboveTaskLimit_multiDesksDisabled_minimize() {
+        val deskId = 0
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+            }
         freeformTasks.forEach { markTaskVisible(it) }
         val newFreeformTask = createFreeformTask()
 
@@ -3623,6 +3927,24 @@
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun handleRequest_freeformTask_freeformVisible_aboveTaskLimit_multiDesksEnabled_minimize() {
+        val deskId = 0
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+            }
+        freeformTasks.forEach { markTaskVisible(it) }
+        val newFreeformTask = createFreeformTask()
+
+        val wct =
+            controller.handleRequest(Binder(), createTransition(newFreeformTask, TRANSIT_OPEN))
+
+        assertNotNull(wct)
+        verify(desksOrganizer).minimizeTask(wct, deskId, freeformTasks[0])
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
     fun handleRequest_freeformTaskFromInactiveDesk_tracksDeskDeactivation() {
         val deskId = 0
         val freeformTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
@@ -5524,7 +5846,8 @@
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
-    fun openInstance_fromFreeformAddsNewWindow() {
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun openInstance_fromFreeformAddsNewWindow_multiDesksDisabled() {
         setUpLandscapeDisplay()
         val task = setUpFreeformTask()
         val taskToRequest = setUpFreeformTask()
@@ -5538,7 +5861,9 @@
                 )
             )
             .thenReturn(Binder())
+
         runOpenInstance(task, taskToRequest.taskId)
+
         verify(desktopMixedTransitionHandler)
             .startLaunchTransition(anyInt(), any(), anyInt(), anyOrNull(), anyOrNull())
         val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
@@ -5547,10 +5872,42 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
-    fun openInstance_fromFreeform_minimizesIfNeeded() {
+    @EnableFlags(
+        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES,
+        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+    )
+    fun openInstance_fromFreeformAddsNewWindow_multiDesksEnabled() {
         setUpLandscapeDisplay()
-        val freeformTasks = (1..MAX_TASK_LIMIT + 1).map { _ -> setUpFreeformTask() }
+        val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
+        val taskToRequest = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0)
+        whenever(
+                desktopMixedTransitionHandler.startLaunchTransition(
+                    eq(TRANSIT_TO_FRONT),
+                    any(),
+                    eq(taskToRequest.taskId),
+                    anyOrNull(),
+                    anyOrNull(),
+                )
+            )
+            .thenReturn(Binder())
+
+        runOpenInstance(task, taskToRequest.taskId)
+
+        verify(desktopMixedTransitionHandler)
+            .startLaunchTransition(anyInt(), any(), anyInt(), anyOrNull(), anyOrNull())
+        verify(desksOrganizer).reorderTaskToFront(any(), eq(0), eq(taskToRequest))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun openInstance_fromFreeform_multiDesksDisabled_minimizesIfNeeded() {
+        setUpLandscapeDisplay()
+        val deskId = 0
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT + 1).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+            }
         val oldestTask = freeformTasks.first()
         val newestTask = freeformTasks.last()
 
@@ -5576,6 +5933,40 @@
     }
 
     @Test
+    @EnableFlags(
+        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES,
+        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+    )
+    fun openInstance_fromFreeform_multiDesksEnabled_minimizesIfNeeded() {
+        setUpLandscapeDisplay()
+        val deskId = 0
+        val freeformTasks =
+            (1..MAX_TASK_LIMIT + 1).map { _ ->
+                setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId)
+            }
+        val oldestTask = freeformTasks.first()
+        val newestTask = freeformTasks.last()
+
+        val transition = Binder()
+        val wctCaptor = argumentCaptor<WindowContainerTransaction>()
+        whenever(
+                desktopMixedTransitionHandler.startLaunchTransition(
+                    anyInt(),
+                    wctCaptor.capture(),
+                    anyInt(),
+                    anyOrNull(),
+                    anyOrNull(),
+                )
+            )
+            .thenReturn(transition)
+
+        runOpenInstance(newestTask, freeformTasks[1].taskId)
+
+        val wct = wctCaptor.firstValue
+        verify(desksOrganizer).minimizeTask(wct, deskId, oldestTask)
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
     fun openInstance_fromFreeform_exitsImmersiveIfNeeded() {
         setUpLandscapeDisplay()
@@ -6533,7 +6924,7 @@
         Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
     )
     fun startLaunchTransition_desktopNotShowing_movesWallpaperToFront() {
-        val launchingTask = createFreeformTask()
+        val launchingTask = createFreeformTask(displayId = DEFAULT_DISPLAY)
         val wct = WindowContainerTransaction()
         wct.reorder(launchingTask.token, /* onTop= */ true)
         whenever(
@@ -6547,7 +6938,13 @@
             )
             .thenReturn(Binder())
 
-        controller.startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
+        controller.startLaunchTransition(
+            transitionType = TRANSIT_OPEN,
+            wct = wct,
+            launchingTaskId = null,
+            deskId = 0,
+            displayId = DEFAULT_DISPLAY,
+        )
 
         val latestWct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
         val launchingTaskReorderIndex = latestWct.indexOfReorder(launchingTask, toTop = true)
@@ -6571,6 +6968,8 @@
             transitionType = TRANSIT_OPEN,
             wct = WindowContainerTransaction(),
             launchingTaskId = null,
+            deskId = 0,
+            displayId = DEFAULT_DISPLAY,
         )
 
         verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(any())
@@ -6580,6 +6979,51 @@
     @EnableFlags(
         Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
         Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+    )
+    fun startLaunchTransition_launchingTaskFromInactiveDesk_otherDeskActive_activatesDesk() {
+        val activeDeskId = 4
+        taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = activeDeskId)
+        taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = activeDeskId)
+        val inactiveDesk = 5
+        taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = inactiveDesk)
+        val launchingTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = inactiveDesk)
+        val transition = Binder()
+        whenever(
+                desktopMixedTransitionHandler.startLaunchTransition(
+                    eq(TRANSIT_OPEN),
+                    any(),
+                    eq(launchingTask.taskId),
+                    anyOrNull(),
+                    anyOrNull(),
+                )
+            )
+            .thenReturn(transition)
+
+        val wct = WindowContainerTransaction()
+        controller.startLaunchTransition(
+            transitionType = TRANSIT_OPEN,
+            wct = wct,
+            launchingTaskId = launchingTask.taskId,
+            deskId = inactiveDesk,
+            displayId = DEFAULT_DISPLAY,
+        )
+
+        verify(desksOrganizer).activateDesk(any(), eq(inactiveDesk))
+        verify(desksTransitionsObserver)
+            .addPendingTransition(
+                DeskTransition.ActivateDesk(
+                    token = transition,
+                    displayId = DEFAULT_DISPLAY,
+                    deskId = inactiveDesk,
+                )
+            )
+    }
+
+    @Test
+    @EnableFlags(
+        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+        Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
     )
     fun startLaunchTransition_desktopShowing_doesNotReorderWallpaper() {
         val wct = WindowContainerTransaction()
@@ -6594,8 +7038,14 @@
             )
             .thenReturn(Binder())
 
-        setUpFreeformTask()
-        controller.startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
+        setUpFreeformTask(deskId = 0, displayId = DEFAULT_DISPLAY)
+        controller.startLaunchTransition(
+            transitionType = TRANSIT_OPEN,
+            wct = wct,
+            launchingTaskId = null,
+            deskId = 0,
+            displayId = DEFAULT_DISPLAY,
+        )
 
         val latestWct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
         assertNull(latestWct.hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() })
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
index 62e3c54..eeecb00 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
@@ -39,12 +39,14 @@
 import com.android.dx.mockito.inline.extended.StaticMockitoSession
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION
+import com.android.window.flags.Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer
 import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
 import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
@@ -67,10 +69,13 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito.any
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.never
 import org.mockito.quality.Strictness
 
 /**
@@ -84,6 +89,7 @@
 class DesktopTasksLimiterTest : ShellTestCase() {
 
     @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer
+    @Mock lateinit var desksOrganizer: DesksOrganizer
     @Mock lateinit var transitions: Transitions
     @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
     @Mock lateinit var handler: Handler
@@ -128,6 +134,7 @@
                 transitions,
                 userRepositories,
                 shellTaskOrganizer,
+                desksOrganizer,
                 MAX_TASK_LIMIT,
                 interactionJankMonitor,
                 mContext,
@@ -148,6 +155,7 @@
                 transitions,
                 userRepositories,
                 shellTaskOrganizer,
+                desksOrganizer,
                 0,
                 interactionJankMonitor,
                 mContext,
@@ -163,6 +171,7 @@
                 transitions,
                 userRepositories,
                 shellTaskOrganizer,
+                desksOrganizer,
                 -5,
                 interactionJankMonitor,
                 mContext,
@@ -172,6 +181,21 @@
     }
 
     @Test
+    fun createDesktopTasksLimiter_withNoLimit_shouldSucceed() {
+        // Instantiation should succeed without an error.
+        DesktopTasksLimiter(
+            transitions,
+            userRepositories,
+            shellTaskOrganizer,
+            desksOrganizer,
+            maxTasksLimit = null,
+            interactionJankMonitor,
+            mContext,
+            handler,
+        )
+    }
+
+    @Test
     fun addPendingMinimizeTransition_taskIsNotMinimized() {
         desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
@@ -380,7 +404,8 @@
     }
 
     @Test
-    fun addAndGetMinimizeTaskChanges_tasksWithinLimit_noTaskMinimized() {
+    @DisableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun addAndGetMinimizeTaskChanges_tasksWithinLimit_multiDesksDisabled_noTaskMinimized() {
         desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() }
@@ -388,7 +413,7 @@
         val wct = WindowContainerTransaction()
         val minimizedTaskId =
             desktopTasksLimiter.addAndGetMinimizeTaskChanges(
-                displayId = DEFAULT_DISPLAY,
+                deskId = 0,
                 wct = wct,
                 newFrontTaskId = setUpFreeformTask().taskId,
             )
@@ -398,7 +423,27 @@
     }
 
     @Test
-    fun addAndGetMinimizeTaskChanges_tasksAboveLimit_backTaskMinimized() {
+    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun addAndGetMinimizeTaskChanges_tasksWithinLimit_multiDesksEnabled_noTaskMinimized() {
+        desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
+        desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
+        (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() }
+
+        val wct = WindowContainerTransaction()
+        val minimizedTaskId =
+            desktopTasksLimiter.addAndGetMinimizeTaskChanges(
+                deskId = 0,
+                wct = wct,
+                newFrontTaskId = setUpFreeformTask().taskId,
+            )
+
+        assertThat(minimizedTaskId).isNull()
+        verify(desksOrganizer, never()).minimizeTask(eq(wct), eq(0), any())
+    }
+
+    @Test
+    @DisableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun addAndGetMinimizeTaskChanges_tasksAboveLimit_multiDesksDisabled_backTaskMinimized() {
         desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         // The following list will be ordered bottom -> top, as the last task is moved to top last.
@@ -407,7 +452,7 @@
         val wct = WindowContainerTransaction()
         val minimizedTaskId =
             desktopTasksLimiter.addAndGetMinimizeTaskChanges(
-                displayId = DEFAULT_DISPLAY,
+                deskId = DEFAULT_DISPLAY,
                 wct = wct,
                 newFrontTaskId = setUpFreeformTask().taskId,
             )
@@ -419,7 +464,28 @@
     }
 
     @Test
-    fun addAndGetMinimizeTaskChanges_nonMinimizedTasksWithinLimit_noTaskMinimized() {
+    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun addAndGetMinimizeTaskChanges_tasksAboveLimit_multiDesksEnabled_backTaskMinimized() {
+        desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
+        desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
+        // The following list will be ordered bottom -> top, as the last task is moved to top last.
+        val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() }
+
+        val wct = WindowContainerTransaction()
+        val minimizedTaskId =
+            desktopTasksLimiter.addAndGetMinimizeTaskChanges(
+                deskId = DEFAULT_DISPLAY,
+                wct = wct,
+                newFrontTaskId = setUpFreeformTask().taskId,
+            )
+
+        assertThat(minimizedTaskId).isEqualTo(tasks.first().taskId)
+        verify(desksOrganizer).minimizeTask(wct, deskId = 0, tasks.first())
+    }
+
+    @Test
+    @DisableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun addAndGetMinimizeTaskChanges_nonMinimizedTasksWithinLimit_multiDesksDisabled_noTaskMinimized() {
         desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() }
@@ -428,7 +494,7 @@
         val wct = WindowContainerTransaction()
         val minimizedTaskId =
             desktopTasksLimiter.addAndGetMinimizeTaskChanges(
-                displayId = 0,
+                deskId = 0,
                 wct = wct,
                 newFrontTaskId = setUpFreeformTask().taskId,
             )
@@ -438,6 +504,26 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+    fun addAndGetMinimizeTaskChanges_nonMinimizedTasksWithinLimit_multiDesksEnabled_noTaskMinimized() {
+        desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
+        desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
+        val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() }
+        desktopTaskRepo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = tasks[0].taskId)
+
+        val wct = WindowContainerTransaction()
+        val minimizedTaskId =
+            desktopTasksLimiter.addAndGetMinimizeTaskChanges(
+                deskId = 0,
+                wct = wct,
+                newFrontTaskId = setUpFreeformTask().taskId,
+            )
+
+        assertThat(minimizedTaskId).isNull()
+        verify(desksOrganizer, never()).minimizeTask(eq(wct), eq(0), any())
+    }
+
+    @Test
     fun getTaskToMinimize_tasksWithinLimit_returnsNull() {
         desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
@@ -471,6 +557,7 @@
                 transitions,
                 userRepositories,
                 shellTaskOrganizer,
+                desksOrganizer,
                 MAX_TASK_LIMIT2,
                 interactionJankMonitor,
                 mContext,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
index fd8842b..a7dc706 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
@@ -48,13 +48,11 @@
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG
 import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider
-import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
 import com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP
 import com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP
-import com.android.wm.shell.util.StubTransaction
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Before
@@ -95,7 +93,6 @@
     private val backAnimationController = mock<BackAnimationController>()
     private val desktopWallpaperActivityTokenProvider =
         mock<DesktopWallpaperActivityTokenProvider>()
-    private val desksTransitionObserver = mock<DesksTransitionObserver>()
     private val wallpaperToken = MockToken().token()
 
     private lateinit var transitionObserver: DesktopTasksTransitionObserver
@@ -119,7 +116,6 @@
                 mixedHandler,
                 backAnimationController,
                 desktopWallpaperActivityTokenProvider,
-                desksTransitionObserver,
                 shellInit,
             )
     }
@@ -403,21 +399,6 @@
         verify(taskRepository).setTaskInPip(task.displayId, task.taskId, enterPip = false)
     }
 
-    @Test
-    fun onTransitionReady_forwardsToDesksTransitionObserver() {
-        val transition = Binder()
-        val info = TransitionInfo(TRANSIT_CLOSE, /* flags= */ 0)
-
-        transitionObserver.onTransitionReady(
-            transition = transition,
-            info = info,
-            StubTransaction(),
-            StubTransaction(),
-        )
-
-        verify(desksTransitionObserver).onTransitionReady(transition, info)
-    }
-
     private fun createBackNavigationTransition(
         task: RunningTaskInfo?,
         type: Int = TRANSIT_TO_BACK,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
index c00083b..c40a04c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt
@@ -41,6 +41,7 @@
             .setActivityType(ACTIVITY_TYPE_STANDARD)
             .setWindowingMode(WINDOWING_MODE_FREEFORM)
             .setLastActiveTime(100)
+            .setUserId(DEFAULT_USER_ID)
             .apply { bounds?.let { setBounds(it) } }
             .build()
 
@@ -50,6 +51,7 @@
             .setToken(MockToken().token())
             .setActivityType(ACTIVITY_TYPE_STANDARD)
             .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+            .setUserId(DEFAULT_USER_ID)
             .setLastActiveTime(100)
 
     /** Create a task that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */
@@ -63,6 +65,7 @@
             .setToken(MockToken().token())
             .setActivityType(ACTIVITY_TYPE_STANDARD)
             .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
+            .setUserId(DEFAULT_USER_ID)
             .setLastActiveTime(100)
             .build()
 
@@ -72,6 +75,7 @@
             .setToken(MockToken().token())
             .setActivityType(ACTIVITY_TYPE_HOME)
             .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+            .setUserId(DEFAULT_USER_ID)
             .setLastActiveTime(100)
             .build()
 
@@ -91,4 +95,6 @@
         createSystemModalTask().apply {
             baseActivity = ComponentName("com.test.dummypackage", "TestClass")
         }
+
+    const val DEFAULT_USER_ID = 10
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 9588a5c..0871d38 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -15,7 +15,6 @@
 import android.platform.test.annotations.EnableFlags
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
-import android.view.Display.DEFAULT_DISPLAY
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_OPEN
 import android.window.TransitionInfo
@@ -785,7 +784,7 @@
         startTransaction: SurfaceControl.Transaction = mock(),
         finishTransaction: SurfaceControl.Transaction = mock(),
         homeChange: TransitionInfo.Change? = createHomeChange(),
-        transitionRootLeash: SurfaceControl? = null,
+        transitionRootLeash: SurfaceControl = mock(),
     ): IBinder {
         whenever(dragAnimator.position).thenReturn(PointF())
         // Simulate transition is started and is ready to animate.
@@ -887,7 +886,7 @@
         type: Int,
         draggedTask: RunningTaskInfo,
         homeChange: TransitionInfo.Change? = createHomeChange(),
-        rootLeash: SurfaceControl? = null,
+        rootLeash: SurfaceControl = mock(),
     ) =
         TransitionInfo(type, /* flags= */ 0).apply {
             homeChange?.let { addChange(it) }
@@ -904,9 +903,7 @@
                     flags = flags or FLAG_IS_WALLPAPER
                 }
             )
-            if (rootLeash != null) {
-                addRootLeash(DEFAULT_DISPLAY, rootLeash, /* offsetLeft= */ 0, /* offsetTop= */ 0)
-            }
+            addRootLeash(draggedTask.displayId, rootLeash, /* offsetLeft= */ 0, /* offsetTop= */ 0)
         }
 
     private fun createHomeChange() =
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
index 96b85ad..6b2f90f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
@@ -21,14 +21,17 @@
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_TO_FRONT
 import android.window.TransitionInfo
+import android.window.WindowContainerToken
 import android.window.WindowContainerTransaction
 import android.window.WindowContainerTransaction.Change
 import android.window.WindowContainerTransaction.HierarchyOp
+import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
 import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT
 import androidx.test.filters.SmallTest
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.common.LaunchAdjacentController
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
 import com.android.wm.shell.desktopmode.multidesks.RootTaskDesksOrganizer.DeskMinimizationRoot
 import com.android.wm.shell.desktopmode.multidesks.RootTaskDesksOrganizer.DeskRoot
@@ -58,13 +61,19 @@
     private val testShellInit = ShellInit(testExecutor)
     private val mockShellCommandHandler = mock<ShellCommandHandler>()
     private val mockShellTaskOrganizer = mock<ShellTaskOrganizer>()
+    private val launchAdjacentController = LaunchAdjacentController(mock())
 
     private lateinit var organizer: RootTaskDesksOrganizer
 
     @Before
     fun setUp() {
         organizer =
-            RootTaskDesksOrganizer(testShellInit, mockShellCommandHandler, mockShellTaskOrganizer)
+            RootTaskDesksOrganizer(
+                testShellInit,
+                mockShellCommandHandler,
+                mockShellTaskOrganizer,
+                launchAdjacentController,
+            )
     }
 
     @Test
@@ -473,14 +482,7 @@
 
         organizer.minimizeTask(wct, deskId = desk.deskRoot.deskId, task)
 
-        assertThat(
-                wct.hierarchyOps.any { hop ->
-                    hop.isReparent &&
-                        hop.container == task.token.asBinder() &&
-                        hop.newParent == desk.minimizationRoot.token.asBinder()
-                }
-            )
-            .isTrue()
+        assertThat(wct.hasMinimizationHops(desk, task.token)).isTrue()
     }
 
     @Test
@@ -508,14 +510,205 @@
         assertThat(wct.isEmpty).isTrue()
     }
 
+    @Test
+    fun unminimizeTask() {
+        val desk = createDesk()
+        val task = createFreeformTask().apply { parentTaskId = desk.deskRoot.deskId }
+        val wct = WindowContainerTransaction()
+        organizer.moveTaskToDesk(wct, desk.deskRoot.deskId, task)
+        organizer.onTaskAppeared(task, SurfaceControl())
+        organizer.minimizeTask(wct, deskId = desk.deskRoot.deskId, task)
+        task.parentTaskId = desk.minimizationRoot.rootId
+        organizer.onTaskInfoChanged(task)
+
+        wct.clear()
+        organizer.unminimizeTask(wct, deskId = desk.deskRoot.deskId, task)
+
+        assertThat(wct.hasUnminimizationHops(desk, task.token)).isTrue()
+    }
+
+    @Test
+    fun unminimizeTask_alreadyUnminimized_noOp() {
+        val desk = createDesk()
+        val task = createFreeformTask().apply { parentTaskId = desk.deskRoot.deskId }
+        val wct = WindowContainerTransaction()
+        organizer.moveTaskToDesk(wct, desk.deskRoot.deskId, task)
+        organizer.onTaskAppeared(task, SurfaceControl())
+
+        wct.clear()
+        organizer.unminimizeTask(wct, deskId = desk.deskRoot.deskId, task)
+
+        assertThat(wct.hasUnminimizationHops(desk, task.token)).isFalse()
+    }
+
+    @Test
+    fun unminimizeTask_notInDesk_noOp() {
+        val desk = createDesk()
+        val task = createFreeformTask()
+        val wct = WindowContainerTransaction()
+
+        organizer.unminimizeTask(wct, deskId = desk.deskRoot.deskId, task)
+
+        assertThat(wct.hasUnminimizationHops(desk, task.token)).isFalse()
+    }
+
+    @Test
+    fun reorderTaskToFront() {
+        val desk = createDesk()
+        val task = createFreeformTask().apply { parentTaskId = desk.deskRoot.deskId }
+        val wct = WindowContainerTransaction()
+        organizer.onTaskAppeared(task, SurfaceControl())
+
+        organizer.reorderTaskToFront(wct, desk.deskRoot.deskId, task)
+
+        assertThat(
+                wct.hierarchyOps.singleOrNull { hop ->
+                    hop.container == task.token.asBinder() &&
+                        hop.type == HIERARCHY_OP_TYPE_REORDER &&
+                        hop.toTop &&
+                        hop.includingParents()
+                }
+            )
+            .isNotNull()
+    }
+
+    @Test
+    fun reorderTaskToFront_notInDesk_noOp() {
+        val desk = createDesk()
+        val task = createFreeformTask()
+        val wct = WindowContainerTransaction()
+
+        organizer.reorderTaskToFront(wct, desk.deskRoot.deskId, task)
+
+        assertThat(
+                wct.hierarchyOps.singleOrNull { hop ->
+                    hop.container == task.token.asBinder() &&
+                        hop.type == HIERARCHY_OP_TYPE_REORDER &&
+                        hop.toTop &&
+                        hop.includingParents()
+                }
+            )
+            .isNull()
+    }
+
+    @Test
+    fun reorderTaskToFront_minimized_unminimizesAndReorders() {
+        val desk = createDesk()
+        val task = createFreeformTask().apply { parentTaskId = desk.deskRoot.deskId }
+        val wct = WindowContainerTransaction()
+        organizer.onTaskAppeared(task, SurfaceControl())
+        task.parentTaskId = desk.minimizationRoot.rootId
+        organizer.onTaskInfoChanged(task)
+
+        organizer.reorderTaskToFront(wct, desk.deskRoot.deskId, task)
+
+        assertThat(wct.hasUnminimizationHops(desk, task.token)).isTrue()
+        assertThat(
+                wct.hierarchyOps.singleOrNull { hop ->
+                    hop.container == task.token.asBinder() &&
+                        hop.type == HIERARCHY_OP_TYPE_REORDER &&
+                        hop.toTop &&
+                        hop.includingParents()
+                }
+            )
+            .isNotNull()
+    }
+
+    @Test
+    fun onTaskAppeared_visibleDesk_onlyDesk_disablesLaunchAdjacent() {
+        launchAdjacentController.launchAdjacentEnabled = true
+
+        createDesk(visible = true)
+
+        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
+    }
+
+    @Test
+    fun onTaskAppeared_invisibleDesk_onlyDesk_enablesLaunchAdjacent() {
+        launchAdjacentController.launchAdjacentEnabled = false
+
+        createDesk(visible = false)
+
+        assertThat(launchAdjacentController.launchAdjacentEnabled).isTrue()
+    }
+
+    @Test
+    fun onTaskAppeared_invisibleDesk_otherVisibleDesk_disablesLaunchAdjacent() {
+        launchAdjacentController.launchAdjacentEnabled = true
+
+        createDesk(visible = true)
+        createDesk(visible = false)
+
+        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
+    }
+
+    @Test
+    fun onTaskInfoChanged_deskBecomesVisible_onlyDesk_disablesLaunchAdjacent() {
+        launchAdjacentController.launchAdjacentEnabled = true
+
+        val desk = createDesk(visible = false)
+        desk.deskRoot.taskInfo.isVisible = true
+        organizer.onTaskInfoChanged(desk.deskRoot.taskInfo)
+
+        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
+    }
+
+    @Test
+    fun onTaskInfoChanged_deskBecomesInvisible_onlyDesk_enablesLaunchAdjacent() {
+        launchAdjacentController.launchAdjacentEnabled = false
+
+        val desk = createDesk(visible = true)
+        desk.deskRoot.taskInfo.isVisible = false
+        organizer.onTaskInfoChanged(desk.deskRoot.taskInfo)
+
+        assertThat(launchAdjacentController.launchAdjacentEnabled).isTrue()
+    }
+
+    @Test
+    fun onTaskInfoChanged_deskBecomesInvisible_otherVisibleDesk_disablesLaunchAdjacent() {
+        launchAdjacentController.launchAdjacentEnabled = true
+
+        createDesk(visible = true)
+        val desk = createDesk(visible = true)
+        desk.deskRoot.taskInfo.isVisible = false
+        organizer.onTaskInfoChanged(desk.deskRoot.taskInfo)
+
+        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
+    }
+
+    @Test
+    fun onTaskVanished_visibleDeskDisappears_onlyDesk_enablesLaunchAdjacent() {
+        launchAdjacentController.launchAdjacentEnabled = false
+
+        val desk = createDesk(visible = true)
+        organizer.onTaskVanished(desk.deskRoot.taskInfo)
+
+        assertThat(launchAdjacentController.launchAdjacentEnabled).isTrue()
+    }
+
+    @Test
+    fun onTaskVanished_visibleDeskDisappears_otherDeskVisible_disablesLaunchAdjacent() {
+        launchAdjacentController.launchAdjacentEnabled = true
+
+        createDesk(visible = true)
+        val desk = createDesk(visible = true)
+        organizer.onTaskVanished(desk.deskRoot.taskInfo)
+
+        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
+    }
+
     private data class DeskRoots(
         val deskRoot: DeskRoot,
         val minimizationRoot: DeskMinimizationRoot,
     )
 
-    private fun createDesk(): DeskRoots {
+    private fun createDesk(visible: Boolean = true): DeskRoots {
         organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
-        val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
+        val freeformRoot =
+            createFreeformTask().apply {
+                parentTaskId = -1
+                isVisible = visible
+            }
         organizer.onTaskAppeared(freeformRoot, SurfaceControl())
         val minimizationRoot = createFreeformTask().apply { parentTaskId = -1 }
         organizer.onTaskAppeared(minimizationRoot, SurfaceControl())
@@ -525,6 +718,27 @@
         )
     }
 
+    private fun WindowContainerTransaction.hasMinimizationHops(
+        desk: DeskRoots,
+        task: WindowContainerToken,
+    ): Boolean =
+        hierarchyOps.any { hop ->
+            hop.isReparent &&
+                hop.container == task.asBinder() &&
+                hop.newParent == desk.minimizationRoot.token.asBinder()
+        }
+
+    private fun WindowContainerTransaction.hasUnminimizationHops(
+        desk: DeskRoots,
+        task: WindowContainerToken,
+    ): Boolean =
+        hierarchyOps.any { hop ->
+            hop.isReparent &&
+                hop.container == task.asBinder() &&
+                hop.newParent == desk.deskRoot.token.asBinder() &&
+                hop.toTop
+        }
+
     private class FakeOnCreateCallback : DesksOrganizer.OnCreateCallback {
         var deskId: Int? = null
         val created: Boolean
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
index 9509aaf..52c5ad1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java
@@ -41,6 +41,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.window.flags.Flags;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestRunningTaskInfoBuilder;
@@ -198,6 +199,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
     public void visibilityTaskChanged_visible_setLaunchAdjacentDisabled() {
         ActivityManager.RunningTaskInfo task =
                 new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
@@ -209,6 +211,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
     public void visibilityTaskChanged_notVisible_setLaunchAdjacentEnabled() {
         ActivityManager.RunningTaskInfo task =
                 new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
index bc91845..714e5f4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
@@ -44,10 +44,12 @@
 import com.android.window.flags.Flags;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.desktopmode.DesktopImmersiveController;
+import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.TransitionInfoBuilder;
 import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.util.StubTransaction;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
 import org.junit.Before;
@@ -68,6 +70,7 @@
     @Mock private WindowDecorViewModel mWindowDecorViewModel;
     @Mock private TaskChangeListener mTaskChangeListener;
     @Mock private FocusTransitionObserver mFocusTransitionObserver;
+    @Mock private DesksTransitionObserver mDesksTransitionObserver;
 
     private FreeformTaskTransitionObserver mTransitionObserver;
 
@@ -88,7 +91,8 @@
                         Optional.of(mDesktopImmersiveController),
                         mWindowDecorViewModel,
                         Optional.of(mTaskChangeListener),
-                        mFocusTransitionObserver);
+                        mFocusTransitionObserver,
+                        Optional.of(mDesksTransitionObserver));
 
         final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
         verify(mShellInit).addInitCallback(initRunnableCaptor.capture(), same(mTransitionObserver));
@@ -357,6 +361,18 @@
         verify(mDesktopImmersiveController).onTransitionFinished(transition, /* aborted= */ false);
     }
 
+    @Test
+    public void onTransitionReady_forwardsToDesksTransitionObserver() {
+        final IBinder transition = mock(IBinder.class);
+        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, /* flags= */ 0)
+                .build();
+
+        mTransitionObserver.onTransitionReady(transition, info, new StubTransaction(),
+                new StubTransaction());
+
+        verify(mDesksTransitionObserver).onTransitionReady(transition, info);
+    }
+
     private static TransitionInfo.Change createChange(int mode, int taskId, int windowingMode) {
         final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
         taskInfo.taskId = taskId;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
index 333569a..5029371 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.mockito.kotlin.MatchersKt.eq;
 import static org.mockito.kotlin.VerificationKt.clearInvocations;
@@ -35,7 +36,9 @@
 import android.app.PendingIntent;
 import android.app.PictureInPictureParams;
 import android.app.RemoteAction;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
@@ -48,8 +51,10 @@
 
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
 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.pip2.animation.PipResizeAnimator;
 
 import org.junit.Before;
@@ -107,6 +112,16 @@
     }
 
     @Test
+    public void constructor_addOnPipComponentChangedListener() {
+        mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
+                mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState,
+                mMockPipBoundsAlgorithm, mMockShellExecutor);
+
+        verify(mMockPipBoundsState).addOnPipComponentChangedListener(
+                any(PipBoundsState.OnPipComponentChangedListener.class));
+    }
+
+    @Test
     public void setPictureInPictureParams_updatePictureInPictureParams() {
         mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
                 mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState,
@@ -359,6 +374,26 @@
         verify(mMockPipResizeAnimator, times(0)).start();
     }
 
+    @Test
+    public void onPipComponentChanged_clearPictureInPictureParams() {
+        when(mMockContext.getResources()).thenReturn(mock(Resources.class));
+        PipBoundsState pipBoundsState = new PipBoundsState(mMockContext,
+                mock(PhoneSizeSpecSource.class), mock(PipDisplayLayoutState.class));
+        pipBoundsState.setLastPipComponentName(new ComponentName("org.test", "test1"));
+
+        mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
+                mMockPipTransitionState, mMockPipScheduler, pipBoundsState,
+                mMockPipBoundsAlgorithm, mMockShellExecutor);
+        Rational aspectRatio = new Rational(4, 3);
+        String action1 = "action1";
+        mPipTaskListener.setPictureInPictureParams(getPictureInPictureParams(
+                aspectRatio, action1));
+
+        pipBoundsState.setLastPipComponentName(new ComponentName("org.test", "test2"));
+
+        assertTrue(mPipTaskListener.getPictureInPictureParams().empty());
+    }
+
     private PictureInPictureParams getPictureInPictureParams(Rational aspectRatio,
             String... actions) {
         final PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryTest.kt
index fd22a84..2b39262 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryTest.kt
@@ -53,7 +53,8 @@
         tabletPortrait.copy(windowBounds = Rect(0, 0, 800, 900), isSmallTablet = true)
     private val foldableLandscape =
         foldablePortrait.copy(windowBounds = Rect(0, 0, 900, 800), isLandscape = true)
-    private val splitScreenModeChecker = SplitScreenModeChecker { SplitScreenMode.NONE }
+    private var splitScreenMode = SplitScreenMode.NONE
+    private val splitScreenModeChecker = SplitScreenModeChecker { splitScreenMode }
     private var isDesktopWindowModeSupported = true
     private val desktopWindowModeChecker = DesktopWindowModeChecker { isDesktopWindowModeSupported }
 
@@ -283,7 +284,7 @@
     }
 
     @Test
-    fun dragZonesForBubble_tablet_desktopModeDisabled() {
+    fun dragZonesForBubble_desktopModeDisabled() {
         isDesktopWindowModeSupported = false
         dragZoneFactory =
             DragZoneFactory(
@@ -298,7 +299,7 @@
     }
 
     @Test
-    fun dragZonesForExpandedView_tablet_desktopModeDisabled() {
+    fun dragZonesForExpandedView_desktopModeDisabled() {
         isDesktopWindowModeSupported = false
         dragZoneFactory =
             DragZoneFactory(
@@ -314,6 +315,38 @@
         assertThat(dragZones.filterIsInstance<DragZone.DesktopWindow>()).isEmpty()
     }
 
+    @Test
+    fun dragZonesForBubble_splitScreenModeUnsupported() {
+        splitScreenMode = SplitScreenMode.UNSUPPORTED
+        dragZoneFactory =
+            DragZoneFactory(
+                context,
+                foldableLandscape,
+                splitScreenModeChecker,
+                desktopWindowModeChecker
+            )
+        val dragZones =
+            dragZoneFactory.createSortedDragZones(DraggedObject.Bubble(BubbleBarLocation.LEFT))
+        assertThat(dragZones.filterIsInstance<DragZone.Split>()).isEmpty()
+    }
+
+    @Test
+    fun dragZonesForExpandedView_splitScreenModeUnsupported() {
+        splitScreenMode = SplitScreenMode.UNSUPPORTED
+        dragZoneFactory =
+            DragZoneFactory(
+                context,
+                foldableLandscape,
+                splitScreenModeChecker,
+                desktopWindowModeChecker
+            )
+        val dragZones =
+            dragZoneFactory.createSortedDragZones(
+                DraggedObject.ExpandedView(BubbleBarLocation.LEFT)
+            )
+        assertThat(dragZones.filterIsInstance<DragZone.Split>()).isEmpty()
+    }
+
     private inline fun <reified T> verifyInstance(): DragZoneVerifier = { dragZone ->
         assertThat(dragZone).isInstanceOf(T::class.java)
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
index fb62ba7..edf91fe 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
@@ -234,14 +234,25 @@
         assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
     }
 
+    @DisableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
     @Test
     fun isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsFalse() {
         doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
-        doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
+        doReturn(false).whenever(mockResources)
+            .getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
 
         assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
     }
 
+    @EnableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
+    @Test
+    fun isPDDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsTrue() {
+        doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
+        doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
+
+        assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue()
+    }
+
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
index 257bbb5..b07b6c1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
@@ -22,6 +22,7 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.SurfaceControl
+import android.window.TaskSnapshot
 import androidx.test.filters.SmallTest
 import com.android.window.flags.Flags
 import com.android.wm.shell.MockToken
@@ -33,6 +34,7 @@
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
+import org.junit.Assert.fail
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -84,7 +86,29 @@
         assertThat(menu.menuViewContainer).isInstanceOf(AdditionalSystemViewContainer::class.java)
     }
 
-    private fun createMenu(task: RunningTaskInfo) = DesktopHeaderManageWindowsMenu(
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun testShow_nullSnapshotDoesNotCauseNPE() {
+        val task = createFreeformTask()
+        val snapshotList = listOf(Pair(/* index = */ 1, /* snapshot = */ null))
+        // Set as immersive so that menu is created as system view container (simpler of the
+        // options)
+        userRepositories.getProfile(DEFAULT_USER_ID).setTaskInFullImmersiveState(
+            displayId = task.displayId,
+            taskId = task.taskId,
+            immersive = true
+        )
+        try {
+            menu = createMenu(task, snapshotList)
+        } catch (e: NullPointerException) {
+            fail("Null snapshot should not have thrown null pointer exception")
+        }
+    }
+
+    private fun createMenu(
+        task: RunningTaskInfo,
+        snapshotList: List<Pair<Int, TaskSnapshot?>> = emptyList()
+    ) = DesktopHeaderManageWindowsMenu(
         callerTaskInfo = task,
         x = 0,
         y = 0,
@@ -94,7 +118,7 @@
         desktopUserRepositories = userRepositories,
         surfaceControlBuilderSupplier = { SurfaceControl.Builder() },
         surfaceControlTransactionSupplier = { SurfaceControl.Transaction() },
-        snapshotList = emptyList(),
+        snapshotList = snapshotList,
         onIconClickListener = {},
         onOutsideClickListener = {},
     )
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index e89a122..d69509f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -115,7 +115,8 @@
                 .spyStatic(DragPositioningCallbackUtility::class.java)
                 .startMocking()
 
-        doReturn(true).`when` { DesktopModeStatus.canInternalDisplayHostDesktops(Mockito.any()) }
+        doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupportedOnDisplay(Mockito.any(),
+            Mockito.any()) }
         doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(Mockito.any()) }
         doReturn(false).`when` { DesktopModeStatus.overridesShowAppHandle(Mockito.any()) }
 
@@ -394,7 +395,7 @@
         whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true)
 
         val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)
-        doReturn(true).`when` { DesktopModeStatus.canInternalDisplayHostDesktops(any()) }
+        doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupportedOnDisplay(any(), any()) }
         setUpMockDecorationsForTasks(task)
 
         onTaskOpening(task)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
index 81dfaed..a1f40fd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -79,6 +79,7 @@
 import com.android.wm.shell.util.StubTransaction
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper
 import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost
 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier
@@ -174,6 +175,7 @@
     internal lateinit var desktopModeOnKeyguardChangedListener: DesktopModeKeyguardChangeListener
     protected lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel
     protected lateinit var desktopModeCompatPolicy: DesktopModeCompatPolicy
+    protected lateinit var appHandleAndHeaderVisibilityHelper: AppHandleAndHeaderVisibilityHelper
 
     fun setUpCommon() {
         spyContext = spy(mContext)
@@ -185,9 +187,13 @@
         whenever(mockDesktopUserRepositories.current).thenReturn(mockDesktopRepository)
         whenever(mockDisplayController.getDisplayContext(any())).thenReturn(spyContext)
         whenever(mockDisplayController.getDisplay(any())).thenReturn(display)
+        whenever(display.type).thenReturn(Display.TYPE_INTERNAL)
         whenever(mockDesktopUserRepositories.getProfile(anyInt()))
             .thenReturn(mockDesktopRepository)
         desktopModeCompatPolicy = DesktopModeCompatPolicy(spyContext)
+        appHandleAndHeaderVisibilityHelper =
+            AppHandleAndHeaderVisibilityHelper(spyContext, mockDisplayController,
+                desktopModeCompatPolicy)
         desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel(
             spyContext,
             testShellExecutor,
@@ -222,6 +228,7 @@
             Optional.of(mockTasksLimiter),
             mockAppHandleEducationController,
             mockAppToWebEducationController,
+            appHandleAndHeaderVisibilityHelper,
             mockCaptionHandleRepository,
             Optional.of(mockActivityOrientationChangeHandler),
             mockTaskPositionerFactory,
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 c4f70ac2..1371b38 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
@@ -167,6 +167,7 @@
     private static final boolean DEFAULT_IS_STATUSBAR_VISIBLE = true;
     private static final boolean DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED = false;
     private static final boolean DEFAULT_IS_IN_FULL_IMMERSIVE_MODE = false;
+    private static final boolean DEFAULT_IS_DRAGGING = false;
     private static final boolean DEFAULT_HAS_GLOBAL_FOCUS = true;
     private static final boolean DEFAULT_SHOULD_IGNORE_CORNER_RADIUS = false;
     private static final boolean DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS = false;
@@ -415,6 +416,7 @@
                 DEFAULT_IS_STATUSBAR_VISIBLE,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -616,6 +618,7 @@
                 DEFAULT_IS_STATUSBAR_VISIBLE,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -650,6 +653,7 @@
                 DEFAULT_IS_STATUSBAR_VISIBLE,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -728,6 +732,7 @@
                 DEFAULT_IS_STATUSBAR_VISIBLE,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 /* inFullImmersiveMode */ true,
+                DEFAULT_IS_DRAGGING,
                 insetsState,
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -755,6 +760,7 @@
                 DEFAULT_IS_STATUSBAR_VISIBLE,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 /* inFullImmersiveMode */ true,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -781,6 +787,7 @@
                 /* isStatusBarVisible */ false,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -807,6 +814,7 @@
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
                 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -832,6 +840,7 @@
                 /* isStatusBarVisible */ false,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -857,6 +866,7 @@
                 DEFAULT_IS_STATUSBAR_VISIBLE,
                 /* isKeyguardVisibleAndOccluded */ true,
                 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -883,6 +893,7 @@
                 /* isStatusBarVisible */ true,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 /* inFullImmersiveMode */ true,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -901,6 +912,7 @@
                 /* isStatusBarVisible */ false,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 /* inFullImmersiveMode */ true,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -911,6 +923,33 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX)
+    public void updateRelayoutParams_header_fullyImmersive_captionVisDuringDrag() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        final RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                mMockSplitScreenController,
+                DEFAULT_APPLY_START_TRANSACTION_ON_DRAW,
+                DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP,
+                /* isStatusBarVisible */ false,
+                DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
+                /* inFullImmersiveMode */ true,
+                /* isDragging */ true,
+                new InsetsState(),
+                DEFAULT_HAS_GLOBAL_FOCUS,
+                mExclusionRegion,
+                DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
+                DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
+
+        assertThat(relayoutParams.mIsCaptionVisible).isTrue();
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
     public void updateRelayoutParams_header_fullyImmersive_overKeyguard_captionNotVisible() {
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
@@ -927,6 +966,7 @@
                 DEFAULT_IS_STATUSBAR_VISIBLE,
                 /* isKeyguardVisibleAndOccluded */ true,
                 /* inFullImmersiveMode */ true,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
@@ -1588,6 +1628,7 @@
                 DEFAULT_IS_STATUSBAR_VISIBLE,
                 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
                 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
+                DEFAULT_IS_DRAGGING,
                 new InsetsState(),
                 DEFAULT_HAS_GLOBAL_FOCUS,
                 mExclusionRegion,
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 30594dc..0d45149 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1265,6 +1265,9 @@
     // Varies in length from 3 to 8 chars. Zero-filled value.
     char localeNumberingSystem[8];
 
+    // Mark all padding explicitly so it's clear how much we can expand it.
+    char endPadding[3];
+
     void copyFromDeviceNoSwap(const ResTable_config& o) {
       const auto o_size = dtohl(o.size);
       if (o_size >= sizeof(ResTable_config)) [[likely]] {
@@ -1422,6 +1425,13 @@
     void swapHtoD_slow();
 };
 
+// Fix the struct size for backward compatibility
+static_assert(sizeof(ResTable_config) == 64);
+
+// Make sure there's no unaccounted padding in the structure.
+static_assert(offsetof(ResTable_config, endPadding) +
+                  sizeof(ResTable_config::endPadding) == sizeof(ResTable_config));
+
 /**
  * A specification of the resources defined by a particular type.
  *
diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp
index a210ddf..7d227f7 100644
--- a/libs/hwui/jni/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -722,10 +722,15 @@
 
             auto canvas = SkCanvas(recycledPixels->getSkBitmap());
             SkRect destination = SkRect::Make(recycledPixels->info().bounds());
-            destination.intersect(SkRect::Make(mSkiaBitmap->info().bounds()));
-            canvas.drawImageRect(mSkiaBitmap->asImage(), *mDesiredSubset, destination,
-                                 SkSamplingOptions(SkFilterMode::kLinear), nullptr,
-                                 SkCanvas::kFast_SrcRectConstraint);
+            if (destination.intersect(SkRect::Make(mSkiaBitmap->info().bounds()))) {
+                canvas.drawImageRect(mSkiaBitmap->asImage(), *mDesiredSubset, destination,
+                                     SkSamplingOptions(SkFilterMode::kLinear), nullptr,
+                                     SkCanvas::kFast_SrcRectConstraint);
+            } else {
+                // The canvas would have discarded the draw operation automatically, but
+                // this case should have been detected before getting to this point.
+                ALOGE("Copy destination does not intersect image bounds");
+            }
         } else {
             void* dst = recycledPixels->pixels();
             const size_t dstRowBytes = mRecycledBitmap->rowBytes();
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index 83b1778..f8eb418 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -179,3 +179,10 @@
     }
 }
 
+flag {
+    name: "gnss_location_provider_overlay_2025_devices"
+    namespace: "location"
+    description: "Flag for GNSS location provider overlay for 2025 devices"
+    bug: "398254728"
+    is_fixed_read_only: true
+}
diff --git a/media/java/Android.bp b/media/java/Android.bp
index 6878f9d..28b9d3b 100644
--- a/media/java/Android.bp
+++ b/media/java/Android.bp
@@ -15,6 +15,7 @@
     ],
     exclude_srcs: [
         ":framework-media-tv-tunerresourcemanager-sources-aidl",
+        ":framework-media-quality-sources-aidl",
     ],
     visibility: [
         "//frameworks/base",
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d082c73..32af7c6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4857,7 +4857,7 @@
             focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId);
         }
 
-        return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver);
+        return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver, afr);
     }
 
     /**
@@ -5070,7 +5070,7 @@
             focusReceiver = addClientIdToFocusReceiverLocked(clientId);
         }
 
-        return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver);
+        return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver, afr);
     }
 
     @GuardedBy("mFocusRequestsLock")
@@ -5086,11 +5086,20 @@
     }
 
     private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId,
-            BlockingFocusResultReceiver focusReceiver) {
+            BlockingFocusResultReceiver focusReceiver, @NonNull AudioFocusRequest afr) {
         focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
-        if (DEBUG && !focusReceiver.receivedResult()) {
-            Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded"
-                    + " response from ext policy timed out, denying request");
+        if (!focusReceiver.receivedResult()) {
+            if (DEBUG) {
+                Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded"
+                        + " response from ext policy timed out, denying request");
+            }
+            try {
+                // To prevent from orphan focus holder, cleanup
+                abandonAudioFocus(afr.getOnAudioFocusChangeListener());
+            } catch (Exception e) {
+                Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded failed to abandon audio"
+                        +" focus after time out, error: " + e.getMessage());
+            }
         }
 
         synchronized (mFocusRequestsLock) {
diff --git a/media/java/android/media/quality/Android.bp b/media/java/android/media/quality/Android.bp
new file mode 100644
index 0000000..080d526
--- /dev/null
+++ b/media/java/android/media/quality/Android.bp
@@ -0,0 +1,39 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-media-quality-sources-aidl",
+    srcs: [
+        "aidl/android/media/quality/*.aidl",
+    ],
+    path: "aidl",
+}
+
+aidl_interface {
+    name: "media_quality_aidl_interface",
+    unstable: true,
+    local_include_dir: "aidl",
+    backend: {
+        java: {
+            enabled: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+        ndk: {
+            enabled: false,
+        },
+        rust: {
+            enabled: false,
+        },
+    },
+    srcs: [
+        ":framework-media-quality-sources-aidl",
+    ],
+}
diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl
deleted file mode 100644
index 6e9fa1d..0000000
--- a/media/java/android/media/quality/IMediaQualityManager.aidl
+++ /dev/null
@@ -1,81 +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.media.quality;
-
-import android.media.quality.AmbientBacklightSettings;
-import android.media.quality.IAmbientBacklightCallback;
-import android.media.quality.IPictureProfileCallback;
-import android.media.quality.ISoundProfileCallback;
-import android.media.quality.ParameterCapability;
-import android.media.quality.PictureProfileHandle;
-import android.media.quality.PictureProfile;
-import android.media.quality.SoundProfileHandle;
-import android.media.quality.SoundProfile;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-/**
- * Interface for Media Quality Manager
- * @hide
- */
-interface IMediaQualityManager {
-    PictureProfile createPictureProfile(in PictureProfile pp, in UserHandle user);
-    void updatePictureProfile(in String id, in PictureProfile pp, in UserHandle user);
-    void removePictureProfile(in String id, in UserHandle user);
-    boolean setDefaultPictureProfile(in String id, in UserHandle user);
-    PictureProfile getPictureProfile(
-            in int type, in String name, in Bundle options, in UserHandle user);
-    List<PictureProfile> getPictureProfilesByPackage(
-            in String packageName, in Bundle options, in UserHandle user);
-    List<PictureProfile> getAvailablePictureProfiles(in Bundle options, in UserHandle user);
-    List<String> getPictureProfilePackageNames(in UserHandle user);
-    List<String> getPictureProfileAllowList(in UserHandle user);
-    void setPictureProfileAllowList(in List<String> packages, in UserHandle user);
-    List<PictureProfileHandle> getPictureProfileHandle(in String[] id, in UserHandle user);
-
-    SoundProfile createSoundProfile(in SoundProfile pp, in UserHandle user);
-    void updateSoundProfile(in String id, in SoundProfile pp, in UserHandle user);
-    void removeSoundProfile(in String id, in UserHandle user);
-    boolean setDefaultSoundProfile(in String id, in UserHandle user);
-    SoundProfile getSoundProfile(
-            in int type, in String name, in Bundle options, in UserHandle user);
-    List<SoundProfile> getSoundProfilesByPackage(
-            in String packageName, in Bundle options, in UserHandle user);
-    List<SoundProfile> getAvailableSoundProfiles(in Bundle options, in UserHandle user);
-    List<String> getSoundProfilePackageNames(in UserHandle user);
-    List<String> getSoundProfileAllowList(in UserHandle user);
-    void setSoundProfileAllowList(in List<String> packages, in UserHandle user);
-    List<SoundProfileHandle> getSoundProfileHandle(in String[] id, in UserHandle user);
-
-    void registerPictureProfileCallback(in IPictureProfileCallback cb);
-    void registerSoundProfileCallback(in ISoundProfileCallback cb);
-    void registerAmbientBacklightCallback(in IAmbientBacklightCallback cb);
-
-    List<ParameterCapability> getParameterCapabilities(in List<String> names, in UserHandle user);
-
-    boolean isSupported(in UserHandle user);
-    void setAutoPictureQualityEnabled(in boolean enabled, in UserHandle user);
-    boolean isAutoPictureQualityEnabled(in UserHandle user);
-    void setSuperResolutionEnabled(in boolean enabled, in UserHandle user);
-    boolean isSuperResolutionEnabled(in UserHandle user);
-    void setAutoSoundQualityEnabled(in boolean enabled, in UserHandle user);
-    boolean isAutoSoundQualityEnabled(in UserHandle user);
-
-    void setAmbientBacklightSettings(in AmbientBacklightSettings settings, in UserHandle user);
-    void setAmbientBacklightEnabled(in boolean enabled, in UserHandle user);
-    boolean isAmbientBacklightEnabled(in UserHandle user);
-}
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 0d6d32a..bfd0138 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -274,9 +274,9 @@
             @NonNull String name,
             @Nullable ProfileQueryParams options) {
         try {
-            Bundle optionsBundle = options == null
-                    ? ProfileQueryParams.DEFAULT.toBundle() : options.toBundle();
-            return mService.getPictureProfile(type, name, optionsBundle, mUserHandle);
+            boolean includeParams = options == null || options.mParametersIncluded;
+            return mService.getPictureProfile(
+                    type, name, includeParams, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -299,10 +299,9 @@
     public List<PictureProfile> getPictureProfilesByPackage(
             @NonNull String packageName, @Nullable ProfileQueryParams options) {
         try {
-            Bundle optionsBundle = options == null
-                    ? ProfileQueryParams.DEFAULT.toBundle() : options.toBundle();
+            boolean includeParams = options == null || options.mParametersIncluded;
             return mService.getPictureProfilesByPackage(
-                    packageName, optionsBundle, mUserHandle);
+                    packageName, includeParams, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -321,9 +320,8 @@
     @NonNull
     public List<PictureProfile> getAvailablePictureProfiles(@Nullable ProfileQueryParams options) {
         try {
-            Bundle optionsBundle = options == null
-                    ? ProfileQueryParams.DEFAULT.toBundle() : options.toBundle();
-            return mService.getAvailablePictureProfiles(optionsBundle, mUserHandle);
+            boolean includeParams = options == null || options.mParametersIncluded;
+            return mService.getAvailablePictureProfiles(includeParams, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -344,7 +342,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public boolean setDefaultPictureProfile(@Nullable String pictureProfileId) {
         try {
-            return mService.setDefaultPictureProfile(pictureProfileId, mUserHandle);
+            return mService.setDefaultPictureProfile(pictureProfileId, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -361,7 +359,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public List<String> getPictureProfilePackageNames() {
         try {
-            return mService.getPictureProfilePackageNames(mUserHandle);
+            return mService.getPictureProfilePackageNames(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -373,7 +371,7 @@
      */
     public List<PictureProfileHandle> getPictureProfileHandle(String[] id) {
         try {
-            return mService.getPictureProfileHandle(id, mUserHandle);
+            return mService.getPictureProfileHandle(id, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -385,7 +383,7 @@
      */
     public List<SoundProfileHandle> getSoundProfileHandle(String[] id) {
         try {
-            return mService.getSoundProfileHandle(id, mUserHandle);
+            return mService.getSoundProfileHandle(id, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -401,7 +399,7 @@
      */
     public void createPictureProfile(@NonNull PictureProfile pp) {
         try {
-            mService.createPictureProfile(pp, mUserHandle);
+            mService.createPictureProfile(pp, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -416,7 +414,7 @@
      */
     public void updatePictureProfile(@NonNull String profileId, @NonNull PictureProfile pp) {
         try {
-            mService.updatePictureProfile(profileId, pp, mUserHandle);
+            mService.updatePictureProfile(profileId, pp, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -430,7 +428,7 @@
      */
     public void removePictureProfile(@NonNull String profileId) {
         try {
-            mService.removePictureProfile(profileId, mUserHandle);
+            mService.removePictureProfile(profileId, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -484,9 +482,8 @@
             @NonNull String name,
             @Nullable ProfileQueryParams options) {
         try {
-            Bundle optionsBundle = options == null
-                    ? ProfileQueryParams.DEFAULT.toBundle() : options.toBundle();
-            return mService.getSoundProfile(type, name, optionsBundle, mUserHandle);
+            boolean includeParams = options == null || options.mParametersIncluded;
+            return mService.getSoundProfile(type, name, includeParams, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -510,9 +507,9 @@
     public List<SoundProfile> getSoundProfilesByPackage(
             @NonNull String packageName, @Nullable ProfileQueryParams options) {
         try {
-            Bundle optionsBundle = options == null
-                    ? ProfileQueryParams.DEFAULT.toBundle() : options.toBundle();
-            return mService.getSoundProfilesByPackage(packageName, optionsBundle, mUserHandle);
+            boolean includeParams = options == null || options.mParametersIncluded;
+            return mService.getSoundProfilesByPackage(
+                    packageName, includeParams, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -531,9 +528,8 @@
     @NonNull
     public List<SoundProfile> getAvailableSoundProfiles(@Nullable ProfileQueryParams options) {
         try {
-            Bundle optionsBundle = options == null
-                    ? ProfileQueryParams.DEFAULT.toBundle() : options.toBundle();
-            return mService.getAvailableSoundProfiles(optionsBundle, mUserHandle);
+            boolean includeParams = options == null || options.mParametersIncluded;
+            return mService.getAvailableSoundProfiles(includeParams, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -554,7 +550,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public boolean setDefaultSoundProfile(@Nullable String soundProfileId) {
         try {
-            return mService.setDefaultSoundProfile(soundProfileId, mUserHandle);
+            return mService.setDefaultSoundProfile(soundProfileId, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -572,7 +568,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public List<String> getSoundProfilePackageNames() {
         try {
-            return mService.getSoundProfilePackageNames(mUserHandle);
+            return mService.getSoundProfilePackageNames(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -589,7 +585,7 @@
      */
     public void createSoundProfile(@NonNull SoundProfile sp) {
         try {
-            mService.createSoundProfile(sp, mUserHandle);
+            mService.createSoundProfile(sp, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -604,7 +600,7 @@
      */
     public void updateSoundProfile(@NonNull String profileId, @NonNull SoundProfile sp) {
         try {
-            mService.updateSoundProfile(profileId, sp, mUserHandle);
+            mService.updateSoundProfile(profileId, sp, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -618,7 +614,7 @@
      */
     public void removeSoundProfile(@NonNull String profileId) {
         try {
-            mService.removeSoundProfile(profileId, mUserHandle);
+            mService.removeSoundProfile(profileId, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -636,7 +632,7 @@
     @NonNull
     public List<ParameterCapability> getParameterCapabilities(@NonNull List<String> names) {
         try {
-            return mService.getParameterCapabilities(names, mUserHandle);
+            return mService.getParameterCapabilities(names, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -654,7 +650,7 @@
     @NonNull
     public List<String> getPictureProfileAllowList() {
         try {
-            return mService.getPictureProfileAllowList(mUserHandle);
+            return mService.getPictureProfileAllowList(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -668,7 +664,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setPictureProfileAllowList(@NonNull List<String> packageNames) {
         try {
-            mService.setPictureProfileAllowList(packageNames, mUserHandle);
+            mService.setPictureProfileAllowList(packageNames, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -686,7 +682,7 @@
     @NonNull
     public List<String> getSoundProfileAllowList() {
         try {
-            return mService.getSoundProfileAllowList(mUserHandle);
+            return mService.getSoundProfileAllowList(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -700,7 +696,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public void setSoundProfileAllowList(@NonNull List<String> packageNames) {
         try {
-            mService.setSoundProfileAllowList(packageNames, mUserHandle);
+            mService.setSoundProfileAllowList(packageNames, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -712,7 +708,7 @@
      */
     public boolean isSupported() {
         try {
-            return mService.isSupported(mUserHandle);
+            return mService.isSupported(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -730,7 +726,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setAutoPictureQualityEnabled(boolean enabled) {
         try {
-            mService.setAutoPictureQualityEnabled(enabled, mUserHandle);
+            mService.setAutoPictureQualityEnabled(enabled, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -741,7 +737,7 @@
      */
     public boolean isAutoPictureQualityEnabled() {
         try {
-            return mService.isAutoPictureQualityEnabled(mUserHandle);
+            return mService.isAutoPictureQualityEnabled(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -758,7 +754,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setSuperResolutionEnabled(boolean enabled) {
         try {
-            mService.setSuperResolutionEnabled(enabled, mUserHandle);
+            mService.setSuperResolutionEnabled(enabled, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -769,7 +765,7 @@
      */
     public boolean isSuperResolutionEnabled() {
         try {
-            return mService.isSuperResolutionEnabled(mUserHandle);
+            return mService.isSuperResolutionEnabled(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -787,7 +783,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public void setAutoSoundQualityEnabled(boolean enabled) {
         try {
-            mService.setAutoSoundQualityEnabled(enabled, mUserHandle);
+            mService.setAutoSoundQualityEnabled(enabled, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -798,7 +794,7 @@
      */
     public boolean isAutoSoundQualityEnabled() {
         try {
-            return mService.isAutoSoundQualityEnabled(mUserHandle);
+            return mService.isAutoSoundQualityEnabled(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -847,7 +843,7 @@
             @NonNull AmbientBacklightSettings settings) {
         Preconditions.checkNotNull(settings);
         try {
-            mService.setAmbientBacklightSettings(settings, mUserHandle);
+            mService.setAmbientBacklightSettings(settings, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -858,7 +854,7 @@
      */
     public boolean isAmbientBacklightEnabled() {
         try {
-            return mService.isAmbientBacklightEnabled(mUserHandle);
+            return mService.isAmbientBacklightEnabled(mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -872,7 +868,7 @@
     @RequiresPermission(android.Manifest.permission.READ_COLOR_ZONES)
     public void setAmbientBacklightEnabled(boolean enabled) {
         try {
-            mService.setAmbientBacklightEnabled(enabled, mUserHandle);
+            mService.setAmbientBacklightEnabled(enabled, mUserHandle.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/media/java/android/media/quality/SoundProfileHandle.java b/media/java/android/media/quality/SoundProfileHandle.java
deleted file mode 100644
index edb546e..0000000
--- a/media/java/android/media/quality/SoundProfileHandle.java
+++ /dev/null
@@ -1,72 +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.media.quality;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
-  * A type-safe handle to a sound profile.
-  *
-  * @hide
-  */
-public final class SoundProfileHandle implements Parcelable {
-    public static final @NonNull SoundProfileHandle NONE = new SoundProfileHandle(-1000);
-
-    private final long mId;
-
-    /** @hide */
-    public SoundProfileHandle(long id) {
-        mId = id;
-    }
-
-    /** @hide */
-    public long getId() {
-        return mId;
-    }
-
-    /** @hide */
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeLong(mId);
-    }
-
-    /** @hide */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** @hide */
-    public static final @NonNull Creator<SoundProfileHandle> CREATOR =
-            new Creator<SoundProfileHandle>() {
-                @Override
-                public SoundProfileHandle createFromParcel(Parcel in) {
-                    return new SoundProfileHandle(in);
-                }
-
-                @Override
-                public SoundProfileHandle[] newArray(int size) {
-                    return new SoundProfileHandle[size];
-                }
-            };
-
-    private SoundProfileHandle(@NonNull Parcel in) {
-        mId = in.readLong();
-    }
-}
diff --git a/media/java/android/media/quality/ActiveProcessingPicture.aidl b/media/java/android/media/quality/aidl/android/media/quality/ActiveProcessingPicture.aidl
similarity index 100%
rename from media/java/android/media/quality/ActiveProcessingPicture.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/ActiveProcessingPicture.aidl
diff --git a/media/java/android/media/quality/AmbientBacklightEvent.aidl b/media/java/android/media/quality/aidl/android/media/quality/AmbientBacklightEvent.aidl
similarity index 100%
rename from media/java/android/media/quality/AmbientBacklightEvent.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/AmbientBacklightEvent.aidl
diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.aidl b/media/java/android/media/quality/aidl/android/media/quality/AmbientBacklightMetadata.aidl
similarity index 100%
rename from media/java/android/media/quality/AmbientBacklightMetadata.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/AmbientBacklightMetadata.aidl
diff --git a/media/java/android/media/quality/AmbientBacklightSettings.aidl b/media/java/android/media/quality/aidl/android/media/quality/AmbientBacklightSettings.aidl
similarity index 100%
rename from media/java/android/media/quality/AmbientBacklightSettings.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/AmbientBacklightSettings.aidl
diff --git a/media/java/android/media/quality/IAmbientBacklightCallback.aidl b/media/java/android/media/quality/aidl/android/media/quality/IAmbientBacklightCallback.aidl
similarity index 100%
rename from media/java/android/media/quality/IAmbientBacklightCallback.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/IAmbientBacklightCallback.aidl
diff --git a/media/java/android/media/quality/aidl/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/aidl/android/media/quality/IMediaQualityManager.aidl
new file mode 100644
index 0000000..0191ea7
--- /dev/null
+++ b/media/java/android/media/quality/aidl/android/media/quality/IMediaQualityManager.aidl
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.quality;
+
+import android.media.quality.AmbientBacklightSettings;
+import android.media.quality.IAmbientBacklightCallback;
+import android.media.quality.IPictureProfileCallback;
+import android.media.quality.ISoundProfileCallback;
+import android.media.quality.ParameterCapability;
+import android.media.quality.PictureProfileHandle;
+import android.media.quality.PictureProfile;
+import android.media.quality.SoundProfileHandle;
+import android.media.quality.SoundProfile;
+
+/**
+ * Interface for Media Quality Manager
+ * @hide
+ */
+interface IMediaQualityManager {
+    // TODO: use UserHandle
+    PictureProfile createPictureProfile(in PictureProfile pp, int userId);
+    void updatePictureProfile(in String id, in PictureProfile pp, int userId);
+    void removePictureProfile(in String id, int userId);
+    boolean setDefaultPictureProfile(in String id, int userId);
+    // TODO: use Bundle for includeParams
+    PictureProfile getPictureProfile(
+            in int type, in String name, in boolean includeParams, int userId);
+    List<PictureProfile> getPictureProfilesByPackage(
+            in String packageName, in boolean includeParams, int userId);
+    List<PictureProfile> getAvailablePictureProfiles(in boolean includeParams, int userId);
+    List<String> getPictureProfilePackageNames(int userId);
+    List<String> getPictureProfileAllowList(int userId);
+    void setPictureProfileAllowList(in List<String> packages, int userId);
+    List<PictureProfileHandle> getPictureProfileHandle(in String[] id, int userId);
+
+    SoundProfile createSoundProfile(in SoundProfile pp, int userId);
+    void updateSoundProfile(in String id, in SoundProfile pp, int userId);
+    void removeSoundProfile(in String id, int userId);
+    boolean setDefaultSoundProfile(in String id, int userId);
+    SoundProfile getSoundProfile(
+            in int type, in String name, in boolean includeParams, int userId);
+    List<SoundProfile> getSoundProfilesByPackage(
+            in String packageName, in boolean includeParams, int userId);
+    List<SoundProfile> getAvailableSoundProfiles(in boolean includeParams, int userId);
+    List<String> getSoundProfilePackageNames(int userId);
+    List<String> getSoundProfileAllowList(int userId);
+    void setSoundProfileAllowList(in List<String> packages, int userId);
+    List<SoundProfileHandle> getSoundProfileHandle(in String[] id, int userId);
+
+    void registerPictureProfileCallback(in IPictureProfileCallback cb);
+    void registerSoundProfileCallback(in ISoundProfileCallback cb);
+    void registerAmbientBacklightCallback(in IAmbientBacklightCallback cb);
+
+    List<ParameterCapability> getParameterCapabilities(in List<String> names, int userId);
+
+    boolean isSupported(int userId);
+    void setAutoPictureQualityEnabled(in boolean enabled, int userId);
+    boolean isAutoPictureQualityEnabled(int userId);
+    void setSuperResolutionEnabled(in boolean enabled, int userId);
+    boolean isSuperResolutionEnabled(int userId);
+    void setAutoSoundQualityEnabled(in boolean enabled, int userId);
+    boolean isAutoSoundQualityEnabled(int userId);
+
+    void setAmbientBacklightSettings(in AmbientBacklightSettings settings, int userId);
+    void setAmbientBacklightEnabled(in boolean enabled, int userId);
+    boolean isAmbientBacklightEnabled(int userId);
+}
diff --git a/media/java/android/media/quality/IPictureProfileCallback.aidl b/media/java/android/media/quality/aidl/android/media/quality/IPictureProfileCallback.aidl
similarity index 100%
rename from media/java/android/media/quality/IPictureProfileCallback.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/IPictureProfileCallback.aidl
diff --git a/media/java/android/media/quality/ISoundProfileCallback.aidl b/media/java/android/media/quality/aidl/android/media/quality/ISoundProfileCallback.aidl
similarity index 100%
rename from media/java/android/media/quality/ISoundProfileCallback.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/ISoundProfileCallback.aidl
diff --git a/media/java/android/media/quality/ParameterCapability.aidl b/media/java/android/media/quality/aidl/android/media/quality/ParameterCapability.aidl
similarity index 100%
rename from media/java/android/media/quality/ParameterCapability.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/ParameterCapability.aidl
diff --git a/media/java/android/media/quality/PictureProfile.aidl b/media/java/android/media/quality/aidl/android/media/quality/PictureProfile.aidl
similarity index 100%
rename from media/java/android/media/quality/PictureProfile.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/PictureProfile.aidl
diff --git a/media/java/android/media/quality/PictureProfileHandle.aidl b/media/java/android/media/quality/aidl/android/media/quality/PictureProfileHandle.aidl
similarity index 100%
rename from media/java/android/media/quality/PictureProfileHandle.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/PictureProfileHandle.aidl
diff --git a/media/java/android/media/quality/SoundProfile.aidl b/media/java/android/media/quality/aidl/android/media/quality/SoundProfile.aidl
similarity index 100%
rename from media/java/android/media/quality/SoundProfile.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/SoundProfile.aidl
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/media/java/android/media/quality/aidl/android/media/quality/SoundProfileHandle.aidl
similarity index 88%
rename from media/java/android/media/quality/SoundProfileHandle.aidl
rename to media/java/android/media/quality/aidl/android/media/quality/SoundProfileHandle.aidl
index 6b8161c..ea26b19 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/media/java/android/media/quality/aidl/android/media/quality/SoundProfileHandle.aidl
@@ -16,4 +16,7 @@
 
 package android.media.quality;
 
-parcelable SoundProfileHandle;
+// TODO: add SoundProfileHandle.java
+parcelable SoundProfileHandle {
+    long id;
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanListener.aidl b/media/java/android/media/tv/extension/scan/IScanListener.aidl
index 2c4807f..79810a7 100644
--- a/media/java/android/media/tv/extension/scan/IScanListener.aidl
+++ b/media/java/android/media/tv/extension/scan/IScanListener.aidl
@@ -27,7 +27,7 @@
     // notify the scan progress.
     void onScanProgress(String scanProgress, in Bundle scanProgressInfo);
     // notify the scan completion.
-    void onScanCompleted(int scanResult);
+    void onScanCompleted(int scanResult, in Bundle optionScanInfo);
     // notify that the temporaily held channel list is stored.
     void onStoreCompleted(int storeResult);
 }
diff --git a/media/java/android/media/tv/extension/scan/IScanSession.aidl b/media/java/android/media/tv/extension/scan/IScanSession.aidl
index d42eca1..f53b096 100644
--- a/media/java/android/media/tv/extension/scan/IScanSession.aidl
+++ b/media/java/android/media/tv/extension/scan/IScanSession.aidl
@@ -24,7 +24,7 @@
 interface IScanSession {
     // Start a service scan.
     int startScan(int broadcastType, String countryCode, String operator, in int[] frequency,
-        String scanType, String languageCode);
+        String scanType, String languageCode, in Bundle optionalScanParams);
     // Reset the scan information held in TIS.
     int resetScan();
     // Cancel scan.
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
index 1b1577f..0e9ac5f 100644
--- a/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
@@ -78,4 +78,11 @@
     int addPredefinedChannelList(String serviceListId, in Bundle[] predefinedListBundle);
     // Add predefined satellite info of Hotbird 13E in scan two satellite scene EU region.
     int addPredefinedSatInfo(String serviceListId, in Bundle predefinedSatInfoBundle);
+
+    // Get the logo URI for a specific service - DVB-I only.
+    String getServiceLogoUri(int serviceRecordId);
+    // Get the installed service list information for a specific channel list id - DVB-I only.
+    Bundle getInstalledServiceListInfo(String channelListId);
+    // Get all installed service list information - DVB-I only.
+    Bundle[] getAllInstalledServiceListInfo();
 }
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
index abd8320..fced45b 100644
--- a/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
@@ -16,10 +16,12 @@
 
 package android.media.tv.extension.servicedb;
 
+import android.os.Bundle;
+
 /**
  * @hide
  */
 interface IServiceListImportListener {
     void onImported(int importResult);
-    void onPreloaded(int preloadResult);
+    void onPreloaded(int preloadResult, in Bundle serviceListInfo);
 }
\ No newline at end of file
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 1e6a7b7..45b746d 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -971,7 +971,7 @@
                 .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos,
                 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
                                                         hal::WorkDurationFixedV1>({
-                        .durationNanos = message.cpuDurationNanos,
+                        .durationNanos = message.durationNanos,
                         .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
                         .cpuDurationNanos = message.cpuDurationNanos,
                         .gpuDurationNanos = message.gpuDurationNanos,
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index b802d0f..8e5a2b7 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Kanselleer"</string>
     <string name="consent_back" msgid="2560683030046918882">"Terug"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Rollees met die lys af"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Afwaartse pyl"</string>
     <string name="permission_expand" msgid="893185038020887411">"Vou <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> uit"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Vou <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> in"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Gee programme op &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; dieselfde toestemmings as op &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index d4d0b07..40472d2 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ይቅር"</string>
     <string name="consent_back" msgid="2560683030046918882">"ተመለስ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"በዝርዝሩ ላይ ወደታች ያሸብልሉ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"የአውርድ ቀስት"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ን ዘርጋ"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ን ሰብስብ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"በ&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ላይ ላሉ መተግበሪያዎች በ&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ላይ ካሉት ጋር ተመሳሳይ ፈቃዶች ይሰጣቸው?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 322d422..1f3ee73 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"বাতিল কৰক"</string>
     <string name="consent_back" msgid="2560683030046918882">"উভতি যাওক"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"সূচীখনত তললৈ স্ক্ৰ’ল কৰক"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"তলমুৱা কাঁড়"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> বিস্তাৰ কৰক"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> সংকোচন কৰক"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"এপ্‌সমূহক &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ত দিয়াৰ দৰে &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;তো একে অনুমতি প্ৰদান কৰিবনে?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 9f3ab2bd..aa4788a 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Ləğv edin"</string>
     <string name="consent_back" msgid="2560683030046918882">"Geriyə"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Siyahını aşağı sürüşdürün"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Aşağı ox"</string>
     <string name="permission_expand" msgid="893185038020887411">"Genişləndirin: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Yığcamlaşdırın: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; cihazındakı tətbiqlərə &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazındakılarla eyni icazələr verilsin?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index d28b9b2..3dcb585 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Otkaži"</string>
     <string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Skrolujte nadole na listi"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Strelica nadole"</string>
     <string name="permission_expand" msgid="893185038020887411">"Proširi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Skupi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Aplikcijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; dajete sve dozvole kao na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 214dc71..f5cf720 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"বাতিল করুন"</string>
     <string name="consent_back" msgid="2560683030046918882">"ফিরুন"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"তালিকা নিচের দিকে স্ক্রল করুন"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"নিম্নমুখী তীরচিহ্ন"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> বড় করুন"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> আড়াল করুন"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-এ যে অনুমতি দেওয়া আছে &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;-এও সেই একই অনুমতি দিতে চান?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index b23f600..a87ea18 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Otkaži"</string>
     <string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Klizanje nadolje na listi"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Strelica nadolje"</string>
     <string name="permission_expand" msgid="893185038020887411">"Proširivanje stavke <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sužavanje stavke <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dati aplikacijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ista odobrenja kao na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 21f3871..7ec2b8b 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"No permetis"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel·la"</string>
     <string name="consent_back" msgid="2560683030046918882">"Enrere"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Desplaça la llista cap avall"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Fletxa avall"</string>
     <string name="permission_expand" msgid="893185038020887411">"Desplega <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Replega <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vols concedir a les aplicacions del dispositiu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; els mateixos permisos que tenen a &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index cd89130..a1ea39b 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Zrušit"</string>
     <string name="consent_back" msgid="2560683030046918882">"Zpět"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Přejít v seznamu dolů"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Šipka dolů"</string>
     <string name="permission_expand" msgid="893185038020887411">"Rozbalit sekci <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sbalit sekci <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Udělit aplikacím v zařízení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; stejné oprávnění, jako mají v zařízení &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 6dc34e7..97e6fe56 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Annuller"</string>
     <string name="consent_back" msgid="2560683030046918882">"Tilbage"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Rul ned på listen"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Pil ned"</string>
     <string name="permission_expand" msgid="893185038020887411">"Udvid <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Skjul <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vil du give apps på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; de samme tilladelser som på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 4dc2929..fc0231f 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nicht zulassen"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Abbrechen"</string>
     <string name="consent_back" msgid="2560683030046918882">"Zurück"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"In der Liste nach unten scrollen"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Abwärtspfeil"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> maximieren"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> minimieren"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Apps auf &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; die gleichen Berechtigungen geben wie auf &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index bbd81bf..68c74e0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
     <string name="consent_back" msgid="2560683030046918882">"Back"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll down the list"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Downward arrow"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index bbd81bf..68c74e0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
     <string name="consent_back" msgid="2560683030046918882">"Back"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll down the list"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Downward arrow"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index bbd81bf..68c74e0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
     <string name="consent_back" msgid="2560683030046918882">"Back"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll down the list"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Downward arrow"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index f8e2c74..d74b4f8 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Desplazarse hacia abajo por la lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Flecha hacia abajo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Desplegar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Contraer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"¿Dar a las aplicaciones de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; los mismos permisos que &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index fb36c46..cf4fe25 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"اجازه ندادن"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"لغو"</string>
     <string name="consent_back" msgid="2560683030046918882">"برگشتن"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"پیمایش به‌پایین فهرست"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"جهت‌نمای پایین"</string>
     <string name="permission_expand" msgid="893185038020887411">"ازهم بازکردن <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"جمع کردن <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏به برنامه‌های موجود در &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; همان اجازه‌های &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; داده شود؟"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index ff6cae1..4be6a5a 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Älä salli"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Peruuta"</string>
     <string name="consent_back" msgid="2560683030046918882">"Takaisin"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Vieritä listaa alaspäin"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Alanuoli"</string>
     <string name="permission_expand" msgid="893185038020887411">"Laajenna <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Tiivistä <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Anna laitteen &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; sovelluksille samat luvat kuin laitteella &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 4d7de76..70beafb 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Annuler"</string>
     <string name="consent_back" msgid="2560683030046918882">"Retour"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Faire défiler la liste en bas"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Flèche vers le bas"</string>
     <string name="permission_expand" msgid="893185038020887411">"Développer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Réduire <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder aux applis sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; les autorisations déjà accordées sur &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index d4c12fb..394efae 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Annuler"</string>
     <string name="consent_back" msgid="2560683030046918882">"Retour"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Faire défiler la liste vers le bas"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Flèche vers le bas"</string>
     <string name="permission_expand" msgid="893185038020887411">"Développer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Réduire <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder les mêmes autorisations aux applis sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; que sur &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 999ab97..ce23be8 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Non permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Desprazarse abaixo na lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Frecha cara abaixo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Despregar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Contraer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Queres darlles ás aplicacións de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; os mesmos permisos que teñen as de &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 51d07c9..7956ba6 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"રદ કરો"</string>
     <string name="consent_back" msgid="2560683030046918882">"પાછળ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"સૂચિ પર નીચે સ્ક્રોલ કરો"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"નીચેની તરફ ઍરો"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ને મોટું કરો"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ને નાનું કરો"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; પરની ઍપને &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; પર છે તે જ પરવાનગીઓ આપીએ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 04872e5..326564e 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Odustani"</string>
     <string name="consent_back" msgid="2560683030046918882">"Natrag"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Pomicanje po popisu"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Strelica prema dolje"</string>
     <string name="permission_expand" msgid="893185038020887411">"Proširi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sažmi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dati jednaka dopuštenja aplikacijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; kao i na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index e7c7139..cbf1d8d 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Չեղարկել"</string>
     <string name="consent_back" msgid="2560683030046918882">"Հետ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Թերթեք ներքև"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Ներքև սլաք"</string>
     <string name="permission_expand" msgid="893185038020887411">"Ծավալել «<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>» բաժինը"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Ծալել «<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>» բաժինը"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;-ում հավելվածներին տա՞լ նույն թույլտվությունները, ինչ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ում"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index f582205..fe3406e 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Batal"</string>
     <string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll daftar ke bawah"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Panah bawah"</string>
     <string name="permission_expand" msgid="893185038020887411">"Luaskan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Ciutkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Berikan aplikasi di &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; izin yang sama seperti di &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index b66133c..9e366d6 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Hætta við"</string>
     <string name="consent_back" msgid="2560683030046918882">"Til baka"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Fletta niður listann"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Ör niður"</string>
     <string name="permission_expand" msgid="893185038020887411">"Stækka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Minnka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Veita forritum í &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; sömu heimildir og í &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 626ae7a..1e299b7 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"אין אישור"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ביטול"</string>
     <string name="consent_back" msgid="2560683030046918882">"חזרה"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"גלילה למטה ברשימה"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"חץ למטה"</string>
     <string name="permission_expand" msgid="893185038020887411">"הרחבה של <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"כיווץ של <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏האם לתת לאפליקציות ב-‎&lt;strong&gt;‎‏<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>‏‎&lt;/strong&gt;‎‏ את אותן הרשאות כמו ב-‏‎&lt;strong&gt;‎‏<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>‏‎&lt;/strong&gt;‎‏?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 97f3087..d0214ae 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"გაუქმება"</string>
     <string name="consent_back" msgid="2560683030046918882">"უკან"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"გადაადგილება სიის ქვემოთ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ქვემოთ მიმართული ისარი"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-ის გაფართოება"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-ის ჩაკეცვა"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"გსურთ აპებს &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;-ზე იგივე ნებართვები მიანიჭოთ, როგორიც აქვს &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ზე?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 4d77c6c..e794415 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Бас тарту"</string>
     <string name="consent_back" msgid="2560683030046918882">"Артқа"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Тізім соңына дейін айналдыру"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Төмен бағытталған перне"</string>
     <string name="permission_expand" msgid="893185038020887411">"\"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\" панелін жаю"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"\"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\" панелін жию"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; құрылғысындағы қолданбаларға &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысындағыдай рұқсаттар берілсін бе?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 751ac1f..a957f48 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ರದ್ದುಮಾಡಿ"</string>
     <string name="consent_back" msgid="2560683030046918882">"ಹಿಂದೆ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ಪಟ್ಟಿಯನ್ನು ಕೆಳಗೆ ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ಕೆಳಮುಖ ಬಾಣ"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ಅನ್ನು ವಿಸ್ತರಿಸಿ"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ಅನ್ನು ಕುಗ್ಗಿಸಿ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;/strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ಅನುಮತಿಗಳನ್ನೇ &lt;/strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ಆ್ಯಪ್‌ಗಳಿಗೆ ನೀಡಬೇಕೆ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index a7a5dc1..d7d489af 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"허용 안함"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"취소"</string>
     <string name="consent_back" msgid="2560683030046918882">"뒤로"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"목록을 아래로 스크롤"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"아래쪽 화살표"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> 펼치기"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> 접기"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;에 설치된 앱에 &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 설치된 앱과 동일한 권한을 부여하시겠습니까?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 991fc9f..3f8c58a 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Жок"</string>
     <string name="consent_back" msgid="2560683030046918882">"Артка"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Тизменин ылдый жагына сыдыруу"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Ылдый караган жебе"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> жайып көрсөтүү"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> жыйыштыруу"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; түзмөгүнө да &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүнө берилген уруксаттар берилсинби?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 91399b6..457efdb 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ຍົກເລີກ"</string>
     <string name="consent_back" msgid="2560683030046918882">"ກັບຄືນ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ເລື່ອນລາຍຊື່ລົງ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ລູກສອນຊີ້ລົງ"</string>
     <string name="permission_expand" msgid="893185038020887411">"ຂະຫຍາຍ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"ຫຍໍ້ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ລົງ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ໃຫ້ການອະນຸຍາດແອັບຢູ່ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ເປັນການອະນຸຍາດດຽວກັນກັບຢູ່ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 35c7481..01c9ed5 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Atcelt"</string>
     <string name="consent_back" msgid="2560683030046918882">"Atpakaļ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Ritināt sarakstu lejup"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Lejupvērsta bultiņa"</string>
     <string name="permission_expand" msgid="893185038020887411">"Izvērst: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sakļaut: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vai lietotnēm ierīcē &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; piešķirt tādas pašas atļaujas kā ierīcē &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 1eaf2d2..d9c8695 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Откажи"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Лизгај надолу по списокот"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрелка надолу"</string>
     <string name="permission_expand" msgid="893185038020887411">"Прошири <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Собери <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Дасе дадат исти дозволи на апликациите на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; како на &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 52fcb1f..828b6cf 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"റദ്ദാക്കുക"</string>
     <string name="consent_back" msgid="2560683030046918882">"മടങ്ങുക"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ലിസ്റ്റ് താഴേക്ക് സ്ക്രോൾ ചെയ്യൂ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"താഴേക്കുള്ള അമ്പടയാളം"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> വികസിപ്പിക്കുക"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ചുരുക്കുക"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിലെ അതേ അനുമതികൾ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിലെ ആപ്പുകൾക്ക് നൽകണോ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 5faf241..be6eb8e 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Цуцлах"</string>
     <string name="consent_back" msgid="2560683030046918882">"Буцах"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Жагсаалтыг доош гүйлгэх"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Доош заасан сум"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-г дэлгэх"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-г хураах"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; дээрх аппуудад &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; дээрхтэй адил зөвшөөрөл өгөх үү?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 94e49fe..99f59a6 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"रद्द करा"</string>
     <string name="consent_back" msgid="2560683030046918882">"मागे जा"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"सूचीवर खाली स्क्रोल करा"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"खालच्या दिशेचा अ‍ॅरो"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> चा विस्तार करा"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> कोलॅप्स करा"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; वरील अ‍ॅप्सना &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रमाणेच परवानग्या द्यायच्या आहेत का?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 8b1170b..9c15c06 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Batal"</string>
     <string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Tatal ke bawah senarai"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Anak panah ke bawah"</string>
     <string name="permission_expand" msgid="893185038020887411">"Kembangkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Kuncupkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Beri apl pada &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; kebenaran yang sama seperti pada &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index faca3e3..6068c43 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"မလုပ်တော့"</string>
     <string name="consent_back" msgid="2560683030046918882">"နောက်သို့"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"စာရင်းအောက်သို့ လှိမ့်ရန်"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"အောက်ညွှန်မြား"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ကို ပိုပြရန်"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ကို လျှော့ပြရန်"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"အက်ပ်များကို &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; တွင်ပေးထားသည့် ခွင့်ပြုချက်များအတိုင်း &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; တွင် ပေးမလား။"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 4188951..eb5e2e9 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Avbryt"</string>
     <string name="consent_back" msgid="2560683030046918882">"Tilbake"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Rull nedover i listen"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Nedoverpil"</string>
     <string name="permission_expand" msgid="893185038020887411">"Vis <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Skjul <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vil du gi apper på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; de samme tillatelsene som på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 2cd4fef..f3b56de 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"रद्द गर्नुहोस्"</string>
     <string name="consent_back" msgid="2560683030046918882">"पछाडि"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"सूचीको तलतिर स्क्रोल गर्नुहोस्"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"डाउनवार्ड एरो"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> एक्स्पान्ड गर्नुहोस्"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> कोल्याप्स गर्नुहोस्"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; मा भएका एपहरूलाई पनि &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; मा दिइएकै अनुमति दिने हो?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index 8298a5b..bd602e4 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ବାତିଲ କରନ୍ତୁ"</string>
     <string name="consent_back" msgid="2560683030046918882">"ପଛକୁ ଫେରନ୍ତୁ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ତାଲିକା ତଳକୁ ସ୍କ୍ରୋଲ କରନ୍ତୁ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ଡାଉନୱାର୍ଡ ତୀର"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>କୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>କୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ପରି &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;ରେ ଥିବା ଆପ୍ସକୁ ସମାନ ଅନୁମତିଗୁଡ଼ିକ ଦେବେ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index fe13c00..ae0b59d 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ਰੱਦ ਕਰੋ"</string>
     <string name="consent_back" msgid="2560683030046918882">"ਪਿੱਛੇ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ਸੂਚੀ ਨੂੰ ਹੇਠਾਂ ਵੱਲ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ਹੇਠਾਂ ਤੀਰ"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ਨੂੰ ਸਮੇਟੋ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ਕੀ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਐਪਾਂ ਨੂੰ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਐਪਾਂ ਵਾਂਗ ਇਜਾਜ਼ਤਾਂ ਦੇਣੀਆਂ ਹਨ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 1599f3f..bce0a6e 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Anuluj"</string>
     <string name="consent_back" msgid="2560683030046918882">"Wstecz"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Przewiń listę w dół"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Strzałka w dół"</string>
     <string name="permission_expand" msgid="893185038020887411">"Rozwiń sekcję <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Zwiń sekcję <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Czy aplikacjom na urządzeniu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; przyznać te same uprawnienia co na urządzeniu &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 85c23ea7..35b653a 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Role para baixo na lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Seta para baixo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Abrir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Fechar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar aos apps no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; as mesmas permissões do dispositivo &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 85c23ea7..35b653a 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Role para baixo na lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Seta para baixo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Abrir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Fechar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar aos apps no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; as mesmas permissões do dispositivo &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 6820d5b..0fdeb29 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nu permite"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Anulează"</string>
     <string name="consent_back" msgid="2560683030046918882">"Înapoi"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Derulează în jos lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Săgeată în jos"</string>
     <string name="permission_expand" msgid="893185038020887411">"Extinde <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Restrânge <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Acorzi aplicațiilor de pe &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; aceleași permisiuni ca pe &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 3213a2f..872f45e 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Запретить"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Отмена"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Прокрутить список вниз"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрелка вниз"</string>
     <string name="permission_expand" msgid="893185038020887411">"Разворачивать список \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\"."</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Сворачивать список \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\"."</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Предоставить приложениям на устройстве &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; те же разрешения, что на устройстве &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 7fd6611..ec362f2 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"අවලංගු කරන්න"</string>
     <string name="consent_back" msgid="2560683030046918882">"ආපසු"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ලැයිස්තුව පහළට අනුචලනය කරන්න"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"පහළට ඊතලය"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> විදහන්න"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> හකුළන්න"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the හි යෙදුම්වලට &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හි අවසරම දෙන්නද?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 5194f21..cbf5648 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Zrušiť"</string>
     <string name="consent_back" msgid="2560683030046918882">"Späť"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Posunúť zoznam nadol"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Šípka nadol"</string>
     <string name="permission_expand" msgid="893185038020887411">"Rozbaliť sekciu <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Zbaliť sekciu <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Chcete udeliť aplikáciám v zariadení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; rovnaké povolenia ako v zariadení &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 2200220..20570c30 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Prekliči"</string>
     <string name="consent_back" msgid="2560683030046918882">"Nazaj"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Pomikanje navzdol po seznamu"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Puščica navzdol"</string>
     <string name="permission_expand" msgid="893185038020887411">"Razširi dovoljenje »<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>«"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Strni dovoljenje »<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>«"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ali želite aplikacijam v napravi &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; odobriti enaka dovoljenja kot v napravi &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index f683dd9..32ede40 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Anulo"</string>
     <string name="consent_back" msgid="2560683030046918882">"Pas"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Lëviz poshtë në listë"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Shigjeta poshtë"</string>
     <string name="permission_expand" msgid="893185038020887411">"Zgjero: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Palos: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"T\'i jepen aplikacioneve në &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; të njëjtat leje si në &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index d568009..ac84c34 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Откажи"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Скролујте надоле на листи"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрелица надоле"</string>
     <string name="permission_expand" msgid="893185038020887411">"Прошири <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Скупи <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Апликцијама на уређају &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; дајете све дозволе као на уређају &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 5c6f5ba..c9364b8 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Avbryt"</string>
     <string name="consent_back" msgid="2560683030046918882">"Tillbaka"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scrolla nedåt i listan"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Nedåtpil"</string>
     <string name="permission_expand" msgid="893185038020887411">"Utöka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Komprimera <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vill du ge apparna på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; samma behörigheter som de har på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 7a1cf98..2a9cbee 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Ghairi"</string>
     <string name="consent_back" msgid="2560683030046918882">"Nyuma"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Sogeza chini kwenye orodha"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Kishale kinachoelekeza chini"</string>
     <string name="permission_expand" msgid="893185038020887411">"Panua <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Kunja <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ungependa kuzipa programu katika &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ruhusa ile ile kama kwenye &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 2313cc3..2503826 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"அனுமதிக்க வேண்டாம்"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ரத்துசெய்"</string>
     <string name="consent_back" msgid="2560683030046918882">"பின்செல்"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"பட்டியலில் கீழே நகர்த்து"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"கீழ்நோக்கிய அம்புக்குறி"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ஐ விரிவாக்கும்"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ஐச் சுருக்கும்"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்தில் இருக்கும் அதே அனுமதிகளை &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; சாதனத்தில் உள்ள ஆப்ஸுக்கும் வழங்கவா?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index eed0eee..d82c57c 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"రద్దు చేయండి"</string>
     <string name="consent_back" msgid="2560683030046918882">"వెనుకకు"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"లిస్ట్‌ను కిందకు స్క్రోల్ చేయి"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"కింది వైపు బాణం గుర్తు"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>‌ను విస్తరించండి"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>‌ను కుదించండి"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;లోని యాప్‌లకు &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;లో ఉన్న అనుమతులను ఇవ్వాలా?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index bf14f4c..26aa9dd 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ยกเลิก"</string>
     <string name="consent_back" msgid="2560683030046918882">"กลับ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"เลื่อนรายการลง"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ลูกศรชี้ลง"</string>
     <string name="permission_expand" msgid="893185038020887411">"ขยาย <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"ยุบ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ให้แอปใน &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; มีสิทธิ์เหมือนกับใน &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ไหม"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 56997d7..01fc767 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"İzin verme"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"İptal"</string>
     <string name="consent_back" msgid="2560683030046918882">"Geri"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Listeyi aşağı kaydırın"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Aşağı ok"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> panelini genişlet"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> panelini daralt"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; cihazındaki uygulamalara, &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazındakiyle aynı izinler verilsin mi?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 7d7b9de..73e5d58 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Скасувати"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Прокрутити список униз"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрілка вниз"</string>
     <string name="permission_expand" msgid="893185038020887411">"Розгорнути дозвіл \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\""</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Згорнути дозвіл \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\""</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Надати додаткам на пристрої &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; такі самі дозволи, що й на пристрої &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index e1a024c..b4ac45c 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Bekor qilish"</string>
     <string name="consent_back" msgid="2560683030046918882">"Orqaga"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Roʻyxatni pastga varaqlash"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Pastga strelka"</string>
     <string name="permission_expand" msgid="893185038020887411">"Yoyish: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Yopish: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovalariga &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasidagi kabi bir xil ruxsatlar berilsinmi?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 0293317..11cceaf 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Huỷ"</string>
     <string name="consent_back" msgid="2560683030046918882">"Quay lại"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Di chuyển xuống danh sách"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Mũi tên xuống"</string>
     <string name="permission_expand" msgid="893185038020887411">"Mở rộng <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Thu gọn <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Cấp cho các ứng dụng trên &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; các quyền giống như trên &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index ed68dd3..7632af0 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"不允许"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
     <string name="consent_back" msgid="2560683030046918882">"返回"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"向下滚动列表"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"向下箭头"</string>
     <string name="permission_expand" msgid="893185038020887411">"展开<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"收起<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要让&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;上的应用享有在&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;上的同等权限吗?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 17d3482f..9f988c3 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
     <string name="consent_back" msgid="2560683030046918882">"返回"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"向下捲動清單"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"向下箭咀"</string>
     <string name="permission_expand" msgid="893185038020887411">"展開<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"收合<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; 上的應用程式可獲在 &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 上的相同權限嗎?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 542a73fc..5bc7bfa 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
     <string name="consent_back" msgid="2560683030046918882">"返回"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"向下捲動清單"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"向下箭頭"</string>
     <string name="permission_expand" msgid="893185038020887411">"展開<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"收合<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要讓「<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;的應用程式沿用在「<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;上的權限嗎?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index b1c7a14..37034fa 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Khansela"</string>
     <string name="consent_back" msgid="2560683030046918882">"Emuva"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Skrola uye ezansi ohlwini"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Umcibisholo obheke phansi"</string>
     <string name="permission_expand" msgid="893185038020887411">"Nweba i-<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Goqa i-<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Nikeza ama-app &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; izimvume ezifanayot &lt;strong&gt;njengaku-<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/UniverseProgressNotifier.kt b/packages/EasterEgg/src/com/android/egg/landroid/UniverseProgressNotifier.kt
index bb3a04d..705d9e1 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/UniverseProgressNotifier.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/UniverseProgressNotifier.kt
@@ -127,7 +127,7 @@
                     val eta = if (speed > 0) "%1.0fs".format(distToTarget / speed) else "???"
                     builder.setContentTitle("headed to: ${target.name}")
                     builder.setContentText(
-                        "autopilot is ${autopilot.strategy.toLowerCase()}" +
+                        "autopilot is ${autopilot.strategy.lowercase()}" +
                             "\ndist: ${distToTarget}u // eta: $eta"
                     )
                     // fun fact: ProgressStyle was originally EnRouteStyle
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index e818a60..0c64fa7 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -138,8 +138,12 @@
         ImageView backgroundViewTablet =
                 (ImageView) holder.findViewById(R.id.background_view_tablet);
 
-        backgroundView.setVisibility(mIsTablet ? View.GONE : View.VISIBLE);
-        backgroundViewTablet.setVisibility(mIsTablet ? View.VISIBLE : View.GONE);
+        if (backgroundView != null) {
+            backgroundView.setVisibility(mIsTablet ? View.GONE : View.VISIBLE);
+        }
+        if (backgroundViewTablet != null) {
+            backgroundViewTablet.setVisibility(mIsTablet ? View.VISIBLE : View.GONE);
+        }
         if (mIsTablet) {
             backgroundView = backgroundViewTablet;
         }
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml
index 7580973..2ffdc93 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml
@@ -21,8 +21,4 @@
     <string name="enabled_by_admin">Enabled by admin</string>
     <!-- Summary for switch preference to denote it is switched off by an admin [CHAR LIMIT=50] -->
     <string name="disabled_by_admin">Disabled by admin</string>
-    <!-- Summary for switch preference to denote it is switched on by Advanced protection [CHAR LIMIT=50] -->
-    <string name="enabled_by_advanced_protection">Enabled by Advanced Protection</string>
-    <!-- Summary for switch preference to denote it is switched off by Advanced protection [CHAR LIMIT=50] -->
-    <string name="disabled_by_advanced_protection">Disabled by Advanced Protection</string>
 </resources>
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedMode.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedMode.kt
index a848330..6f37f0c 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedMode.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedMode.kt
@@ -46,7 +46,7 @@
 ) : BlockedByAdmin {
     override fun getSummary(checked: Boolean?) = when (checked) {
         true -> enterpriseRepository.getAdminSummaryString(
-            advancedProtectionStringId = R.string.enabled_by_advanced_protection,
+            advancedProtectionStringId = com.android.settingslib.R.string.enabled,
             updatableStringId = Settings.ENABLED_BY_ADMIN_SWITCH_SUMMARY,
             resId = R.string.enabled_by_admin,
             enforcedAdmin = enforcedAdmin,
@@ -54,7 +54,7 @@
         )
 
         false -> enterpriseRepository.getAdminSummaryString(
-            advancedProtectionStringId = R.string.disabled_by_advanced_protection,
+            advancedProtectionStringId = com.android.settingslib.R.string.disabled,
             updatableStringId = Settings.DISABLED_BY_ADMIN_SWITCH_SUMMARY,
             resId = R.string.disabled_by_admin,
             enforcedAdmin = enforcedAdmin,
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSystemInteger.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSystemInteger.kt
new file mode 100644
index 0000000..db7a640
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSystemInteger.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.spaprivileged.settingsprovider
+
+import android.content.ContentResolver
+import android.content.Context
+import android.provider.Settings
+import com.android.settingslib.spaprivileged.database.contentChangeFlow
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+
+fun Context.settingsSystemInteger(
+    name: String,
+    defaultValue: Int
+): ReadWriteProperty<Any?, Int> = SettingsSystemIntegerDelegate(this, name, defaultValue)
+
+fun Context.settingsSystemIntegerFlow(name: String, defaultValue: Int): Flow<Int> {
+    val value by settingsSystemInteger(name, defaultValue)
+    return contentChangeFlow(Settings.System.getUriFor(name))
+        .map { value }
+        .distinctUntilChanged()
+        .conflate()
+        .flowOn(Dispatchers.IO)
+}
+
+private class SettingsSystemIntegerDelegate(
+    context: Context,
+    private val name: String,
+    private val defaultValue: Int,
+) : ReadWriteProperty<Any?, Int> {
+
+    private val contentResolver: ContentResolver = context.contentResolver
+
+    override fun getValue(thisRef: Any?, property: KProperty<*>): Int =
+        Settings.System.getInt(contentResolver, name, defaultValue)
+
+    override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
+        Settings.System.putInt(contentResolver, name, value)
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/robotests/Android.bp b/packages/SettingsLib/SpaPrivileged/tests/robotests/Android.bp
new file mode 100644
index 0000000..e3faf73
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/robotests/Android.bp
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2025 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+    name: "SpaPrivilegedRoboTestStub",
+    defaults: [
+        "SpaPrivilegedLib-defaults",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+}
+
+android_robolectric_test {
+    name: "SpaPrivilegedRoboTests",
+    srcs: [
+        ":SpaPrivilegedLib_srcs",
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+
+    defaults: [
+        "SpaPrivilegedLib-defaults",
+    ],
+
+    static_libs: [
+        "SpaLibTestUtils",
+        "androidx.test.ext.junit",
+        "androidx.test.runner",
+    ],
+
+    java_resource_dirs: [
+        "config",
+    ],
+
+    instrumentation_for: "SpaPrivilegedRoboTestStub",
+
+    test_options: {
+        timeout: 36000,
+    },
+
+    strict_mode: false,
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/robotests/AndroidManifest.xml b/packages/SettingsLib/SpaPrivileged/tests/robotests/AndroidManifest.xml
new file mode 100644
index 0000000..113852d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/robotests/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    coreApp="true"
+    package="com.android.settingslib.spaprivileged.settingsprovider">
+
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+
+    <application/>
+</manifest>
\ No newline at end of file
diff --git a/packages/SettingsLib/SpaPrivileged/tests/robotests/config/robolectric.properties b/packages/SettingsLib/SpaPrivileged/tests/robotests/config/robolectric.properties
new file mode 100644
index 0000000..95a24bd
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/robotests/config/robolectric.properties
@@ -0,0 +1,16 @@
+/*
+* Copyright (C) 2025 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+sdk=NEWEST_SDK
\ No newline at end of file
diff --git a/packages/SettingsLib/SpaPrivileged/tests/robotests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSystemIntegerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/robotests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSystemIntegerTest.kt
new file mode 100644
index 0000000..67e4180
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/robotests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSystemIntegerTest.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.spaprivileged.settingsprovider
+
+import android.content.Context
+import android.provider.Settings
+
+import androidx.test.core.app.ApplicationProvider
+
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.android.settingslib.spa.testutils.toListWithTimeout
+import com.google.common.truth.Truth.assertThat
+
+import kotlinx.coroutines.async
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@RunWith(RobolectricTestRunner::class)
+class SettingsSystemIntegerTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Before
+    fun setUp() {
+        Settings.System.putString(context.contentResolver, TEST_NAME, null)
+    }
+
+    @Test
+    fun setIntValue_returnSameValueByDelegate() {
+        val settingValue = 250
+
+        Settings.System.putInt(context.contentResolver, TEST_NAME, settingValue)
+
+        val value by context.settingsSystemInteger(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+
+        assertThat(value).isEqualTo(settingValue)
+    }
+
+    @Test
+    fun setZero_returnZeroByDelegate() {
+        val settingValue = 0
+        Settings.System.putInt(context.contentResolver, TEST_NAME, settingValue)
+
+        val value by context.settingsSystemInteger(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+
+        assertThat(value).isEqualTo(settingValue)
+    }
+
+    @Test
+    fun setValueByDelegate_getValueFromSettings() {
+        val settingsValue = 5
+        var value by context.settingsSystemInteger(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+
+        value = settingsValue
+
+        assertThat(Settings.System.getInt(context.contentResolver, TEST_NAME, TEST_SETTING_DEFAULT_VALUE)).isEqualTo(settingsValue)
+    }
+
+    @Test
+    fun setZeroByDelegate_getZeroFromSettings() {
+        val settingValue = 0
+        var value by context.settingsSystemInteger(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+
+        value = settingValue
+
+        assertThat(Settings.System.getInt(context.contentResolver, TEST_NAME, TEST_SETTING_DEFAULT_VALUE)).isEqualTo(settingValue)
+    }
+
+    @Test
+    fun setValueByDelegate_returnValueFromsettingsSystemIntegerFlow() = runBlocking<Unit> {
+        val settingValue = 7
+        var value by context.settingsSystemInteger(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+        value = settingValue
+
+        val flow = context.settingsSystemIntegerFlow(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+
+        assertThat(flow.firstWithTimeoutOrNull()).isEqualTo(settingValue)
+    }
+
+    @Test
+    fun setValueByDelegateTwice_collectAfterValueChanged_onlyKeepLatest() = runBlocking<Unit> {
+        val firstSettingValue = 5
+        val secondSettingValue = 10
+
+        var value by context.settingsSystemInteger(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+        value = firstSettingValue
+
+        val flow = context.settingsSystemIntegerFlow(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+        value = secondSettingValue
+
+        assertThat(flow.firstWithTimeoutOrNull()).isEqualTo(value)
+    }
+
+    @Test
+    fun settingsSystemIntegerFlow_collectBeforeValueChanged_getBoth() = runBlocking<Unit> {
+        val firstSettingValue = 12
+        val secondSettingValue = 17
+        val delay_ms = 100L
+
+        var value by context.settingsSystemInteger(TEST_NAME, TEST_SETTING_DEFAULT_VALUE)
+        value = firstSettingValue
+
+
+        val listDeferred = async {
+            context.settingsSystemIntegerFlow(TEST_NAME, TEST_SETTING_DEFAULT_VALUE).toListWithTimeout()
+        }
+
+        delay(delay_ms)
+        value = secondSettingValue
+
+        assertThat(listDeferred.await())
+            .containsAtLeast(firstSettingValue, secondSettingValue).inOrder()
+    }
+
+    private companion object {
+        const val TEST_NAME = "test_system_integer_delegate"
+        const val TEST_SETTING_DEFAULT_VALUE = -1
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/Android.bp b/packages/SettingsLib/SpaPrivileged/tests/unit/Android.bp
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/Android.bp
rename to packages/SettingsLib/SpaPrivileged/tests/unit/Android.bp
diff --git a/packages/SettingsLib/SpaPrivileged/tests/AndroidManifest.xml b/packages/SettingsLib/SpaPrivileged/tests/unit/AndroidManifest.xml
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/AndroidManifest.xml
rename to packages/SettingsLib/SpaPrivileged/tests/unit/AndroidManifest.xml
diff --git a/packages/SettingsLib/SpaPrivileged/tests/res/values/strings.xml b/packages/SettingsLib/SpaPrivileged/tests/unit/res/values/strings.xml
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/res/values/strings.xml
rename to packages/SettingsLib/SpaPrivileged/tests/unit/res/values/strings.xml
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatterTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatterTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatterTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatterTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsRepositoryTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsRepositoryTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsRepositoryTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt
similarity index 93%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt
index f3245c9..189bf36 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt
@@ -77,8 +77,8 @@
             if (RestrictedLockUtilsInternal.isPolicyEnforcedByAdvancedProtection(context,
                     RESTRICTION, userId)) {
                 return when (advancedProtectionStringId) {
-                    R.string.enabled_by_advanced_protection -> ENABLED_BY_ADVANCED_PROTECTION
-                    R.string.disabled_by_advanced_protection -> DISABLED_BY_ADVANCED_PROTECTION
+                    com.android.settingslib.R.string.enabled -> ENABLED
+                    com.android.settingslib.R.string.disabled -> DISABLED
                     else -> ""
                 }
             }
@@ -129,7 +129,7 @@
 
         val summary = blockedByAdmin.getSummary(true)
 
-        assertThat(summary).isEqualTo(ENABLED_BY_ADVANCED_PROTECTION)
+        assertThat(summary).isEqualTo(ENABLED)
     }
 
     @RequiresFlagsEnabled(Flags.FLAG_AAPM_API)
@@ -148,7 +148,7 @@
 
         val summary = blockedByAdmin.getSummary(false)
 
-        assertThat(summary).isEqualTo(DISABLED_BY_ADVANCED_PROTECTION)
+        assertThat(summary).isEqualTo(DISABLED)
     }
 
     @RequiresFlagsEnabled(Flags.FLAG_AAPM_API)
@@ -202,7 +202,7 @@
 
         const val ENABLED_BY_ADMIN = "Enabled by admin"
         const val DISABLED_BY_ADMIN = "Disabled by admin"
-        const val ENABLED_BY_ADVANCED_PROTECTION = "Enabled by advanced protection"
-        const val DISABLED_BY_ADVANCED_PROTECTION = "Disabled by advanced protection"
+        const val ENABLED = "Enabled"
+        const val DISABLED = "Disabled"
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItemTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItemTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItemTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
similarity index 97%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
index 79085af..308b285 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
@@ -175,13 +175,7 @@
 
         val summary = getSummary(listModel)
 
-        assertThat(summary)
-            .isEqualTo(
-                context.getString(
-                    com.android.settingslib.widget.restricted.R.string
-                        .disabled_by_advanced_protection
-                )
-            )
+        assertThat(summary).isEqualTo(context.getString(com.android.settingslib.R.string.disabled))
     }
 
     @RequiresFlagsEnabled(Flags.FLAG_AAPM_API)
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/common/UserProfilePagerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/common/UserProfilePagerTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/common/UserProfilePagerTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/common/UserProfilePagerTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedMainSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedMainSwitchPreferenceTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedMainSwitchPreferenceTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedMainSwitchPreferenceTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedPreferenceTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedPreferenceTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedPreferenceTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreferenceTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreferenceTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreferenceTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index a029f56..349d13a 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -37,13 +37,6 @@
 }
 
 flag {
-    name: "enable_hide_exclusively_managed_bluetooth_device"
-    namespace: "dck_framework"
-    description: "Hide exclusively managed Bluetooth devices in BT settings menu."
-    bug: "324475542"
-}
-
-flag {
     name: "enable_set_preferred_transport_for_le_audio_device"
     namespace: "bluetooth"
     description: "Enable setting preferred transport for Le Audio device"
@@ -249,3 +242,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "audio_stream_media_service_by_receive_state"
+    namespace: "cross_device_experiences"
+    description: "Start or update audio stream media service by receive state"
+    bug: "398700619"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SettingsLib/res/drawable/ic_news.xml b/packages/SettingsLib/res/drawable/ic_news.xml
new file mode 100644
index 0000000..90615ec
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_news.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:height="14.933333dp" android:viewportHeight="14" android:viewportWidth="15" android:width="16dp">
+    <path android:fillColor="#ffffff" android:pathData="M3,10.8H11V9.6H3V10.8ZM3,8.4H5.4V4.8H3V8.4ZM12.2,13.6H1.8C1.467,13.6 1.183,13.483 0.95,13.25C0.717,13.017 0.6,12.733 0.6,12.4V3.6C0.6,3.267 0.717,2.983 0.95,2.75C1.183,2.517 1.467,2.4 1.8,2.4H6.683C6.528,2.711 6.406,3.033 6.317,3.367C6.239,3.7 6.2,4.044 6.2,4.4C6.2,4.933 6.283,5.439 6.45,5.917C6.628,6.383 6.878,6.811 7.2,7.2H6.6V8.4H8.767C9.056,8.522 9.35,8.622 9.65,8.7C9.961,8.767 10.278,8.8 10.6,8.8C11.111,8.8 11.606,8.717 12.083,8.55C12.572,8.372 13.011,8.122 13.4,7.8V12.4C13.4,12.733 13.283,13.017 13.05,13.25C12.817,13.483 12.533,13.6 12.2,13.6ZM10.6,8C10.6,7 10.25,6.15 9.55,5.45C8.85,4.75 8,4.4 7,4.4C8,4.4 8.85,4.05 9.55,3.35C10.25,2.65 10.6,1.8 10.6,0.8C10.6,1.8 10.95,2.65 11.65,3.35C12.35,4.05 13.2,4.4 14.2,4.4C13.2,4.4 12.35,4.75 11.65,5.45C10.95,6.15 10.6,7 10.6,8Z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_promotions.xml b/packages/SettingsLib/res/drawable/ic_promotions.xml
new file mode 100644
index 0000000..a597ece
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_promotions.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:height="16dp" android:viewportHeight="15" android:viewportWidth="13" android:width="13.866667dp">
+    <path android:fillColor="#ffffff" android:pathData="M1.4,13.4C1.067,13.4 0.783,13.283 0.55,13.05C0.317,12.817 0.2,12.533 0.2,12.2V4.6C0.2,4.267 0.317,3.983 0.55,3.75C0.783,3.517 1.067,3.4 1.4,3.4H2.6V3.133C2.6,2.467 2.822,1.878 3.267,1.367C3.722,0.856 4.3,0.6 5,0.6C5.667,0.6 6.233,0.833 6.7,1.3C7.167,1.767 7.4,2.333 7.4,3V3.4H8.6C8.933,3.4 9.217,3.517 9.45,3.75C9.683,3.983 9.8,4.267 9.8,4.6V6.367C9.611,6.311 9.417,6.272 9.217,6.25C9.017,6.217 8.811,6.2 8.6,6.2C7.378,6.2 6.339,6.628 5.483,7.483C4.628,8.339 4.2,9.378 4.2,10.6C4.2,11.111 4.283,11.611 4.45,12.1C4.628,12.578 4.878,13.011 5.2,13.4H1.4ZM8.6,14.2C8.6,13.2 8.25,12.35 7.55,11.65C6.85,10.95 6,10.6 5,10.6C6,10.6 6.85,10.25 7.55,9.55C8.25,8.85 8.6,8 8.6,7C8.6,8 8.95,8.85 9.65,9.55C10.35,10.25 11.2,10.6 12.2,10.6C11.2,10.6 10.35,10.95 9.65,11.65C8.95,12.35 8.6,13.2 8.6,14.2ZM3.8,3.4H6.2V3C6.2,2.667 6.083,2.383 5.85,2.15C5.617,1.917 5.333,1.8 5,1.8C4.667,1.8 4.383,1.917 4.15,2.15C3.917,2.383 3.8,2.667 3.8,3V3.4ZM3.2,5.8C3.367,5.8 3.506,5.744 3.617,5.633C3.739,5.511 3.8,5.367 3.8,5.2V4.6H2.6V5.2C2.6,5.367 2.656,5.511 2.767,5.633C2.889,5.744 3.033,5.8 3.2,5.8ZM6.8,5.8C6.967,5.8 7.106,5.744 7.217,5.633C7.339,5.511 7.4,5.367 7.4,5.2V4.6H6.2V5.2C6.2,5.367 6.256,5.511 6.367,5.633C6.489,5.744 6.633,5.8 6.8,5.8Z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_recs.xml b/packages/SettingsLib/res/drawable/ic_recs.xml
new file mode 100644
index 0000000..034ff9e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_recs.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="14dp"
+    android:height="16dp"
+    android:viewportWidth="14"
+    android:viewportHeight="16">
+  <path
+      android:pathData="M6,15.2L3.6,12.8H1.6C1.278,12.8 0.994,12.683 0.75,12.45C0.517,12.206 0.4,11.922 0.4,11.6V2.8C0.4,2.478 0.517,2.2 0.75,1.967C0.994,1.722 1.278,1.6 1.6,1.6H6.2C5.878,1.989 5.628,2.428 5.45,2.917C5.283,3.394 5.2,3.889 5.2,4.4C5.2,5.622 5.628,6.661 6.483,7.517C7.339,8.372 8.378,8.8 9.6,8.8C9.956,8.8 10.3,8.761 10.633,8.683C10.967,8.594 11.289,8.472 11.6,8.317V11.6C11.6,11.922 11.483,12.206 11.25,12.45C11.017,12.683 10.733,12.8 10.4,12.8H8.4L6,15.2ZM9.6,8C9.6,7 9.25,6.15 8.55,5.45C7.85,4.75 7,4.4 6,4.4C7,4.4 7.85,4.05 8.55,3.35C9.25,2.65 9.6,1.8 9.6,0.8C9.6,1.8 9.95,2.65 10.65,3.35C11.35,4.05 12.2,4.4 13.2,4.4C12.2,4.4 11.35,4.75 10.65,5.45C9.95,6.15 9.6,7 9.6,8Z"
+      android:fillColor="#ffffff"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_social.xml b/packages/SettingsLib/res/drawable/ic_social.xml
new file mode 100644
index 0000000..0197431
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_social.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:height="16dp" android:viewportHeight="15" android:viewportWidth="15" android:width="16dp">
+    <path android:fillColor="#ffffff" android:pathData="M0.6,14.4V12.733C0.6,12.411 0.678,12.117 0.833,11.85C0.989,11.583 1.211,11.378 1.5,11.233C2.056,10.956 2.628,10.75 3.217,10.617C3.817,10.472 4.428,10.4 5.05,10.4C5.661,10.4 6.256,10.472 6.833,10.617C7.422,10.75 7.989,10.956 8.533,11.233C8.811,11.378 9.028,11.583 9.183,11.85C9.339,12.117 9.417,12.411 9.417,12.733V14.4H0.6ZM10.6,14.4V12.617C10.6,12.183 10.494,11.778 10.283,11.4C10.072,11.022 9.772,10.733 9.383,10.533C9.772,10.6 10.144,10.7 10.5,10.833C10.856,10.956 11.206,11.106 11.55,11.283C11.828,11.439 12.072,11.628 12.283,11.85C12.494,12.061 12.6,12.317 12.6,12.617V14.4H10.6ZM5.2,9.6C4.589,9.6 4.067,9.389 3.633,8.967C3.211,8.533 3,8.011 3,7.4C3,6.789 3.211,6.272 3.633,5.85C4.067,5.417 4.589,5.2 5.2,5.2C5.811,5.2 6.328,5.417 6.75,5.85C7.183,6.272 7.4,6.789 7.4,7.4C7.4,8.011 7.183,8.533 6.75,8.967C6.328,9.389 5.811,9.6 5.2,9.6ZM10.6,7.4C10.6,8.011 10.383,8.533 9.95,8.967C9.528,9.389 9.011,9.6 8.4,9.6C8.311,9.6 8.217,9.594 8.117,9.583C8.017,9.572 7.922,9.55 7.833,9.517C8.089,9.206 8.278,8.872 8.4,8.517C8.533,8.161 8.6,7.789 8.6,7.4C8.6,7.011 8.533,6.639 8.4,6.283C8.278,5.928 8.089,5.594 7.833,5.283C7.922,5.25 8.017,5.228 8.117,5.217C8.217,5.206 8.311,5.2 8.4,5.2C9.011,5.2 9.528,5.417 9.95,5.85C10.383,6.272 10.6,6.789 10.6,7.4ZM11.4,6.4C11.4,5.622 11.128,4.961 10.583,4.417C10.039,3.872 9.378,3.6 8.6,3.6C9.378,3.6 10.039,3.328 10.583,2.783C11.128,2.239 11.4,1.578 11.4,0.8C11.4,1.578 11.672,2.239 12.217,2.783C12.761,3.328 13.422,3.6 14.2,3.6C13.422,3.6 12.761,3.872 12.217,4.417C11.672,4.961 11.4,5.622 11.4,6.4Z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 91ec836..03cb1ff 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1263,6 +1263,8 @@
 
     <!-- [CHAR LIMIT=25] Manage applications, text telling using an application is disabled. -->
     <string name="disabled">Disabled</string>
+    <!-- Summary for a settings preference indicating it is enabled [CHAR LIMIT = 30] -->
+    <string name="enabled">Enabled</string>
     <!-- Summary of app trusted to install apps [CHAR LIMIT=45] -->
     <string name="external_source_trusted">Allowed</string>
     <!-- Summary of app not trusted to install apps [CHAR LIMIT=45] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 1044750..9d97901 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -120,7 +120,7 @@
             final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
             if (summaryView != null) {
                 final CharSequence disabledText = getDisabledByAdminSummaryString();
-                if (mDisabledByAdmin) {
+                if (mDisabledByAdmin && disabledText != null) {
                     summaryView.setText(disabledText);
                 } else if (mDisabledByEcm) {
                     summaryView.setText(getEcmTextResId());
@@ -132,10 +132,10 @@
         }
     }
 
-    private String getDisabledByAdminSummaryString() {
+    private @Nullable String getDisabledByAdminSummaryString() {
         if (isRestrictionEnforcedByAdvancedProtection()) {
-            return mContext.getString(com.android.settingslib.widget.restricted
-                    .R.string.disabled_by_advanced_protection);
+            // Advanced Protection doesn't set the summary string, it keeps the current summary.
+            return null;
         }
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
             return mContext.getSystemService(DevicePolicyManager.class).getResources().getString(
@@ -321,7 +321,10 @@
         }
 
         if (android.security.Flags.aapmApi() && !isEnabled && mDisabledByAdmin) {
-            mPreference.setSummary(getDisabledByAdminSummaryString());
+            String summary = getDisabledByAdminSummaryString();
+            if (summary != null) {
+                mPreference.setSummary(summary);
+            }
         }
 
         if (!isEnabled && mDisabledByEcm) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index a5fa6a8..67c4207 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -36,6 +36,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceViewHolder;
@@ -141,7 +142,7 @@
             final TextView additionalSummaryView = (TextView) holder.findViewById(
                     R.id.additional_summary);
             if (additionalSummaryView != null) {
-                if (isDisabledByAdmin()) {
+                if (isDisabledByAdmin() && switchSummary != null) {
                     additionalSummaryView.setText(switchSummary);
                     additionalSummaryView.setVisibility(View.VISIBLE);
                 } else {
@@ -151,7 +152,7 @@
         } else {
             final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
             if (summaryView != null) {
-                if (isDisabledByAdmin()) {
+                if (isDisabledByAdmin() && switchSummary != null) {
                     summaryView.setText(switchSummary);
                     summaryView.setVisibility(View.VISIBLE);
                 }
@@ -171,14 +172,10 @@
                 () -> context.getString(resId));
     }
 
-    private String getRestrictedSwitchSummary() {
+    private @Nullable String getRestrictedSwitchSummary() {
         if (mHelper.isRestrictionEnforcedByAdvancedProtection()) {
-            final int apmResId = isChecked()
-                    ? com.android.settingslib.widget.restricted.R.string
-                            .enabled_by_advanced_protection
-                    : com.android.settingslib.widget.restricted.R.string
-                            .disabled_by_advanced_protection;
-            return getContext().getString(apmResId);
+            // Advanced Protection doesn't set the summary string, it keeps the current summary.
+            return null;
         }
 
         return isChecked()
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index e78a692..ae9ad95 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -51,6 +51,8 @@
 import com.google.common.collect.ImmutableSet;
 
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -1268,4 +1270,15 @@
 
         return false;
     }
+
+    /** Gets key missing count of the device. This is a workaround before the API is rolled out. */
+    public static Integer getKeyMissingCount(BluetoothDevice device) {
+        try {
+            Method m = BluetoothDevice.class.getDeclaredMethod("getKeyMissingCount");
+            return (int) m.invoke(device);
+        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+            Log.w(TAG, "error happens when getKeyMissingCount.");
+            return null;
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
index 88bccc9..2ed437c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
@@ -509,6 +509,7 @@
                     val intent = AdvancedProtectionManager.createSupportIntent(
                         AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP,
                         AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION)
+                    intent.putExtra(DIALOG_WINDOW_TYPE, dialogWindowType)
                     onStartActivity(intent)
                 } else if (wifiManager.isWepSupported == true && wifiManager.queryWepAllowed()) {
                     onAllowed()
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
index dbbbd5b..f9769fa 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
@@ -23,6 +23,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.atMostOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -130,7 +131,7 @@
 
     @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API)
     @Test
-    public void bindPreference_disabled_byAdvancedProtection_shouldDisplayDisabledSummary() {
+    public void bindPreference_disabled_byAdvancedProtection_shouldKeepExistingSummary() {
         final TextView summaryView = mock(TextView.class, RETURNS_DEEP_STUBS);
         final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS;
         final RestrictedLockUtils.EnforcedAdmin enforcedAdmin = new RestrictedLockUtils
@@ -143,16 +144,14 @@
                 .thenReturn(summaryView);
         when(mDevicePolicyManager.getEnforcingAdmin(UserHandle.myUserId(), userRestriction))
                 .thenReturn(advancedProtectionEnforcingAdmin);
-        when(mContext.getString(
-                com.android.settingslib.widget.restricted.R.string.disabled_by_advanced_protection))
-                .thenReturn("advanced_protection");
 
+        summaryView.setText("existing summary");
         mHelper.useAdminDisabledSummary(true);
         mHelper.setDisabledByAdmin(enforcedAdmin);
         mHelper.onBindViewHolder(mViewHolder);
 
-        verify(summaryView).setText("advanced_protection");
-        verify(summaryView, never()).setVisibility(View.GONE);
+        verify(summaryView, atMostOnce()).setText(any()); // To set it to existing summary
+        verify(summaryView, never()).setVisibility(View.VISIBLE);
     }
 
     @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index 3d16d6f..c387d48b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -507,4 +507,25 @@
         assertThat(mPhoneMediaDevice.getSelectionBehavior()).isEqualTo(
                 SELECTION_BEHAVIOR_TRANSFER);
     }
+
+    @Test
+    public void getSelectionBehavior_withRouteListingPreferenceItem_returnPreferenceBehavior() {
+        mItem =
+                new RouteListingPreference.Item.Builder(DEVICE_ADDRESS_1)
+                        .setSelectionBehavior(SELECTION_BEHAVIOR_GO_TO_APP)
+                        .build();
+        MediaDevice castMediaDevice = new ComplexMediaDevice(mContext, mRouteInfo1, mItem);
+
+        assertThat(castMediaDevice.hasRouteListingPreferenceItem()).isTrue();
+        assertThat(castMediaDevice.getSelectionBehavior()).isEqualTo(SELECTION_BEHAVIOR_GO_TO_APP);
+    }
+
+    @Test
+    public void getSelectionBehavior_withoutRouteListingPreferenceItem_returnTransfer() {
+        MediaDevice castMediaDevice =
+                new ComplexMediaDevice(mContext, mRouteInfo1, /* item= */ null);
+
+        assertThat(castMediaDevice.hasRouteListingPreferenceItem()).isFalse();
+        assertThat(castMediaDevice.getSelectionBehavior()).isEqualTo(SELECTION_BEHAVIOR_TRANSFER);
+    }
 }
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index dafcc72..d929b0d 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -187,6 +187,9 @@
     <!-- Default state of tap to wake -->
     <bool name="def_double_tap_to_wake">true</bool>
 
+    <!-- Default setting for double tap to sleep (Settings.Secure.DOUBLE_TAP_TO_SLEEP) -->
+    <bool name="def_double_tap_to_sleep">false</bool>
+
     <!-- Default for Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT -->
     <string name="def_nfc_payment_component"></string>
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index c010529..a229112 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -85,6 +85,7 @@
         Settings.Secure.MOUNT_UMS_PROMPT,
         Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED,
         Settings.Secure.DOUBLE_TAP_TO_WAKE,
+        Settings.Secure.DOUBLE_TAP_TO_SLEEP,
         Settings.Secure.WAKE_GESTURE_ENABLED,
         Settings.Secure.LONG_PRESS_TIMEOUT,
         Settings.Secure.KEY_REPEAT_ENABLED,
@@ -229,6 +230,7 @@
         Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
         Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
+        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
         Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ENABLED,
@@ -266,6 +268,7 @@
         Settings.Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED,
         Settings.Secure.HUB_MODE_TUTORIAL_STATE,
         Settings.Secure.GLANCEABLE_HUB_ENABLED,
+        Settings.Secure.WHEN_TO_START_GLANCEABLE_HUB,
         Settings.Secure.STYLUS_BUTTONS_ENABLED,
         Settings.Secure.STYLUS_HANDWRITING_ENABLED,
         Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
@@ -293,5 +296,7 @@
         Settings.Secure.FINGERPRINT_APP_ENABLED,
         Settings.Secure.FINGERPRINT_KEYGUARD_ENABLED,
         Settings.Secure.DUAL_SHADE,
+        Settings.Secure.BROWSER_CONTENT_FILTERS_ENABLED,
+        Settings.Secure.SEARCH_CONTENT_FILTERS_ENABLED,
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 0ffdf53..a432534 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -131,6 +131,7 @@
         VALIDATORS.put(Secure.MOUNT_UMS_PROMPT, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.MOUNT_UMS_NOTIFY_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DOUBLE_TAP_TO_WAKE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOUBLE_TAP_TO_SLEEP, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.WAKE_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.LONG_PRESS_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.KEY_REPEAT_ENABLED, BOOLEAN_VALIDATOR);
@@ -323,6 +324,10 @@
                         Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL));
         VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE,
+                new InclusiveIntegerRangeValidator(
+                        Secure.ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CONTINUOUS,
+                        Secure.ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_EDGE));
         VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
@@ -429,6 +434,8 @@
         VALIDATORS.put(Secure.DND_CONFIGS_MIGRATED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.HUB_MODE_TUTORIAL_STATE, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.GLANCEABLE_HUB_ENABLED, new InclusiveIntegerRangeValidator(0, 1));
+        VALIDATORS.put(Secure.WHEN_TO_START_GLANCEABLE_HUB,
+                new InclusiveIntegerRangeValidator(0, 3));
         VALIDATORS.put(Secure.STYLUS_BUTTONS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.STYLUS_HANDWRITING_ENABLED,
                 new DiscreteValueValidator(new String[] {"-1", "0", "1"}));
@@ -461,5 +468,7 @@
         VALIDATORS.put(Secure.FINGERPRINT_APP_ENABLED,  BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.FINGERPRINT_KEYGUARD_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DUAL_SHADE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.BROWSER_CONTENT_FILTERS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SEARCH_CONTENT_FILTERS_ENABLED, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index de7c450..7c975b7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -72,6 +72,7 @@
 public final class DeviceConfigService extends Binder {
     private static final List<String> sAconfigTextProtoFilesOnDevice = List.of(
             "/system/etc/aconfig_flags.pb",
+            "/system_ext/etc/aconfig_flags.pb",
             "/product/etc/aconfig_flags.pb",
             "/vendor/etc/aconfig_flags.pb");
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e07832e..57facda 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1881,6 +1881,10 @@
                 SecureSettingsProto.Accessibility
                         .ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED);
         dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE,
+                SecureSettingsProto.Accessibility
+                        .ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE);
+        dumpSetting(s, p,
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
                 SecureSettingsProto.Accessibility
                         .ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index bc281ee..65ede9d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -396,6 +396,8 @@
 
     private volatile SystemConfigManager mSysConfigManager;
 
+    private PackageMonitor mPackageMonitor;
+
     @GuardedBy("mLock")
     private boolean mSyncConfigDisabledUntilReboot;
 
@@ -403,6 +405,7 @@
     @EnabledSince(targetSdkVersion=android.os.Build.VERSION_CODES.S)
     private static final long ENFORCE_READ_PERMISSION_FOR_MULTI_SIM_DATA_CALL = 172670679L;
 
+
     @Override
     public boolean onCreate() {
         Settings.setInSystemServer();
@@ -1036,7 +1039,7 @@
             }
         }, userFilter);
 
-        PackageMonitor monitor = new PackageMonitor() {
+        mPackageMonitor = new PackageMonitor() {
             @Override
             public void onPackageRemoved(String packageName, int uid) {
                 synchronized (mLock) {
@@ -1062,7 +1065,7 @@
         };
 
         // package changes
-        monitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
+        mPackageMonitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
                 UserHandle.ALL, true);
     }
 
@@ -4077,7 +4080,7 @@
 
         @VisibleForTesting
         final class UpgradeController {
-            private static final int SETTINGS_VERSION = 227;
+            private static final int SETTINGS_VERSION = 228;
 
             private final int mUserId;
 
@@ -6316,6 +6319,23 @@
                     currentVersion = 227;
                 }
 
+                // Version 227: Add default value for DOUBLE_TAP_TO_SLEEP.
+                if (currentVersion == 227) {
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final Setting doubleTapToSleep = secureSettings.getSettingLocked(
+                            Settings.Secure.DOUBLE_TAP_TO_SLEEP);
+                    if (doubleTapToSleep.isNull()) {
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
+                                Settings.Secure.DOUBLE_TAP_TO_SLEEP,
+                                getContext().getResources().getBoolean(
+                                        R.bool.def_double_tap_to_sleep) ? "1" : "0",
+                                null /* tag */,
+                                true /* makeDefault */,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 228;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 99c4e21c..17c13b7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -158,6 +158,7 @@
 
     private static final List<String> sAconfigTextProtoFilesOnDevice = List.of(
             "/system/etc/aconfig_flags.pb",
+            "/system_ext/etc/aconfig_flags.pb",
             "/product/etc/aconfig_flags.pb",
             "/vendor/etc/aconfig_flags.pb");
 
diff --git a/packages/Shell/res/values-et/strings.xml b/packages/Shell/res/values-et/strings.xml
index 48c7334..c18687f 100644
--- a/packages/Shell/res/values-et/strings.xml
+++ b/packages/Shell/res/values-et/strings.xml
@@ -21,7 +21,7 @@
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Luuakse veaaruannet <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Jäädvustati veaaruanne <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Üksikasjade lisamine veaaruandesse"</string>
-    <string name="bugreport_updating_wait" msgid="3322151947853929470">"Oodake …"</string>
+    <string name="bugreport_updating_wait" msgid="3322151947853929470">"Palun oodake…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Veaaruanne kuvatakse telefonis peagi"</string>
     <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Veaaruande jagamiseks valige"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Veaaruande jagamiseks puudutage"</string>
diff --git a/packages/SystemUI/aconfig/predictive_back.aconfig b/packages/SystemUI/aconfig/predictive_back.aconfig
index ee918c2..dd9a8b1 100644
--- a/packages/SystemUI/aconfig/predictive_back.aconfig
+++ b/packages/SystemUI/aconfig/predictive_back.aconfig
@@ -7,3 +7,13 @@
     description: "Enable Shade Animations"
     bug: "327732946"
 }
+
+flag {
+    name: "predictive_back_delay_wm_transition"
+    namespace: "systemui"
+    description: "Slightly delays the back transition start"
+    bug: "301195601"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a900817..42f576a 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -292,6 +292,17 @@
 }
 
 flag {
+  name: "notification_row_accessibility_expanded"
+  namespace: "systemui"
+  description: "Prepare ExpandableNotificationRow for new A11y expansion APIs."
+  bug: "380027122"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+
+flag {
     name: "scene_container"
     namespace: "systemui"
     description: "Enables the scene container framework go/flexiglass."
@@ -2102,4 +2113,11 @@
     metadata {
         purpose: PURPOSE_BUGFIX
     }
-}
\ No newline at end of file
+}
+
+flag {
+    name: "move_transition_animation_layer"
+    namespace: "systemui"
+    description: "Enables moving the launching window on top of the origin window in the Animation library."
+    bug: "390422470"
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index f03bd3d..e43b8a0 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -62,6 +62,7 @@
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.systemui.Flags.activityTransitionUseLargestWindow
+import com.android.systemui.Flags.moveTransitionAnimationLayer
 import com.android.systemui.Flags.translucentOccludingActivityFix
 import com.android.systemui.animation.TransitionAnimator.Companion.assertLongLivedReturnAnimations
 import com.android.systemui.animation.TransitionAnimator.Companion.assertReturnAnimations
@@ -1514,6 +1515,20 @@
                             )
                         }
 
+                        if (moveTransitionAnimationLayer()) {
+                            // Ensure that the launching window is rendered above the view's window,
+                            // so it is not obstructed.
+                            // TODO(b/397180418): re-use the start transaction once the
+                            //  RemoteAnimation wrapper is cleaned up.
+                            SurfaceControl.Transaction().use {
+                                it.reparent(
+                                    window.leash,
+                                    controller.transitionContainer.viewRootImpl.surfaceControl,
+                                )
+                                it.apply()
+                            }
+                        }
+
                         if (startTransaction != null) {
                             // Calling applyStateToWindow() here avoids skipping a frame when taking
                             // over an animation.
@@ -1566,12 +1581,18 @@
                 } else {
                     null
                 }
+            val fadeWindowBackgroundLayer =
+                if (moveTransitionAnimationLayer()) {
+                    false
+                } else {
+                    !controller.isBelowAnimatingWindow
+                }
             animation =
                 transitionAnimator.startAnimation(
                     controller,
                     endState,
                     windowBackgroundColor,
-                    fadeWindowBackgroundLayer = !controller.isBelowAnimatingWindow,
+                    fadeWindowBackgroundLayer = fadeWindowBackgroundLayer,
                     drawHole = !controller.isBelowAnimatingWindow,
                     startVelocity = velocityPxPerS,
                     startFrameTime = windowState?.timestamp ?: -1,
@@ -1685,7 +1706,7 @@
             // fade in progressively. Otherwise, it should be fully opaque and will be progressively
             // revealed as the window background color layer above the window fades out.
             val alpha =
-                if (controller.isBelowAnimatingWindow) {
+                if (moveTransitionAnimationLayer() || controller.isBelowAnimatingWindow) {
                     if (controller.isLaunching) {
                         interpolators.contentAfterFadeInInterpolator.getInterpolation(
                             windowProgress
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt
index f4e0361..e734dd2 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt
@@ -25,6 +25,7 @@
 )
 
 object GSFAxes {
+    @JvmStatic
     val WEIGHT =
         AxisDefinition(
             tag = "wght",
@@ -91,8 +92,8 @@
 
     private val AXIS_MAP =
         listOf(WEIGHT, WIDTH, SLANT, ROUND, GRADE, OPTICAL_SIZE, ITALIC)
-            .map { def -> def.tag.toLowerCase() to def }
+            .map { def -> def.tag.lowercase() to def }
             .toMap()
 
-    fun getAxis(axis: String): AxisDefinition? = AXIS_MAP[axis.toLowerCase()]
+    fun getAxis(axis: String): AxisDefinition? = AXIS_MAP[axis.lowercase()]
 }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 5b073e4..4a39cff 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -39,6 +39,7 @@
     fun getTypefaceForVariant(fvar: String?): Typeface?
 
     companion object {
+        @JvmStatic
         fun createVariantTypeface(baseTypeface: Typeface, fVar: String?): Typeface {
             if (fVar.isNullOrEmpty()) {
                 return baseTypeface
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index 4e889e9..5d9c441 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -39,6 +39,7 @@
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.dynamicanimation.animation.SpringAnimation
 import com.android.internal.dynamicanimation.animation.SpringForce
+import com.android.systemui.Flags.moveTransitionAnimationLayer
 import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
 import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived
 import java.util.concurrent.Executor
@@ -509,6 +510,8 @@
      * punching a hole in the [transition container][Controller.transitionContainer]) iff [drawHole]
      * is true.
      *
+     * TODO(b/397646693): remove drawHole altogether.
+     *
      * If [startVelocity] (expressed in pixels per second) is not null, a multi-spring animation
      * using it for the initial momentum will be used instead of the default interpolators. In this
      * case, [startFrameTime] (if non-negative) represents the frame time at which the springs
@@ -1183,6 +1186,10 @@
                 if (drawHole) {
                     drawable.setXfermode(SRC_MODE)
                 }
+            } else if (moveTransitionAnimationLayer() && fadeOutProgress >= 1 && drawHole) {
+                // If [drawHole] is true, draw it once the opening content is done fading in.
+                drawable.alpha = 0x00
+                drawable.setXfermode(SRC_MODE)
             } else {
                 drawable.alpha = 0xFF
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/PagerDots.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt
rename to packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/PagerDots.kt
index 91f1477..172d88a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/PagerDots.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.ui.compose
+package com.android.systemui.common.ui.compose
 
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.foundation.Canvas
@@ -43,9 +43,9 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
+import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlin.math.absoluteValue
 import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 import platform.test.motion.compose.values.MotionTestValueKey
 import platform.test.motion.compose.values.motionTestValues
 
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 4e1aab5..3150e94 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
@@ -182,7 +182,7 @@
         viewModel.communalBackground.collectAsStateWithLifecycle(
             initialValue = CommunalBackgroundType.ANIMATED
         )
-    val swipeToHubEnabled by viewModel.swipeToHubEnabled.collectAsStateWithLifecycle()
+    val swipeToHubEnabled by viewModel.swipeToHubEnabled.collectAsStateWithLifecycle(false)
     val state: MutableSceneTransitionLayoutState =
         rememberMutableSceneTransitionLayoutState(
             initialScene = currentSceneKey,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index 547461e..542f081 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -49,7 +49,10 @@
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.modifiers.thenIf
 import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
+import com.android.systemui.brightness.ui.compose.ContainerColors
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.lifecycle.rememberViewModel
@@ -257,8 +260,12 @@
 
             BrightnessSliderContainer(
                 viewModel = viewModel.brightnessSliderViewModel,
-                containerColor = OverlayShade.Colors.PanelBackground,
-                modifier = Modifier.systemGestureExclusionInShade().fillMaxWidth(),
+                containerColors = ContainerColors.singleColor(OverlayShade.Colors.PanelBackground),
+                modifier =
+                    Modifier.systemGestureExclusionInShade(
+                            enabled = { layoutState.transitionState is TransitionState.Idle }
+                        )
+                        .fillMaxWidth(),
             )
 
             Box {
@@ -289,18 +296,20 @@
      * right.
      */
     @Composable
-    fun Modifier.systemGestureExclusionInShade(): Modifier {
+    fun Modifier.systemGestureExclusionInShade(enabled: () -> Boolean): Modifier {
         val density = LocalDensity.current
-        return systemGestureExclusion { layoutCoordinates ->
-            val sidePadding = with(density) { Dimensions.Padding.toPx() }
-            Rect(
-                offset = Offset(x = -sidePadding, y = 0f),
-                size =
-                    Size(
-                        width = layoutCoordinates.size.width.toFloat() + 2 * sidePadding,
-                        height = layoutCoordinates.size.height.toFloat(),
-                    ),
-            )
+        return thenIf(enabled()) {
+            Modifier.systemGestureExclusion { layoutCoordinates ->
+                val sidePadding = with(density) { Dimensions.Padding.toPx() }
+                Rect(
+                    offset = Offset(x = -sidePadding, y = 0f),
+                    size =
+                        Size(
+                            width = layoutCoordinates.size.width.toFloat() + 2 * sidePadding,
+                            height = layoutCoordinates.size.height.toFloat(),
+                        ),
+                )
+            }
         }
     }
 }
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 0c502e6..7015f79 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
@@ -56,6 +56,7 @@
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.view.SceneJankMonitor
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import com.android.systemui.shade.ui.composable.OverlayShade
 import com.android.systemui.shade.ui.composable.isFullWidthShade
 import javax.inject.Provider
 
@@ -100,9 +101,13 @@
         rememberActivated(traceName = "sceneJankMonitor") { sceneJankMonitorFactory.create() }
 
     val hapticFeedback = LocalHapticFeedback.current
+    val shadeExpansionMotion = OverlayShade.rememberShadeExpansionMotion()
     val sceneTransitions =
-        remember(hapticFeedback) {
-            transitionsBuilder.build(viewModel.hapticsViewModel.getRevealHaptics(hapticFeedback))
+        remember(hapticFeedback, shadeExpansionMotion) {
+            transitionsBuilder.build(
+                shadeExpansionMotion,
+                viewModel.hapticsViewModel.getRevealHaptics(hapticFeedback),
+            )
         }
 
     val state =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 7fe19fe..9b45ef6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -6,6 +6,7 @@
 import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
 import com.android.compose.animation.scene.transitions
 import com.android.internal.jank.Cuj
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.Scenes
@@ -48,7 +49,10 @@
  * Please keep the list sorted alphabetically.
  */
 class SceneContainerTransitions : SceneContainerTransitionsBuilder {
-    override fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions {
+    override fun build(
+        shadeExpansionMotion: EdgeContainerExpansionSpec,
+        revealHaptics: ContainerRevealHaptics,
+    ): SceneTransitions {
         return transitions {
             interruptionHandler = DefaultInterruptionHandler
 
@@ -201,13 +205,19 @@
                 Overlays.NotificationsShade,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toNotificationsShadeTransition(revealHaptics = revealHaptics)
+                toNotificationsShadeTransition(
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             to(
                 Overlays.QuickSettingsShade,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toQuickSettingsShadeTransition(revealHaptics = revealHaptics)
+                toQuickSettingsShadeTransition(
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             from(
                 Scenes.Gone,
@@ -215,7 +225,11 @@
                 key = SlightlyFasterShadeCollapse,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toNotificationsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
+                toNotificationsShadeTransition(
+                    durationScale = 0.9,
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             from(
                 Scenes.Gone,
@@ -223,7 +237,11 @@
                 key = SlightlyFasterShadeCollapse,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toQuickSettingsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
+                toQuickSettingsShadeTransition(
+                    durationScale = 0.9,
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             from(
                 Scenes.Lockscreen,
@@ -231,7 +249,11 @@
                 key = SlightlyFasterShadeCollapse,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toNotificationsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
+                toNotificationsShadeTransition(
+                    durationScale = 0.9,
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             from(
                 Scenes.Lockscreen,
@@ -239,7 +261,11 @@
                 key = SlightlyFasterShadeCollapse,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toQuickSettingsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
+                toQuickSettingsShadeTransition(
+                    durationScale = 0.9,
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
         }
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt
index 13d3456..eb5548d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt
@@ -19,6 +19,7 @@
 import com.android.compose.animation.scene.SceneTransitions
 import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
 import com.android.compose.animation.scene.transitions
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 
 /**
  * Builder of the comprehensive definition of all transitions between scenes and overlays in the
@@ -27,7 +28,10 @@
 interface SceneContainerTransitionsBuilder {
 
     /** Build the [SceneContainer] transitions spec. */
-    fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions
+    fun build(
+        shadeExpansionMotion: EdgeContainerExpansionSpec,
+        revealHaptics: ContainerRevealHaptics,
+    ): SceneTransitions
 }
 
 /**
@@ -37,5 +41,8 @@
 class ConstantSceneContainerTransitionsBuilder(
     private val transitions: SceneTransitions = transitions { /* No transitions */ }
 ) : SceneContainerTransitionsBuilder {
-    override fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions = transitions
+    override fun build(
+        shadeExpansionMotion: EdgeContainerExpansionSpec,
+        revealHaptics: ContainerRevealHaptics,
+    ): SceneTransitions = transitions
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
index 722af6a..9b4b91e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
@@ -20,6 +20,7 @@
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
 import com.android.compose.animation.scene.reveal.verticalContainerReveal
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys
 import com.android.systemui.notifications.ui.composable.NotificationsShade
 import com.android.systemui.scene.shared.model.Overlays
@@ -28,6 +29,7 @@
 
 fun TransitionBuilder.toNotificationsShadeTransition(
     durationScale: Double = 1.0,
+    shadeExpansionMotion: EdgeContainerExpansionSpec,
     revealHaptics: ContainerRevealHaptics,
 ) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
@@ -38,7 +40,7 @@
         elevateInContent = Overlays.NotificationsShade,
     )
 
-    verticalContainerReveal(NotificationsShade.Elements.Panel, revealHaptics)
+    verticalContainerReveal(NotificationsShade.Elements.Panel, shadeExpansionMotion, revealHaptics)
 
     fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
     fractionRange(start = .5f) { fade(NotificationsShade.Elements.StatusBar) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
index 3cce997..47dd85f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
@@ -20,17 +20,19 @@
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
 import com.android.compose.animation.scene.reveal.verticalContainerReveal
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 import com.android.systemui.qs.ui.composable.QuickSettingsShade
 import com.android.systemui.shade.ui.composable.OverlayShade
 import kotlin.time.Duration.Companion.milliseconds
 
 fun TransitionBuilder.toQuickSettingsShadeTransition(
     durationScale: Double = 1.0,
+    shadeExpansionMotion: EdgeContainerExpansionSpec,
     revealHaptics: ContainerRevealHaptics,
 ) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
 
-    verticalContainerReveal(QuickSettingsShade.Elements.Panel, revealHaptics)
+    verticalContainerReveal(QuickSettingsShade.Elements.Panel, shadeExpansionMotion, revealHaptics)
 
     fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
     fractionRange(start = .5f) { fade(QuickSettingsShade.Elements.StatusBar) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 7e7b629..3446081 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -37,24 +37,26 @@
 import androidx.compose.foundation.layout.waterfall
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.overscroll
-import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ContentScope
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexContentPicker
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
+import com.android.mechanics.behavior.edgeContainerExpansionBackground
 import com.android.systemui.res.R
-import androidx.compose.ui.unit.Dp
+import com.android.systemui.shade.ui.composable.OverlayShade.rememberShadeExpansionMotion
 
 /** Renders a lightweight shade UI container, as an overlay. */
 @Composable
@@ -110,23 +112,15 @@
 ) {
     Box(
         modifier =
-            modifier.clip(OverlayShade.Shapes.RoundedCornerPanel).disableSwipesWhenScrolling()
+            modifier
+                .disableSwipesWhenScrolling()
+                .edgeContainerExpansionBackground(
+                    OverlayShade.Colors.PanelBackground,
+                    rememberShadeExpansionMotion(),
+                )
     ) {
-        Spacer(
-            modifier =
-                Modifier.element(OverlayShade.Elements.PanelBackground)
-                    .matchParentSize()
-                    .background(
-                        color = OverlayShade.Colors.PanelBackground,
-                        shape = OverlayShade.Shapes.RoundedCornerPanel,
-                    )
-        )
-
         Column {
             header?.invoke()
-
-            // This content is intentionally rendered as a separate element from the background in
-            // order to allow for more flexibility when defining transitions.
             content()
         }
     }
@@ -192,8 +186,6 @@
                 contentPicker = LowestZIndexContentPicker,
                 placeAllCopies = true,
             )
-        val PanelBackground =
-            ElementKey("OverlayShadePanelBackground", contentPicker = LowestZIndexContentPicker)
     }
 
     object Colors {
@@ -205,13 +197,13 @@
     object Dimensions {
         val PanelCornerRadius: Dp
             @Composable
-            @ReadOnlyComposable get() =
-                dimensionResource(R.dimen.overlay_shade_panel_shape_radius)
+            @ReadOnlyComposable
+            get() = dimensionResource(R.dimen.overlay_shade_panel_shape_radius)
     }
 
-    object Shapes {
-        val RoundedCornerPanel: RoundedCornerShape
-            @Composable
-            @ReadOnlyComposable get() = RoundedCornerShape(Dimensions.PanelCornerRadius)
+    @Composable
+    fun rememberShadeExpansionMotion(): EdgeContainerExpansionSpec {
+        val radius = Dimensions.PanelCornerRadius
+        return remember(radius) { EdgeContainerExpansionSpec(radius = radius) }
     }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
index 2134510..72f9bd5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
@@ -16,28 +16,20 @@
 
 package com.android.compose.animation.scene.reveal
 
-import androidx.compose.animation.core.AnimationVector1D
-import androidx.compose.animation.core.DeferredTargetAnimation
-import androidx.compose.animation.core.ExperimentalAnimatableApi
-import androidx.compose.animation.core.FiniteAnimationSpec
-import androidx.compose.animation.core.VectorConverter
-import androidx.compose.animation.core.spring
-import androidx.compose.ui.unit.Dp
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.util.fastCoerceAtLeast
-import androidx.compose.ui.util.fastCoerceAtMost
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.OverlayKey
-import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.UserActionDistance
 import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.mechanics.MotionValueInput
+import com.android.compose.animation.scene.mechanics.TransitionScopedMechanicsAdapter
 import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
 import com.android.compose.animation.scene.transformation.PropertyTransformation
 import com.android.compose.animation.scene.transformation.PropertyTransformationScope
-import kotlin.math.roundToInt
+import com.android.mechanics.MotionValue
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 import kotlinx.coroutines.CoroutineScope
 
 interface ContainerRevealHaptics {
@@ -53,9 +45,15 @@
     fun onRevealThresholdCrossed(revealed: Boolean)
 }
 
-/** Animate the reveal of [container] by animating its size. */
+/**
+ * Animate the reveal of [container] by animating its size.
+ *
+ * This implicitly sets the [distance] of the transition to the target size of [container]
+ */
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
 fun TransitionBuilder.verticalContainerReveal(
     container: ElementKey,
+    motionSpec: EdgeContainerExpansionSpec,
     haptics: ContainerRevealHaptics,
 ) {
     // Make the swipe distance be exactly the target height of the container.
@@ -76,188 +74,73 @@
         (targetSizeInToContent?.height ?: targetSizeInFromContent?.height)?.toFloat() ?: 0f
     }
 
-    // TODO(b/376438969): Improve the motion of this gesture using Motion Mechanics.
-
-    // The min distance to swipe before triggering the reveal spring.
-    val distanceThreshold = 80.dp
-
-    // The minimum height of the container.
-    val minHeight = 10.dp
-
-    // The amount removed from the container width at 0% progress.
-    val widthDelta = 140.dp
-
-    // The ratio at which the distance is tracked before reaching the threshold, e.g. if the user
-    // drags 60dp then the height will be 60dp * 0.25f = 15dp.
-    val trackingRatio = 0.25f
-
-    // The max progress starting from which the container should always be visible, even if we are
-    // animating the container out. This is used so that we don't immediately fade out the container
-    // when triggering a one-off animation that hides it.
-    val alphaProgressThreshold = 0.05f
-
-    // The spring animating the size of the container.
-    val sizeSpec = spring<Float>(stiffness = 380f, dampingRatio = 0.9f)
-
-    // The spring animating the alpha of the container.
-    val alphaSpec = spring<Float>(stiffness = 1200f, dampingRatio = 0.99f)
-
-    // Size transformation.
-    transformation(container) {
-        VerticalContainerRevealSizeTransformation(
-            haptics,
-            distanceThreshold,
-            trackingRatio,
-            minHeight,
-            widthDelta,
-            sizeSpec,
-        )
-    }
-
-    // Alpha transformation.
-    transformation(container) {
-        ContainerRevealAlphaTransformation(alphaSpec, alphaProgressThreshold)
-    }
-}
-
-@OptIn(ExperimentalAnimatableApi::class)
-private class VerticalContainerRevealSizeTransformation(
-    private val haptics: ContainerRevealHaptics,
-    private val distanceThreshold: Dp,
-    private val trackingRatio: Float,
-    private val minHeight: Dp,
-    private val widthDelta: Dp,
-    private val spec: FiniteAnimationSpec<Float>,
-) : CustomPropertyTransformation<IntSize> {
-    override val property = PropertyTransformation.Property.Size
-
-    private val widthAnimation = DeferredTargetAnimation(Float.VectorConverter)
-    private val heightAnimation = DeferredTargetAnimation(Float.VectorConverter)
-
-    private var previousHasReachedThreshold: Boolean? = null
-
-    override fun PropertyTransformationScope.transform(
-        content: ContentKey,
-        element: ElementKey,
-        transition: TransitionState.Transition,
-        transitionScope: CoroutineScope,
-    ): IntSize {
-        // The distance to go to 100%. Note that we don't use
-        // TransitionState.HasOverscrollProperties.absoluteDistance because the transition will not
-        // implement HasOverscrollProperties if the transition is triggered and not gesture based.
+    // TODO(b/392534646) Add haptics back
+    val heightInput: MotionValueInput = { progress, content, element ->
         val idleSize = checkNotNull(element.targetSize(content))
-        val userActionDistance = idleSize.height
-        val progress = transition.progressTo(content)
-        val distance = (progress * userActionDistance).fastCoerceAtLeast(0f)
-        val threshold = distanceThreshold.toPx()
-
-        // Width.
-        val widthDelta = widthDelta.toPx()
-        val width =
-            (idleSize.width - widthDelta +
-                    animateSize(
-                        size = widthDelta,
-                        distance = distance,
-                        threshold = threshold,
-                        transitionScope = transitionScope,
-                        animation = widthAnimation,
-                    ))
-                .roundToInt()
-
-        // Height.
-        val minHeight = minHeight.toPx()
-        val height =
-            (
-                // 1) The minimum size of the container.
-                minHeight +
-
-                    // 2) The animated size between the minimum size and the threshold.
-                    animateSize(
-                        size = threshold - minHeight,
-                        distance = distance,
-                        threshold = threshold,
-                        transitionScope = transitionScope,
-                        animation = heightAnimation,
-                    ) +
-
-                    // 3) The remaining height after the threshold, tracking the finger.
-                    (distance - threshold).fastCoerceAtLeast(0f))
-                .roundToInt()
-                .fastCoerceAtMost(idleSize.height)
-
-        // Haptics.
-        val hasReachedThreshold = distance >= threshold
-        if (
-            previousHasReachedThreshold != null &&
-                hasReachedThreshold != previousHasReachedThreshold &&
-                transition.isUserInputOngoing
-        ) {
-            haptics.onRevealThresholdCrossed(revealed = hasReachedThreshold)
-        }
-        previousHasReachedThreshold = hasReachedThreshold
-
-        return IntSize(width = width, height = height)
+        val targetHeight = idleSize.height.toFloat()
+        targetHeight * progress
     }
 
-    /**
-     * Animate a size up to [size], so that it is equal to 0f when distance is 0f and equal to
-     * [size] when `distance >= threshold`, taking the [trackingRatio] into account.
-     */
-    @OptIn(ExperimentalAnimatableApi::class)
-    private fun animateSize(
-        size: Float,
-        distance: Float,
-        threshold: Float,
-        transitionScope: CoroutineScope,
-        animation: DeferredTargetAnimation<Float, AnimationVector1D>,
-    ): Float {
-        val trackingSize = distance.fastCoerceAtMost(threshold) / threshold * size * trackingRatio
-        val springTarget =
-            if (distance >= threshold) {
-                size * (1f - trackingRatio)
-            } else {
-                0f
+    transformation(container) {
+        object : CustomPropertyTransformation<IntSize> {
+            override val property = PropertyTransformation.Property.Size
+
+            val heightValue =
+                TransitionScopedMechanicsAdapter(
+                    computeInput = heightInput,
+                    stableThreshold = MotionValue.StableThresholdSpatial,
+                    label = "verticalContainerReveal::height",
+                ) { _, _ ->
+                    motionSpec.createHeightSpec(motionScheme, density = this)
+                }
+            val widthValue =
+                TransitionScopedMechanicsAdapter(
+                    computeInput = heightInput,
+                    stableThreshold = MotionValue.StableThresholdSpatial,
+                    label = "verticalContainerReveal::width",
+                ) { content, element ->
+                    val idleSize = checkNotNull(element.targetSize(content))
+                    val intrinsicWidth = idleSize.width.toFloat()
+                    motionSpec.createWidthSpec(intrinsicWidth, motionScheme, density = this)
+                }
+
+            override fun PropertyTransformationScope.transform(
+                content: ContentKey,
+                element: ElementKey,
+                transition: TransitionState.Transition,
+                transitionScope: CoroutineScope,
+            ): IntSize {
+
+                val height =
+                    with(heightValue) { update(content, element, transition, transitionScope) }
+                val width =
+                    with(widthValue) { update(content, element, transition, transitionScope) }
+
+                return IntSize(width.toInt(), height.toInt())
             }
-        val springSize = animation.updateTarget(springTarget, transitionScope, spec)
-        return trackingSize + springSize
-    }
-}
-
-@OptIn(ExperimentalAnimatableApi::class)
-private class ContainerRevealAlphaTransformation(
-    private val spec: FiniteAnimationSpec<Float>,
-    private val progressThreshold: Float,
-) : CustomPropertyTransformation<Float> {
-    override val property = PropertyTransformation.Property.Alpha
-    private val alphaAnimation = DeferredTargetAnimation(Float.VectorConverter)
-
-    override fun PropertyTransformationScope.transform(
-        content: ContentKey,
-        element: ElementKey,
-        transition: TransitionState.Transition,
-        transitionScope: CoroutineScope,
-    ): Float {
-        return alphaAnimation.updateTarget(targetAlpha(transition, content), transitionScope, spec)
-    }
-
-    private fun targetAlpha(transition: TransitionState.Transition, content: ContentKey): Float {
-        if (transition.isUserInputOngoing) {
-            return if (transition.progressTo(content) > 0f) 1f else 0f
         }
+    }
 
-        // The transition was committed (the user released their finger), so the alpha depends on
-        // whether we are animating towards the content (showing the container) or away from it
-        // (hiding the container).
-        val isShowingContainer =
-            when (content) {
-                is SceneKey -> transition.currentScene == content
-                is OverlayKey -> transition.currentOverlays.contains(content)
+    transformation(container) {
+        object : CustomPropertyTransformation<Float> {
+
+            override val property = PropertyTransformation.Property.Alpha
+            val alphaValue =
+                TransitionScopedMechanicsAdapter(
+                    computeInput = heightInput,
+                    label = "verticalContainerReveal::alpha",
+                ) { _, _ ->
+                    motionSpec.createAlphaSpec(motionScheme, density = this)
+                }
+
+            override fun PropertyTransformationScope.transform(
+                content: ContentKey,
+                element: ElementKey,
+                transition: TransitionState.Transition,
+                transitionScope: CoroutineScope,
+            ): Float {
+                return with(alphaValue) { update(content, element, transition, transitionScope) }
             }
-
-        return if (isShowingContainer || transition.progressTo(content) >= progressThreshold) {
-            1f
-        } else {
-            0f
         }
     }
 }
diff --git a/packages/SystemUI/compose/scene/tests/goldens/motionValue_interruptedAnimation_completes.json b/packages/SystemUI/compose/scene/tests/goldens/motionValue_interruptedAnimation_completes.json
index ce62ac3..a2f8863 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/motionValue_interruptedAnimation_completes.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/motionValue_interruptedAnimation_completes.json
@@ -24,7 +24,6 @@
     336,
     352,
     368,
-    384,
     "after"
   ],
   "features": [
@@ -38,29 +37,28 @@
         {
           "type": "not_found"
         },
-        175,
-        175,
-        174.00105,
-        149.84001,
-        114.73702,
+        125,
+        125,
+        124.28647,
+        107.02858,
+        81.95502,
         0,
         0,
         0,
         0,
-        10.212692,
-        42.525528,
-        77.174965,
-        106.322296,
-        128.37651,
-        144.09671,
-        154.88022,
-        162.08202,
-        166.79778,
-        169.83923,
-        171.77742,
-        173.00056,
-        173.76627,
-        174.24236,
+        7.2947845,
+        30.375374,
+        55.12497,
+        75.944496,
+        91.69751,
+        102.92622,
+        110.62873,
+        115.772865,
+        119.141266,
+        121.313736,
+        122.69816,
+        123.57184,
+        124.11877,
         {
           "type": "not_found"
         }
diff --git a/packages/SystemUI/compose/scene/tests/goldens/motionValue_withAnimation_prolongsTransition.json b/packages/SystemUI/compose/scene/tests/goldens/motionValue_withAnimation_prolongsTransition.json
index ac09ff3..bda53bbf 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/motionValue_withAnimation_prolongsTransition.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/motionValue_withAnimation_prolongsTransition.json
@@ -24,23 +24,23 @@
       "name": "Foo_yOffset",
       "type": "float",
       "data_points": [
-        175,
-        175,
-        175,
-        175,
-        156.26086,
-        121.784874,
-        88.35684,
-        61.32686,
-        41.302353,
-        27.215454,
-        17.638702,
-        11.284393,
-        7.144104,
-        4.4841614,
-        2.7943878,
-        1.7307587,
-        1.0663452,
+        125,
+        125,
+        125,
+        125,
+        111.61491,
+        86.9892,
+        63.112034,
+        43.8049,
+        29.501678,
+        19.439606,
+        12.599068,
+        8.06028,
+        5.102936,
+        3.2029724,
+        1.9959946,
+        1.2362518,
+        0.761673,
         0
       ]
     }
diff --git a/packages/SystemUI/compose/scene/tests/goldens/motionValue_withoutAnimation_terminatesImmediately.json b/packages/SystemUI/compose/scene/tests/goldens/motionValue_withoutAnimation_terminatesImmediately.json
index 5cf66a4..7def82f 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/motionValue_withoutAnimation_terminatesImmediately.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/motionValue_withoutAnimation_terminatesImmediately.json
@@ -13,12 +13,12 @@
       "name": "Foo_yOffset",
       "type": "float",
       "data_points": [
-        175,
-        145.83333,
-        116.666664,
-        87.5,
-        58.33333,
-        29.166672,
+        125,
+        104.166664,
+        83.33333,
+        62.5,
+        41.666664,
+        20.833336,
         0
       ]
     }
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json
index 2df44091..054b4a1 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json
@@ -20,7 +20,7 @@
           "height": 100
         },
         {
-          "width": 125.14286,
+          "width": 125.2,
           "height": 90
         },
         {
@@ -28,7 +28,7 @@
           "height": 80
         },
         {
-          "width": 175.14285,
+          "width": 175.2,
           "height": 70
         },
         {
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json
index 2b0a954..ad46a8d 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json
@@ -21,7 +21,7 @@
           "height": 100
         },
         {
-          "width": 125.14286,
+          "width": 125.2,
           "height": 90
         },
         {
@@ -29,7 +29,7 @@
           "height": 80
         },
         {
-          "width": 175.14285,
+          "width": 175.2,
           "height": 70
         },
         {
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json
index 027df29..9a97053 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json
@@ -20,7 +20,7 @@
           "height": 60
         },
         {
-          "width": 125.14286,
+          "width": 125.2,
           "height": 60
         },
         {
@@ -28,7 +28,7 @@
           "height": 60
         },
         {
-          "width": 175.14285,
+          "width": 175.2,
           "height": 60
         },
         {
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragFullyClose.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragFullyClose.json
new file mode 100644
index 0000000..0fcdfa3
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragFullyClose.json
@@ -0,0 +1,634 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624,
+    640,
+    656,
+    672,
+    688,
+    704,
+    720,
+    736,
+    752,
+    768,
+    784,
+    800,
+    816,
+    832,
+    848,
+    864,
+    880,
+    896,
+    912,
+    928,
+    944,
+    960
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50.4
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 52.4,
+          "y": 50
+        },
+        {
+          "x": 56,
+          "y": 50
+        },
+        {
+          "x": 58.8,
+          "y": 50
+        },
+        {
+          "x": 60.8,
+          "y": 50
+        },
+        {
+          "x": 62,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 393.2
+        },
+        {
+          "width": 188,
+          "height": 393.2
+        },
+        {
+          "width": 188,
+          "height": 386
+        },
+        {
+          "width": 188,
+          "height": 379.6
+        },
+        {
+          "width": 188,
+          "height": 372.8
+        },
+        {
+          "width": 188,
+          "height": 366.8
+        },
+        {
+          "width": 188,
+          "height": 360.4
+        },
+        {
+          "width": 188,
+          "height": 354
+        },
+        {
+          "width": 188,
+          "height": 347.6
+        },
+        {
+          "width": 188,
+          "height": 341.2
+        },
+        {
+          "width": 188,
+          "height": 341.2
+        },
+        {
+          "width": 188,
+          "height": 334
+        },
+        {
+          "width": 188,
+          "height": 328
+        },
+        {
+          "width": 188,
+          "height": 321.6
+        },
+        {
+          "width": 188,
+          "height": 315.2
+        },
+        {
+          "width": 188,
+          "height": 308.8
+        },
+        {
+          "width": 188,
+          "height": 302.4
+        },
+        {
+          "width": 188,
+          "height": 296
+        },
+        {
+          "width": 188,
+          "height": 289.6
+        },
+        {
+          "width": 188,
+          "height": 289.6
+        },
+        {
+          "width": 188,
+          "height": 282.8
+        },
+        {
+          "width": 188,
+          "height": 276.4
+        },
+        {
+          "width": 188,
+          "height": 270
+        },
+        {
+          "width": 188,
+          "height": 263.6
+        },
+        {
+          "width": 188,
+          "height": 257.2
+        },
+        {
+          "width": 188,
+          "height": 250.8
+        },
+        {
+          "width": 188,
+          "height": 244.4
+        },
+        {
+          "width": 188,
+          "height": 238
+        },
+        {
+          "width": 188,
+          "height": 238
+        },
+        {
+          "width": 188,
+          "height": 231.2
+        },
+        {
+          "width": 188,
+          "height": 224.8
+        },
+        {
+          "width": 188,
+          "height": 218.4
+        },
+        {
+          "width": 188,
+          "height": 212
+        },
+        {
+          "width": 188,
+          "height": 212
+        },
+        {
+          "width": 188,
+          "height": 192.4
+        },
+        {
+          "width": 188,
+          "height": 159.6
+        },
+        {
+          "width": 188,
+          "height": 124.4
+        },
+        {
+          "width": 188,
+          "height": 92.8
+        },
+        {
+          "width": 183.2,
+          "height": 66.4
+        },
+        {
+          "width": 176,
+          "height": 46
+        },
+        {
+          "width": 170.4,
+          "height": 39.2
+        },
+        {
+          "width": 166.8,
+          "height": 36
+        },
+        {
+          "width": 164,
+          "height": 31.6
+        },
+        {
+          "width": 162.4,
+          "height": 26.8
+        },
+        {
+          "width": 161.2,
+          "height": 22
+        },
+        {
+          "width": 160.4,
+          "height": 17.6
+        },
+        {
+          "width": 160,
+          "height": 14
+        },
+        {
+          "width": 160,
+          "height": 10.8
+        },
+        {
+          "width": 160,
+          "height": 8
+        },
+        {
+          "width": 160,
+          "height": 6
+        },
+        {
+          "width": 160,
+          "height": 4.4
+        },
+        {
+          "width": 160,
+          "height": 2.8
+        },
+        {
+          "width": 160,
+          "height": 2
+        },
+        {
+          "width": 160,
+          "height": 1.2
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.9808927,
+        0.8211168,
+        0.61845565,
+        0.43834114,
+        0.29850912,
+        0.19755232,
+        0.12793064,
+        0.08142871,
+        0.051099956,
+        0.031684637,
+        0.019442618,
+        0.011821032,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragHalfClose.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragHalfClose.json
new file mode 100644
index 0000000..3196334
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragHalfClose.json
@@ -0,0 +1,624 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624,
+    640,
+    656,
+    672,
+    688,
+    704,
+    720,
+    736,
+    752,
+    768,
+    784,
+    800,
+    816,
+    832,
+    848,
+    864,
+    880,
+    896,
+    912,
+    928,
+    944
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50.8,
+          "y": 52
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 52.4,
+          "y": 50
+        },
+        {
+          "x": 55.6,
+          "y": 50
+        },
+        {
+          "x": 58.4,
+          "y": 50
+        },
+        {
+          "x": 60.4,
+          "y": 50
+        },
+        {
+          "x": 61.6,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 63.2,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 390
+        },
+        {
+          "width": 188,
+          "height": 390
+        },
+        {
+          "width": 188,
+          "height": 379.2
+        },
+        {
+          "width": 188,
+          "height": 371.2
+        },
+        {
+          "width": 188,
+          "height": 363.2
+        },
+        {
+          "width": 188,
+          "height": 355.2
+        },
+        {
+          "width": 188,
+          "height": 347.2
+        },
+        {
+          "width": 188,
+          "height": 339.2
+        },
+        {
+          "width": 188,
+          "height": 331.2
+        },
+        {
+          "width": 188,
+          "height": 323.2
+        },
+        {
+          "width": 188,
+          "height": 323.2
+        },
+        {
+          "width": 188,
+          "height": 314.8
+        },
+        {
+          "width": 188,
+          "height": 306.8
+        },
+        {
+          "width": 188,
+          "height": 298.8
+        },
+        {
+          "width": 188,
+          "height": 290.8
+        },
+        {
+          "width": 188,
+          "height": 282.8
+        },
+        {
+          "width": 188,
+          "height": 274.8
+        },
+        {
+          "width": 188,
+          "height": 266.8
+        },
+        {
+          "width": 188,
+          "height": 258.8
+        },
+        {
+          "width": 188,
+          "height": 258.8
+        },
+        {
+          "width": 188,
+          "height": 250.4
+        },
+        {
+          "width": 188,
+          "height": 242.4
+        },
+        {
+          "width": 188,
+          "height": 234.4
+        },
+        {
+          "width": 188,
+          "height": 226.4
+        },
+        {
+          "width": 188,
+          "height": 218.4
+        },
+        {
+          "width": 188,
+          "height": 210.4
+        },
+        {
+          "width": 188,
+          "height": 202.4
+        },
+        {
+          "width": 188,
+          "height": 194.4
+        },
+        {
+          "width": 188,
+          "height": 194.4
+        },
+        {
+          "width": 188,
+          "height": 185.6
+        },
+        {
+          "width": 188,
+          "height": 178
+        },
+        {
+          "width": 188,
+          "height": 170
+        },
+        {
+          "width": 188,
+          "height": 161.6
+        },
+        {
+          "width": 188,
+          "height": 161.6
+        },
+        {
+          "width": 188,
+          "height": 144.8
+        },
+        {
+          "width": 188,
+          "height": 118.8
+        },
+        {
+          "width": 188,
+          "height": 92
+        },
+        {
+          "width": 183.6,
+          "height": 68
+        },
+        {
+          "width": 176.8,
+          "height": 48.4
+        },
+        {
+          "width": 171.6,
+          "height": 39.6
+        },
+        {
+          "width": 167.6,
+          "height": 36.8
+        },
+        {
+          "width": 164.8,
+          "height": 32.4
+        },
+        {
+          "width": 162.8,
+          "height": 27.6
+        },
+        {
+          "width": 161.6,
+          "height": 22.8
+        },
+        {
+          "width": 160.8,
+          "height": 18.4
+        },
+        {
+          "width": 160.4,
+          "height": 14.4
+        },
+        {
+          "width": 160,
+          "height": 11.2
+        },
+        {
+          "width": 160,
+          "height": 8.4
+        },
+        {
+          "width": 160,
+          "height": 6.4
+        },
+        {
+          "width": 160,
+          "height": 4.4
+        },
+        {
+          "width": 160,
+          "height": 3.2
+        },
+        {
+          "width": 160,
+          "height": 2
+        },
+        {
+          "width": 160,
+          "height": 1.6
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.9967737,
+        0.86538374,
+        0.66414475,
+        0.47619528,
+        0.32686388,
+        0.21757984,
+        0.14153665,
+        0.09041709,
+        0.05691254,
+        0.035380244,
+        0.02175957,
+        0.01325649,
+        0.008007765,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragOpen.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragOpen.json
new file mode 100644
index 0000000..4b03068
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragOpen.json
@@ -0,0 +1,544 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624,
+    640,
+    656,
+    672,
+    688,
+    704,
+    720,
+    736,
+    752,
+    768,
+    784,
+    800,
+    816
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 61.6,
+          "y": 50
+        },
+        {
+          "x": 60.8,
+          "y": 50
+        },
+        {
+          "x": 59.6,
+          "y": 50
+        },
+        {
+          "x": 58.4,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 56,
+          "y": 50
+        },
+        {
+          "x": 55.2,
+          "y": 50
+        },
+        {
+          "x": 54,
+          "y": 50
+        },
+        {
+          "x": 54,
+          "y": 50
+        },
+        {
+          "x": 52.8,
+          "y": 50
+        },
+        {
+          "x": 51.6,
+          "y": 50
+        },
+        {
+          "x": 50.4,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "width": 162.4,
+          "height": 1.6
+        },
+        {
+          "width": 162.4,
+          "height": 1.6
+        },
+        {
+          "width": 164.8,
+          "height": 3.2
+        },
+        {
+          "width": 166.8,
+          "height": 4.8
+        },
+        {
+          "width": 169.2,
+          "height": 6.4
+        },
+        {
+          "width": 171.6,
+          "height": 8
+        },
+        {
+          "width": 173.6,
+          "height": 9.6
+        },
+        {
+          "width": 176,
+          "height": 11.2
+        },
+        {
+          "width": 178,
+          "height": 12.8
+        },
+        {
+          "width": 180.4,
+          "height": 14.4
+        },
+        {
+          "width": 180.4,
+          "height": 14.4
+        },
+        {
+          "width": 182.8,
+          "height": 16.4
+        },
+        {
+          "width": 185.2,
+          "height": 18
+        },
+        {
+          "width": 187.2,
+          "height": 19.6
+        },
+        {
+          "width": 188,
+          "height": 24.8
+        },
+        {
+          "width": 188,
+          "height": 32.8
+        },
+        {
+          "width": 188,
+          "height": 44
+        },
+        {
+          "width": 188,
+          "height": 57.2
+        },
+        {
+          "width": 188,
+          "height": 70.8
+        },
+        {
+          "width": 188,
+          "height": 78
+        },
+        {
+          "width": 188,
+          "height": 91.2
+        },
+        {
+          "width": 188,
+          "height": 103.2
+        },
+        {
+          "width": 188,
+          "height": 114.4
+        },
+        {
+          "width": 188,
+          "height": 124.4
+        },
+        {
+          "width": 188,
+          "height": 134
+        },
+        {
+          "width": 188,
+          "height": 142.8
+        },
+        {
+          "width": 188,
+          "height": 150.8
+        },
+        {
+          "width": 188,
+          "height": 158.8
+        },
+        {
+          "width": 188,
+          "height": 159.6
+        },
+        {
+          "width": 188,
+          "height": 167.2
+        },
+        {
+          "width": 188,
+          "height": 174
+        },
+        {
+          "width": 188,
+          "height": 180.8
+        },
+        {
+          "width": 188,
+          "height": 187.6
+        },
+        {
+          "width": 188,
+          "height": 187.6
+        },
+        {
+          "width": 188,
+          "height": 207.2
+        },
+        {
+          "width": 188,
+          "height": 240
+        },
+        {
+          "width": 188,
+          "height": 275.2
+        },
+        {
+          "width": 188,
+          "height": 306.8
+        },
+        {
+          "width": 188,
+          "height": 333.2
+        },
+        {
+          "width": 188,
+          "height": 353.6
+        },
+        {
+          "width": 188,
+          "height": 368.8
+        },
+        {
+          "width": 188,
+          "height": 380
+        },
+        {
+          "width": 188,
+          "height": 387.6
+        },
+        {
+          "width": 188,
+          "height": 392.4
+        },
+        {
+          "width": 188,
+          "height": 395.6
+        },
+        {
+          "width": 188,
+          "height": 398
+        },
+        {
+          "width": 188,
+          "height": 398.8
+        },
+        {
+          "width": 188,
+          "height": 399.6
+        },
+        {
+          "width": 188,
+          "height": 400
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        0,
+        0,
+        0,
+        0,
+        0.0067873597,
+        0.0612576,
+        0.19080025,
+        0.39327443,
+        0.5711931,
+        0.70855826,
+        0.8074064,
+        0.8754226,
+        0.9207788,
+        0.95032376,
+        0.9692185,
+        0.98112255,
+        0.9885286,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingClose.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingClose.json
new file mode 100644
index 0000000..10a9ba7
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingClose.json
@@ -0,0 +1,424 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50.4,
+          "y": 50.8
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 51.2,
+          "y": 50
+        },
+        {
+          "x": 55.6,
+          "y": 50
+        },
+        {
+          "x": 58.8,
+          "y": 50
+        },
+        {
+          "x": 60.8,
+          "y": 50
+        },
+        {
+          "x": 62,
+          "y": 50
+        },
+        {
+          "x": 63.2,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 389.6
+        },
+        {
+          "width": 188,
+          "height": 378.8
+        },
+        {
+          "width": 188,
+          "height": 366
+        },
+        {
+          "width": 188,
+          "height": 352
+        },
+        {
+          "width": 188,
+          "height": 352
+        },
+        {
+          "width": 188,
+          "height": 316.8
+        },
+        {
+          "width": 188,
+          "height": 261.2
+        },
+        {
+          "width": 188,
+          "height": 202.8
+        },
+        {
+          "width": 188,
+          "height": 150.8
+        },
+        {
+          "width": 188,
+          "height": 107.6
+        },
+        {
+          "width": 186,
+          "height": 74.4
+        },
+        {
+          "width": 177.2,
+          "height": 49.6
+        },
+        {
+          "width": 170.8,
+          "height": 39.6
+        },
+        {
+          "width": 166.8,
+          "height": 36.8
+        },
+        {
+          "width": 164,
+          "height": 32.4
+        },
+        {
+          "width": 162,
+          "height": 27.6
+        },
+        {
+          "width": 160.8,
+          "height": 22.8
+        },
+        {
+          "width": 160.4,
+          "height": 18.4
+        },
+        {
+          "width": 160,
+          "height": 14.4
+        },
+        {
+          "width": 160,
+          "height": 11.2
+        },
+        {
+          "width": 160,
+          "height": 8.4
+        },
+        {
+          "width": 160,
+          "height": 6
+        },
+        {
+          "width": 160,
+          "height": 4.4
+        },
+        {
+          "width": 160,
+          "height": 3.2
+        },
+        {
+          "width": 160,
+          "height": 2
+        },
+        {
+          "width": 160,
+          "height": 1.2
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.9833227,
+        0.8263634,
+        0.623688,
+        0.44261706,
+        0.3016883,
+        0.1997872,
+        0.12944388,
+        0.08242595,
+        0.051743627,
+        0.032093227,
+        0.019698441,
+        0.0119793415,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingOpen.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingOpen.json
new file mode 100644
index 0000000..d8bf48d
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingOpen.json
@@ -0,0 +1,364 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "x": 62.4,
+          "y": 50
+        },
+        {
+          "x": 61.2,
+          "y": 50
+        },
+        {
+          "x": 59.2,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 54.8,
+          "y": 50
+        },
+        {
+          "x": 52.4,
+          "y": 50
+        },
+        {
+          "x": 52.4,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "width": 163.2,
+          "height": 2
+        },
+        {
+          "width": 166,
+          "height": 4.4
+        },
+        {
+          "width": 170,
+          "height": 6.8
+        },
+        {
+          "width": 174,
+          "height": 10
+        },
+        {
+          "width": 178.4,
+          "height": 13.2
+        },
+        {
+          "width": 183.6,
+          "height": 16.8
+        },
+        {
+          "width": 183.6,
+          "height": 16.8
+        },
+        {
+          "width": 188,
+          "height": 42.4
+        },
+        {
+          "width": 188,
+          "height": 100
+        },
+        {
+          "width": 188,
+          "height": 161.6
+        },
+        {
+          "width": 188,
+          "height": 218
+        },
+        {
+          "width": 188,
+          "height": 265.6
+        },
+        {
+          "width": 188,
+          "height": 303.6
+        },
+        {
+          "width": 188,
+          "height": 332.4
+        },
+        {
+          "width": 188,
+          "height": 354
+        },
+        {
+          "width": 188,
+          "height": 369.2
+        },
+        {
+          "width": 188,
+          "height": 380
+        },
+        {
+          "width": 188,
+          "height": 387.2
+        },
+        {
+          "width": 188,
+          "height": 392
+        },
+        {
+          "width": 188,
+          "height": 395.2
+        },
+        {
+          "width": 188,
+          "height": 397.6
+        },
+        {
+          "width": 188,
+          "height": 398.4
+        },
+        {
+          "width": 188,
+          "height": 398.8
+        },
+        {
+          "width": 188,
+          "height": 399.2
+        },
+        {
+          "width": 188,
+          "height": 399.6
+        },
+        {
+          "width": 188,
+          "height": 399.6
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        0,
+        0,
+        0.008216977,
+        0.06259775,
+        0.19032806,
+        0.39281356,
+        0.57081985,
+        0.7082821,
+        0.80721295,
+        0.8752918,
+        0.9206928,
+        0.95026827,
+        0.9691833,
+        0.98110056,
+        0.988515,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_magneticDetachAndReattach.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_magneticDetachAndReattach.json
new file mode 100644
index 0000000..57bdf3e
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_magneticDetachAndReattach.json
@@ -0,0 +1,744 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624,
+    640,
+    656,
+    672,
+    688,
+    704,
+    720,
+    736,
+    752,
+    768,
+    784,
+    800,
+    816,
+    832,
+    848,
+    864,
+    880,
+    896,
+    912,
+    928,
+    944,
+    960,
+    976,
+    992,
+    1008,
+    1024,
+    1040,
+    1056,
+    1072,
+    1088,
+    1104,
+    1120,
+    1136
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 62,
+          "y": 50
+        },
+        {
+          "x": 61.2,
+          "y": 50
+        },
+        {
+          "x": 60.4,
+          "y": 50
+        },
+        {
+          "x": 59.6,
+          "y": 50
+        },
+        {
+          "x": 58.8,
+          "y": 50
+        },
+        {
+          "x": 58,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 56.4,
+          "y": 50
+        },
+        {
+          "x": 55.6,
+          "y": 50
+        },
+        {
+          "x": 55.2,
+          "y": 50
+        },
+        {
+          "x": 54.4,
+          "y": 50
+        },
+        {
+          "x": 53.6,
+          "y": 50
+        },
+        {
+          "x": 53.2,
+          "y": 50
+        },
+        {
+          "x": 52.8,
+          "y": 50
+        },
+        {
+          "x": 52,
+          "y": 50
+        },
+        {
+          "x": 51.6,
+          "y": 50
+        },
+        {
+          "x": 51.2,
+          "y": 50
+        },
+        {
+          "x": 50.8,
+          "y": 50
+        },
+        {
+          "x": 50.4,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50.4,
+          "y": 50
+        },
+        {
+          "x": 50.8,
+          "y": 50
+        },
+        {
+          "x": 51.2,
+          "y": 50
+        },
+        {
+          "x": 51.6,
+          "y": 50
+        },
+        {
+          "x": 52,
+          "y": 50
+        },
+        {
+          "x": 52.8,
+          "y": 50
+        },
+        {
+          "x": 53.2,
+          "y": 50
+        },
+        {
+          "x": 53.6,
+          "y": 50
+        },
+        {
+          "x": 54.4,
+          "y": 50
+        },
+        {
+          "x": 55.2,
+          "y": 50
+        },
+        {
+          "x": 55.6,
+          "y": 50
+        },
+        {
+          "x": 56.4,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 58,
+          "y": 50
+        },
+        {
+          "x": 58.8,
+          "y": 50
+        },
+        {
+          "x": 59.6,
+          "y": 50
+        },
+        {
+          "x": 60.4,
+          "y": 50
+        },
+        {
+          "x": 61.2,
+          "y": 50
+        },
+        {
+          "x": 62,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "width": 162.4,
+          "height": 1.6
+        },
+        {
+          "width": 164,
+          "height": 2.8
+        },
+        {
+          "width": 166,
+          "height": 4
+        },
+        {
+          "width": 167.6,
+          "height": 5.2
+        },
+        {
+          "width": 169.2,
+          "height": 6.4
+        },
+        {
+          "width": 170.8,
+          "height": 7.6
+        },
+        {
+          "width": 172.4,
+          "height": 8.8
+        },
+        {
+          "width": 174,
+          "height": 10
+        },
+        {
+          "width": 175.2,
+          "height": 10.8
+        },
+        {
+          "width": 176.8,
+          "height": 12
+        },
+        {
+          "width": 178,
+          "height": 12.8
+        },
+        {
+          "width": 179.2,
+          "height": 13.6
+        },
+        {
+          "width": 180.8,
+          "height": 14.8
+        },
+        {
+          "width": 182,
+          "height": 15.6
+        },
+        {
+          "width": 182.8,
+          "height": 16.4
+        },
+        {
+          "width": 184,
+          "height": 17.2
+        },
+        {
+          "width": 184.8,
+          "height": 17.6
+        },
+        {
+          "width": 186,
+          "height": 18.4
+        },
+        {
+          "width": 186.8,
+          "height": 19.2
+        },
+        {
+          "width": 187.6,
+          "height": 19.6
+        },
+        {
+          "width": 188,
+          "height": 21.2
+        },
+        {
+          "width": 188,
+          "height": 24
+        },
+        {
+          "width": 188,
+          "height": 29.6
+        },
+        {
+          "width": 188,
+          "height": 37.2
+        },
+        {
+          "width": 188,
+          "height": 45.6
+        },
+        {
+          "width": 188,
+          "height": 53.6
+        },
+        {
+          "width": 188,
+          "height": 60.4
+        },
+        {
+          "width": 188,
+          "height": 66.4
+        },
+        {
+          "width": 188,
+          "height": 71.2
+        },
+        {
+          "width": 188,
+          "height": 75.2
+        },
+        {
+          "width": 188,
+          "height": 77.6
+        },
+        {
+          "width": 188,
+          "height": 79.6
+        },
+        {
+          "width": 188,
+          "height": 80.4
+        },
+        {
+          "width": 188,
+          "height": 80.8
+        },
+        {
+          "width": 188,
+          "height": 80.4
+        },
+        {
+          "width": 188,
+          "height": 79.2
+        },
+        {
+          "width": 187.6,
+          "height": 78
+        },
+        {
+          "width": 186.8,
+          "height": 76
+        },
+        {
+          "width": 186,
+          "height": 74
+        },
+        {
+          "width": 184.8,
+          "height": 71.6
+        },
+        {
+          "width": 184,
+          "height": 69.2
+        },
+        {
+          "width": 182.8,
+          "height": 66
+        },
+        {
+          "width": 182,
+          "height": 62.8
+        },
+        {
+          "width": 180.8,
+          "height": 59.2
+        },
+        {
+          "width": 179.2,
+          "height": 55.6
+        },
+        {
+          "width": 178,
+          "height": 52
+        },
+        {
+          "width": 176.8,
+          "height": 48
+        },
+        {
+          "width": 175.2,
+          "height": 44
+        },
+        {
+          "width": 174,
+          "height": 40
+        },
+        {
+          "width": 172.4,
+          "height": 39.2
+        },
+        {
+          "width": 170.8,
+          "height": 38.4
+        },
+        {
+          "width": 169.2,
+          "height": 34.8
+        },
+        {
+          "width": 167.6,
+          "height": 30
+        },
+        {
+          "width": 166,
+          "height": 25.2
+        },
+        {
+          "width": 164,
+          "height": 20.4
+        },
+        {
+          "width": 162.4,
+          "height": 16.4
+        },
+        {
+          "width": 160.8,
+          "height": 12.8
+        },
+        {
+          "width": 160,
+          "height": 9.6
+        },
+        {
+          "width": 160,
+          "height": 7.2
+        },
+        {
+          "width": 160,
+          "height": 5.2
+        },
+        {
+          "width": 160,
+          "height": 3.6
+        },
+        {
+          "width": 160,
+          "height": 2.8
+        },
+        {
+          "width": 160,
+          "height": 1.6
+        },
+        {
+          "width": 160,
+          "height": 1.2
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        0,
+        0,
+        0,
+        0,
+        0.012518823,
+        0.0741024,
+        0.2254293,
+        0.42628878,
+        0.5976641,
+        0.7280312,
+        0.82100236,
+        0.8845844,
+        0.9267946,
+        0.95419544,
+        0.9716705,
+        0.98265487,
+        0.98947525,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.9944124,
+        0.9417388,
+        0.8184184,
+        0.6157812,
+        0.4361611,
+        0.2968906,
+        0.19641554,
+        0.12716137,
+        0.080921985,
+        0.050773025,
+        0.03147719,
+        0.019312752,
+        0.011740655,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealCloseTransition.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealCloseTransition.json
new file mode 100644
index 0000000..9aa91c2
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealCloseTransition.json
@@ -0,0 +1,304 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 53.2,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 59.6,
+          "y": 50
+        },
+        {
+          "x": 61.6,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 372
+        },
+        {
+          "width": 188,
+          "height": 312.8
+        },
+        {
+          "width": 188,
+          "height": 246.8
+        },
+        {
+          "width": 188,
+          "height": 185.2
+        },
+        {
+          "width": 188,
+          "height": 133.6
+        },
+        {
+          "width": 188,
+          "height": 93.2
+        },
+        {
+          "width": 181.6,
+          "height": 62.8
+        },
+        {
+          "width": 174,
+          "height": 40.8
+        },
+        {
+          "width": 168.8,
+          "height": 38.4
+        },
+        {
+          "width": 165.2,
+          "height": 34.8
+        },
+        {
+          "width": 162.8,
+          "height": 30
+        },
+        {
+          "width": 161.2,
+          "height": 25.2
+        },
+        {
+          "width": 160.4,
+          "height": 20.4
+        },
+        {
+          "width": 160,
+          "height": 16.4
+        },
+        {
+          "width": 160,
+          "height": 12.8
+        },
+        {
+          "width": 160,
+          "height": 9.6
+        },
+        {
+          "width": 160,
+          "height": 7.2
+        },
+        {
+          "width": 160,
+          "height": 5.2
+        },
+        {
+          "width": 160,
+          "height": 3.6
+        },
+        {
+          "width": 160,
+          "height": 2.8
+        },
+        {
+          "width": 160,
+          "height": 1.6
+        },
+        {
+          "width": 160,
+          "height": 1.2
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.91758585,
+        0.72435355,
+        0.52812576,
+        0.3665868,
+        0.24600428,
+        0.16102076,
+        0.103373945,
+        0.06533456,
+        0.04075712,
+        0.025142312,
+        0.015358448,
+        0.0092999935,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealOpenTransition.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealOpenTransition.json
new file mode 100644
index 0000000..622c29e
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealOpenTransition.json
@@ -0,0 +1,244 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 59.2,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 169.6,
+          "height": 6.8
+        },
+        {
+          "width": 188,
+          "height": 26.8
+        },
+        {
+          "width": 188,
+          "height": 95.6
+        },
+        {
+          "width": 188,
+          "height": 163.2
+        },
+        {
+          "width": 188,
+          "height": 222
+        },
+        {
+          "width": 188,
+          "height": 269.6
+        },
+        {
+          "width": 188,
+          "height": 307.2
+        },
+        {
+          "width": 188,
+          "height": 335.2
+        },
+        {
+          "width": 188,
+          "height": 356
+        },
+        {
+          "width": 188,
+          "height": 370.4
+        },
+        {
+          "width": 188,
+          "height": 380.8
+        },
+        {
+          "width": 188,
+          "height": 387.6
+        },
+        {
+          "width": 188,
+          "height": 392.4
+        },
+        {
+          "width": 188,
+          "height": 395.2
+        },
+        {
+          "width": 188,
+          "height": 397.2
+        },
+        {
+          "width": 188,
+          "height": 398
+        },
+        {
+          "width": 188,
+          "height": 398.8
+        },
+        {
+          "width": 188,
+          "height": 399.2
+        },
+        {
+          "width": 188,
+          "height": 399.2
+        },
+        {
+          "width": 188,
+          "height": 399.6
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        0,
+        0.05698657,
+        0.24197984,
+        0.44158113,
+        0.6097554,
+        0.73685503,
+        0.8271309,
+        0.8886989,
+        0.9294886,
+        0.9559254,
+        0.97276413,
+        0.98333716,
+        0.98989624,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapterTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapterTest.kt
index b9bd115..9d40350 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapterTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapterTest.kt
@@ -70,7 +70,7 @@
 import org.junit.runner.RunWith
 import platform.test.motion.compose.ComposeRecordingSpec
 import platform.test.motion.compose.MotionControl
-import platform.test.motion.compose.createComposeMotionTestRule
+import platform.test.motion.compose.createFixedConfigurationComposeMotionTestRule
 import platform.test.motion.compose.recordMotion
 import platform.test.motion.compose.runTest
 import platform.test.motion.golden.DataPoint
@@ -86,7 +86,7 @@
         createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
 
     private val testScope = TestScope()
-    @get:Rule val motionRule = createComposeMotionTestRule(goldenPaths, testScope)
+    @get:Rule val motionRule = createFixedConfigurationComposeMotionTestRule(goldenPaths, testScope)
     private val composeRule = motionRule.toolkit.composeContentTestRule
 
     @Test
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/reveal/ContentRevealTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/reveal/ContentRevealTest.kt
new file mode 100644
index 0000000..f4e2328
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/reveal/ContentRevealTest.kt
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.reveal
+
+import android.platform.test.annotations.MotionTest
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.TouchInjectionScope
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.swipe
+import androidx.compose.ui.test.swipeDown
+import androidx.compose.ui.test.swipeUp
+import androidx.compose.ui.test.swipeWithVelocity
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.FeatureCaptures.elementAlpha
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutStateForTests
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayoutForTesting
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.featureOfElement
+import com.android.compose.animation.scene.transitions
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
+import com.android.mechanics.behavior.edgeContainerExpansionBackground
+import kotlin.math.sin
+import kotlinx.coroutines.CoroutineScope
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.motion.compose.ComposeFeatureCaptures.dpSize
+import platform.test.motion.compose.ComposeFeatureCaptures.positionInRoot
+import platform.test.motion.compose.ComposeRecordingSpec
+import platform.test.motion.compose.MotionControl
+import platform.test.motion.compose.MotionControlScope
+import platform.test.motion.compose.createFixedConfigurationComposeMotionTestRule
+import platform.test.motion.compose.recordMotion
+import platform.test.motion.compose.runTest
+import platform.test.motion.testing.createGoldenPathManager
+
+@RunWith(AndroidJUnit4::class)
+@MotionTest
+class ContentRevealTest {
+
+    private val goldenPaths =
+        createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
+
+    @get:Rule val motionRule = createFixedConfigurationComposeMotionTestRule(goldenPaths)
+
+    private val fakeHaptics = FakeHaptics()
+
+    @Test
+    fun verticalReveal_triggeredRevealOpenTransition() {
+        assertVerticalContainerRevealMotion(TriggeredRevealMotion(SceneClosed, SceneOpen))
+    }
+
+    @Test
+    fun verticalReveal_triggeredRevealCloseTransition() {
+        assertVerticalContainerRevealMotion(TriggeredRevealMotion(SceneOpen, SceneClosed))
+    }
+
+    @Test
+    fun verticalReveal_gesture_magneticDetachAndReattach() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneClosed) {
+                val gestureDurationMillis = 1000L
+                swipe(
+                    curve = {
+                        val progress = it / gestureDurationMillis.toFloat()
+                        val y = sin(progress * Math.PI).toFloat() * 100.dp.toPx()
+                        Offset(centerX, y)
+                    },
+                    gestureDurationMillis,
+                )
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_dragOpen() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneClosed) {
+                swipeDown(endY = 200.dp.toPx(), durationMillis = 500)
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_flingOpen() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneClosed) {
+                val end = Offset(centerX, 80.dp.toPx())
+                swipeWithVelocity(start = topCenter, end = end, endVelocity = FlingVelocity.toPx())
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_dragFullyClose() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneOpen) {
+                swipeUp(200.dp.toPx(), 0.dp.toPx(), durationMillis = 500)
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_dragHalfClose() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneOpen) {
+                swipeUp(350.dp.toPx(), 100.dp.toPx(), durationMillis = 500)
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_flingClose() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneOpen) {
+                val start = Offset(centerX, 260.dp.toPx())
+                val end = Offset(centerX, 200.dp.toPx())
+                swipeWithVelocity(start, end, FlingVelocity.toPx())
+            }
+        )
+    }
+
+    private interface RevealMotion {
+        val startScene: SceneKey
+    }
+
+    private class TriggeredRevealMotion(
+        override val startScene: SceneKey,
+        val targetScene: SceneKey,
+    ) : RevealMotion
+
+    private class GestureRevealMotion(
+        override val startScene: SceneKey,
+        val gestureControl: TouchInjectionScope.() -> Unit,
+    ) : RevealMotion
+
+    private fun assertVerticalContainerRevealMotion(testInstructions: RevealMotion) =
+        motionRule.runTest {
+            val transitions = transitions {
+                from(SceneClosed, to = SceneOpen) {
+                    verticalContainerReveal(RevealElement, MotionSpec, fakeHaptics)
+                }
+            }
+
+            val state =
+                toolkit.composeContentTestRule.runOnUiThread {
+                    MutableSceneTransitionLayoutStateForTests(
+                        testInstructions.startScene,
+                        transitions,
+                    )
+                }
+            lateinit var coroutineScope: CoroutineScope
+
+            val recordTransition: suspend MotionControlScope.() -> Unit = {
+                when (testInstructions) {
+                    is TriggeredRevealMotion -> {
+                        val transition =
+                            toolkit.composeContentTestRule.runOnUiThread {
+                                state.setTargetScene(
+                                    testInstructions.targetScene,
+                                    animationScope = coroutineScope,
+                                )
+                            }
+                        checkNotNull(transition).second.join()
+                    }
+
+                    is GestureRevealMotion -> {
+                        performTouchInputAsync(
+                            onNodeWithTag("stl"),
+                            testInstructions.gestureControl,
+                        )
+                        awaitCondition { !state.isTransitioning() }
+                    }
+                }
+            }
+            val recordingSpec =
+                ComposeRecordingSpec(
+                    recordBefore = false,
+                    recordAfter = false,
+                    motionControl = MotionControl(recording = recordTransition),
+                ) {
+                    featureOfElement(RevealElement, positionInRoot)
+                    featureOfElement(RevealElement, dpSize)
+                    featureOfElement(RevealElement, elementAlpha)
+                }
+
+            val motion =
+                recordMotion(
+                    content = {
+                        coroutineScope = rememberCoroutineScope()
+                        SceneTransitionLayoutForTesting(
+                            state,
+                            modifier =
+                                Modifier.padding(50.dp)
+                                    .background(Color.Yellow)
+                                    .size(ContainerSize.width, ContainerSize.height + 200.dp)
+                                    .testTag("stl"),
+                        ) {
+                            scene(
+                                SceneClosed,
+                                mapOf(Swipe.Down to SceneOpen),
+                                content = { ClosedContainer() },
+                            )
+                            scene(
+                                SceneOpen,
+                                mapOf(Swipe.Up to SceneClosed),
+                                content = { OpenContainer() },
+                            )
+                        }
+                    },
+                    recordingSpec,
+                )
+
+            assertThat(motion).timeSeriesMatchesGolden()
+        }
+
+    @Composable
+    fun ContentScope.ClosedContainer() {
+        Box(modifier = Modifier.fillMaxSize())
+    }
+
+    @Composable
+    fun ContentScope.OpenContainer() {
+        Box(contentAlignment = Alignment.TopCenter, modifier = Modifier.fillMaxSize()) {
+            Box(
+                modifier =
+                    Modifier.element(RevealElement)
+                        .size(ContainerSize)
+                        .edgeContainerExpansionBackground(Color.DarkGray, MotionSpec)
+            )
+        }
+    }
+
+    private class FakeHaptics : ContainerRevealHaptics {
+        override fun onRevealThresholdCrossed(revealed: Boolean) {}
+    }
+
+    companion object {
+        val ContainerSize = DpSize(200.dp, 400.dp)
+
+        val FlingVelocity = 1000.dp // dp/sec
+
+        val SceneClosed = SceneKey("SceneA")
+        val SceneOpen = SceneKey("SceneB")
+
+        val RevealElement = ElementKey("RevealElement")
+        val MotionSpec = EdgeContainerExpansionSpec()
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
index 0bd51cd..44f2353 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
@@ -111,8 +111,8 @@
     }
 
     companion object {
-        fun transitionStates() = Factory { metadata, actual: TransitionState ->
-            TransitionStateSubject(metadata, actual)
+        fun transitionStates() = Factory { metadata, actual: TransitionState? ->
+            TransitionStateSubject(metadata, actual!!)
         }
     }
 }
@@ -181,8 +181,8 @@
 
     companion object {
         fun sceneTransitions() =
-            Factory { metadata, actual: TransitionState.Transition.ChangeScene ->
-                SceneTransitionSubject(metadata, actual)
+            Factory { metadata, actual: TransitionState.Transition.ChangeScene? ->
+                SceneTransitionSubject(metadata, actual!!)
             }
     }
 }
@@ -202,8 +202,8 @@
 
     companion object {
         fun showOrHideOverlayTransitions() =
-            Factory { metadata, actual: TransitionState.Transition.ShowOrHideOverlay ->
-                ShowOrHideOverlayTransitionSubject(metadata, actual)
+            Factory { metadata, actual: TransitionState.Transition.ShowOrHideOverlay? ->
+                ShowOrHideOverlayTransitionSubject(metadata, actual!!)
             }
     }
 }
@@ -221,8 +221,8 @@
 
     companion object {
         fun replaceOverlayTransitions() =
-            Factory { metadata, actual: TransitionState.Transition.ReplaceOverlay ->
-                ReplaceOverlayTransitionSubject(metadata, actual)
+            Factory { metadata, actual: TransitionState.Transition.ReplaceOverlay? ->
+                ReplaceOverlayTransitionSubject(metadata, actual!!)
             }
     }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
index ea6f208..3b008ac 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
@@ -31,27 +31,21 @@
 import com.android.compose.animation.scene.TransitionRecordingSpec
 import com.android.compose.animation.scene.featureOfElement
 import com.android.compose.animation.scene.recordTransition
-import org.junit.ClassRule
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import platform.test.motion.compose.ComposeFeatureCaptures
-import platform.test.motion.compose.createComposeMotionTestRule
+import platform.test.motion.compose.createFixedConfigurationComposeMotionTestRule
 import platform.test.motion.testing.createGoldenPathManager
-import platform.test.screenshot.ResetDeviceEmulationRule
 
 @RunWith(AndroidJUnit4::class)
 @MotionTest
 class AnchoredSizeTest {
 
-    companion object {
-        @JvmField @ClassRule val cleanupRule: ResetDeviceEmulationRule = ResetDeviceEmulationRule()
-    }
-
     private val goldenPaths =
         createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
 
-    @get:Rule val motionRule = createComposeMotionTestRule(goldenPaths)
+    @get:Rule val motionRule = createFixedConfigurationComposeMotionTestRule(goldenPaths)
 
     @Test
     fun testAnchoredSizeEnter() {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/subjects/DpOffsetSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/subjects/DpOffsetSubject.kt
index ab31038..368a333 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/subjects/DpOffsetSubject.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/subjects/DpOffsetSubject.kt
@@ -49,8 +49,8 @@
         val DefaultTolerance = Dp(.5f)
 
         fun dpOffsets() =
-            Factory<DpOffsetSubject, DpOffset> { metadata, actual ->
-                DpOffsetSubject(metadata, actual)
+            Factory { metadata, actual: DpOffset? ->
+                DpOffsetSubject(metadata, actual!!)
             }
     }
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
index e9e61a7..37acbe2 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
@@ -161,15 +161,7 @@
             }
 
             override fun onThemeChanged(theme: ThemeConfig) {
-                val color =
-                    when {
-                        theme.seedColor != null -> theme.seedColor!!
-                        theme.isDarkTheme ->
-                            clockCtx.resources.getColor(android.R.color.system_accent1_100)
-                        else -> clockCtx.resources.getColor(android.R.color.system_accent2_600)
-                    }
-
-                view.updateColor(color)
+                view.updateColor(theme.getDefaultColor(clockCtx.context))
             }
 
             override fun onFontSettingChanged(fontSizePx: Float) {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 9bb3bac..bc4bdf4 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -17,7 +17,6 @@
 import android.content.res.Resources
 import android.graphics.Color
 import android.graphics.Rect
-import android.graphics.RectF
 import android.icu.text.NumberFormat
 import android.util.TypedValue
 import android.view.LayoutInflater
@@ -29,6 +28,7 @@
 import com.android.systemui.plugins.clocks.ClockAnimations
 import com.android.systemui.plugins.clocks.ClockConfig
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockEventListener
 import com.android.systemui.plugins.clocks.ClockEvents
 import com.android.systemui.plugins.clocks.ClockFaceConfig
 import com.android.systemui.plugins.clocks.ClockFaceController
@@ -102,7 +102,7 @@
         isDarkTheme: Boolean,
         dozeFraction: Float,
         foldFraction: Float,
-        onBoundsChanged: (RectF) -> Unit,
+        clockListener: ClockEventListener?,
     ) {
         largeClock.recomputePadding(null)
 
@@ -149,14 +149,7 @@
                 override fun onThemeChanged(theme: ThemeConfig) {
                     this@DefaultClockFaceController.theme = theme
 
-                    val color =
-                        when {
-                            theme.seedColor != null -> theme.seedColor!!
-                            theme.isDarkTheme ->
-                                resources.getColor(android.R.color.system_accent1_100)
-                            else -> resources.getColor(android.R.color.system_accent2_600)
-                        }
-
+                    val color = theme.getDefaultColor(ctx)
                     if (currentColor == color) {
                         return
                     }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
index 6dfd226..5acd446 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
@@ -16,13 +16,13 @@
 
 package com.android.systemui.shared.clocks
 
-import android.graphics.RectF
 import com.android.systemui.animation.GSFAxes
 import com.android.systemui.customization.R
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.AxisType
 import com.android.systemui.plugins.clocks.ClockConfig
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockEventListener
 import com.android.systemui.plugins.clocks.ClockEvents
 import com.android.systemui.plugins.clocks.ClockFontAxis
 import com.android.systemui.plugins.clocks.ClockFontAxis.Companion.merge
@@ -107,11 +107,11 @@
         isDarkTheme: Boolean,
         dozeFraction: Float,
         foldFraction: Float,
-        onBoundsChanged: (RectF) -> Unit,
+        clockListener: ClockEventListener?,
     ) {
         events.onFontAxesChanged(clockCtx.settings.axes)
         smallClock.run {
-            layerController.onViewBoundsChanged = onBoundsChanged
+            layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
             events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
             animations.doze(dozeFraction)
             animations.fold(foldFraction)
@@ -119,7 +119,7 @@
         }
 
         largeClock.run {
-            layerController.onViewBoundsChanged = onBoundsChanged
+            layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
             events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
             animations.doze(dozeFraction)
             animations.fold(foldFraction)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
index 97004ef..1d963af 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
@@ -229,15 +229,7 @@
             }
 
             override fun onThemeChanged(theme: ThemeConfig) {
-                val color =
-                    when {
-                        theme.seedColor != null -> theme.seedColor!!
-                        theme.isDarkTheme ->
-                            clockCtx.resources.getColor(android.R.color.system_accent1_100)
-                        else -> clockCtx.resources.getColor(android.R.color.system_accent2_600)
-                    }
-
-                view.updateColor(color)
+                view.updateColor(theme.getDefaultColor(clockCtx.context))
                 refreshTime()
             }
 
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index fae17a5..0ec2d18 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -45,6 +45,7 @@
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting.Companion.replace
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting.Companion.toFVar
 import com.android.systemui.plugins.clocks.ClockLogger
+import com.android.systemui.shared.Flags.ambientAod
 import com.android.systemui.shared.clocks.CanvasUtil.translate
 import com.android.systemui.shared.clocks.CanvasUtil.use
 import com.android.systemui.shared.clocks.ClockContext
@@ -330,7 +331,7 @@
         textAnimator.setTextStyle(
             TextAnimator.Style(
                 fVar = if (isDozing) aodFontVariation else lsFontVariation,
-                color = if (isDozing) AOD_COLOR else lockscreenColor,
+                color = if (isDozing && !ambientAod()) AOD_COLOR else lockscreenColor,
                 textSize = if (isDozing) aodFontSizePx else lockScreenPaint.textSize,
             ),
             TextAnimator.Animation(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ExpandHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ExpandHelperTest.java
index 7fb879c..f0c9141 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ExpandHelperTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ExpandHelperTest.java
@@ -32,7 +32,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.animation.AnimatorTestRule;
 import com.android.systemui.flags.FakeFeatureFlagsClassic;
-import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/KairosCoreStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/KairosCoreStartableTest.kt
new file mode 100644
index 0000000..4daf023
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/KairosCoreStartableTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosNetwork
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kairos.toColdConflatedFlow
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.launch
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class KairosCoreStartableTest : SysuiTestCase() {
+
+    @Test
+    fun kairosNetwork_usedBeforeStarted() =
+        testKosmos().useUnconfinedTestDispatcher().runKairosTest {
+            lateinit var activatable: TestActivatable
+            val underTest = KairosCoreStartable(applicationCoroutineScope) { setOf(activatable) }
+            activatable = TestActivatable(underTest)
+
+            // collect from the cold flow before starting the CoreStartable
+            var collectCount = 0
+            testScope.backgroundScope.launch { activatable.coldFlow.collect { collectCount++ } }
+
+            // start the CoreStartable
+            underTest.start()
+
+            // verify emissions are received
+            activatable.emitEvent()
+
+            assertThat(collectCount).isEqualTo(1)
+        }
+
+    private class TestActivatable(network: KairosNetwork) : KairosBuilder by kairosBuilder() {
+        private val emitter = MutableSharedFlow<Unit>()
+        private val events = buildEvents { emitter.toEvents() }
+
+        val coldFlow = events.toColdConflatedFlow(network)
+
+        suspend fun emitEvent() = emitter.emit(Unit)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
index 0b13900..7e4704a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -71,6 +71,7 @@
 import com.android.systemui.bluetooth.qsdialog.DeviceItemType;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.shared.QSSettingsPackageRepository;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
@@ -108,6 +109,7 @@
     private static final String TEST_LABEL = "label";
     private static final int TEST_PRESET_INDEX = 1;
     private static final String TEST_PRESET_NAME = "test_preset";
+    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Mock
@@ -137,6 +139,8 @@
     @Mock
     private HearingDevicesUiEventLogger mUiEventLogger;
     @Mock
+    private QSSettingsPackageRepository mQSSettingsPackageRepository;
+    @Mock
     private CachedBluetoothDevice mCachedDevice;
     @Mock
     private BluetoothDevice mDevice;
@@ -164,6 +168,8 @@
         when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(List.of(mCachedDevice));
         when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
         when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState);
+        when(mQSSettingsPackageRepository.getSettingsPackageName())
+                .thenReturn(SETTINGS_PACKAGE_NAME);
         when(mDevice.getBondState()).thenReturn(BOND_BONDED);
         when(mDevice.isConnected()).thenReturn(true);
         when(mCachedDevice.getDevice()).thenReturn(mDevice);
@@ -195,6 +201,7 @@
                 anyInt(), any());
         assertThat(intentCaptor.getValue().getAction()).isEqualTo(
                 Settings.ACTION_HEARING_DEVICE_PAIRING_SETTINGS);
+        assertThat(intentCaptor.getValue().getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME);
         verify(mUiEventLogger).log(HearingDevicesUiEvent.HEARING_DEVICES_PAIR,
                 TEST_LAUNCH_SOURCE_ID);
     }
@@ -210,6 +217,7 @@
                 anyInt(), any());
         assertThat(intentCaptor.getValue().getAction()).isEqualTo(
                 HearingDevicesDialogDelegate.ACTION_BLUETOOTH_DEVICE_DETAILS);
+        assertThat(intentCaptor.getValue().getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME);
         verify(mUiEventLogger).log(HearingDevicesUiEvent.HEARING_DEVICES_GEAR_CLICK,
                 TEST_LAUNCH_SOURCE_ID);
     }
@@ -392,7 +400,8 @@
                 mExecutor,
                 mExecutor,
                 mAudioManager,
-                mUiEventLogger
+                mUiEventLogger,
+                mQSSettingsPackageRepository
         );
         mDialog = mDialogDelegate.createDialog();
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ActionIntentCreatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ActionIntentCreatorTest.kt
new file mode 100644
index 0000000..239e026
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ActionIntentCreatorTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.clipboardoverlay
+
+import android.content.ClipData
+import android.content.ComponentName
+import android.content.Intent
+import android.net.Uri
+import android.text.SpannableString
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ActionIntentCreatorTest : SysuiTestCase() {
+    val creator = ActionIntentCreator()
+
+    @Test
+    fun test_getTextEditorIntent() {
+        val intent = creator.getTextEditorIntent(context)
+        assertEquals(ComponentName(context, EditTextActivity::class.java), intent.component)
+        assertFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+    }
+
+    @Test
+    fun test_getRemoteCopyIntent() {
+        context.getOrCreateTestableResources().addOverride(R.string.config_remoteCopyPackage, "")
+
+        val clipData = ClipData.newPlainText("Test", "Test Item")
+        var intent = creator.getRemoteCopyIntent(clipData, context)
+
+        assertEquals(null, intent.component)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        assertEquals(clipData, intent.clipData)
+
+        // Try again with a remote copy component
+        val fakeComponent =
+            ComponentName("com.android.remotecopy", "com.android.remotecopy.RemoteCopyActivity")
+        context
+            .getOrCreateTestableResources()
+            .addOverride(R.string.config_remoteCopyPackage, fakeComponent.flattenToString())
+
+        intent = creator.getRemoteCopyIntent(clipData, context)
+        assertEquals(fakeComponent, intent.component)
+    }
+
+    @Test
+    fun test_getImageEditIntent() {
+        context.getOrCreateTestableResources().addOverride(R.string.config_screenshotEditor, "")
+        val fakeUri = Uri.parse("content://foo")
+        var intent = creator.getImageEditIntent(fakeUri, context)
+
+        assertEquals(Intent.ACTION_EDIT, intent.action)
+        assertEquals("image/*", intent.type)
+        assertEquals(null, intent.component)
+        assertEquals("clipboard", intent.getStringExtra("edit_source"))
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+
+        // try again with an editor component
+        val fakeComponent =
+            ComponentName("com.android.remotecopy", "com.android.remotecopy.RemoteCopyActivity")
+        context
+            .getOrCreateTestableResources()
+            .addOverride(R.string.config_screenshotEditor, fakeComponent.flattenToString())
+        intent = creator.getImageEditIntent(fakeUri, context)
+        assertEquals(fakeComponent, intent.component)
+    }
+
+    @Test
+    fun test_getShareIntent_plaintext() {
+        val clipData = ClipData.newPlainText("Test", "Test Item")
+        val intent = creator.getShareIntent(clipData, context)
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.action)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        val target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertEquals("Test Item", target?.getStringExtra(Intent.EXTRA_TEXT))
+        assertEquals("text/plain", target?.type)
+    }
+
+    @Test
+    fun test_getShareIntent_html() {
+        val clipData = ClipData.newHtmlText("Test", "Some HTML", "<b>Some HTML</b>")
+        val intent = creator.getShareIntent(clipData, getContext())
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.action)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        val target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertEquals("Some HTML", target?.getStringExtra(Intent.EXTRA_TEXT))
+        assertEquals("text/plain", target?.type)
+    }
+
+    @Test
+    fun test_getShareIntent_image() {
+        val uri = Uri.parse("content://something")
+        val clipData = ClipData("Test", arrayOf("image/png"), ClipData.Item(uri))
+        val intent = creator.getShareIntent(clipData, context)
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.action)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        val target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertEquals(uri, target?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
+        assertEquals(uri, target?.clipData?.getItemAt(0)?.uri)
+        assertEquals("image/png", target?.type)
+    }
+
+    @Test
+    fun test_getShareIntent_spannableText() {
+        val clipData = ClipData.newPlainText("Test", SpannableString("Test Item"))
+        val intent = creator.getShareIntent(clipData, context)
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.action)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        val target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertEquals("Test Item", target?.getStringExtra(Intent.EXTRA_TEXT))
+        assertEquals("text/plain", target?.type)
+    }
+
+    // Assert that the given flags are set
+    private fun assertFlags(intent: Intent, flags: Int) {
+        assertTrue((intent.flags and flags) == flags)
+    }
+
+    companion object {
+        private const val EXTERNAL_INTENT_FLAGS: Int =
+            (Intent.FLAG_ACTIVITY_NEW_TASK or
+                Intent.FLAG_ACTIVITY_CLEAR_TASK or
+                Intent.FLAG_GRANT_READ_URI_PERMISSION)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/DefaultIntentCreatorTest.java
similarity index 87%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/DefaultIntentCreatorTest.java
index ea6cb3b..126b3fa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/DefaultIntentCreatorTest.java
@@ -36,13 +36,15 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class IntentCreatorTest extends SysuiTestCase {
+public class DefaultIntentCreatorTest extends SysuiTestCase {
     private static final int EXTERNAL_INTENT_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK
             | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION;
 
+    private final DefaultIntentCreator mIntentCreator  = new DefaultIntentCreator();
+
     @Test
     public void test_getTextEditorIntent() {
-        Intent intent = IntentCreator.getTextEditorIntent(getContext());
+        Intent intent = mIntentCreator.getTextEditorIntent(getContext());
         assertEquals(new ComponentName(getContext(), EditTextActivity.class),
                 intent.getComponent());
         assertFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@@ -54,7 +56,7 @@
                 "");
 
         ClipData clipData = ClipData.newPlainText("Test", "Test Item");
-        Intent intent = IntentCreator.getRemoteCopyIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getRemoteCopyIntent(clipData, getContext());
 
         assertEquals(null, intent.getComponent());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
@@ -66,7 +68,7 @@
         getContext().getOrCreateTestableResources().addOverride(R.string.config_remoteCopyPackage,
                 fakeComponent.flattenToString());
 
-        intent = IntentCreator.getRemoteCopyIntent(clipData, getContext());
+        intent = mIntentCreator.getRemoteCopyIntent(clipData, getContext());
         assertEquals(fakeComponent, intent.getComponent());
     }
 
@@ -75,7 +77,7 @@
         getContext().getOrCreateTestableResources().addOverride(R.string.config_screenshotEditor,
                 "");
         Uri fakeUri = Uri.parse("content://foo");
-        Intent intent = IntentCreator.getImageEditIntent(fakeUri, getContext());
+        Intent intent = mIntentCreator.getImageEditIntent(fakeUri, getContext());
 
         assertEquals(Intent.ACTION_EDIT, intent.getAction());
         assertEquals("image/*", intent.getType());
@@ -88,14 +90,14 @@
                 "com.android.remotecopy.RemoteCopyActivity");
         getContext().getOrCreateTestableResources().addOverride(R.string.config_screenshotEditor,
                 fakeComponent.flattenToString());
-        intent = IntentCreator.getImageEditIntent(fakeUri, getContext());
+        intent = mIntentCreator.getImageEditIntent(fakeUri, getContext());
         assertEquals(fakeComponent, intent.getComponent());
     }
 
     @Test
     public void test_getShareIntent_plaintext() {
         ClipData clipData = ClipData.newPlainText("Test", "Test Item");
-        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getShareIntent(clipData, getContext());
 
         assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
@@ -108,7 +110,7 @@
     public void test_getShareIntent_html() {
         ClipData clipData = ClipData.newHtmlText("Test", "Some HTML",
                 "<b>Some HTML</b>");
-        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getShareIntent(clipData, getContext());
 
         assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
@@ -122,7 +124,7 @@
         Uri uri = Uri.parse("content://something");
         ClipData clipData = new ClipData("Test", new String[]{"image/png"},
                 new ClipData.Item(uri));
-        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getShareIntent(clipData, getContext());
 
         assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
@@ -135,7 +137,7 @@
     @Test
     public void test_getShareIntent_spannableText() {
         ClipData clipData = ClipData.newPlainText("Test", new SpannableString("Test Item"));
-        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getShareIntent(clipData, getContext());
 
         assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
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 f47aa6b..8dc7a33 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
@@ -32,6 +32,8 @@
 import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.common.data.repository.batteryRepository
+import com.android.systemui.common.data.repository.fake
 import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
 import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
 import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
@@ -48,6 +50,7 @@
 import com.android.systemui.communal.domain.interactor.communalSceneInteractor
 import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
 import com.android.systemui.communal.domain.interactor.communalTutorialInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.shared.log.CommunalMetricsLogger
 import com.android.systemui.communal.shared.model.CommunalContentSize
@@ -73,6 +76,8 @@
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.keyguard.ui.transitions.blurConfig
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
@@ -96,6 +101,7 @@
 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.settings.fakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.advanceTimeBy
@@ -940,6 +946,36 @@
             assertThat(isUiBlurred).isFalse()
         }
 
+    @Test
+    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+    fun swipeToCommunal() =
+        kosmos.runTest {
+            setCommunalV2ConfigEnabled(true)
+            val mainUser = fakeUserRepository.asMainUser()
+            fakeKeyguardRepository.setKeyguardShowing(true)
+            fakeUserRepository.setUserUnlocked(mainUser.id, true)
+            fakeUserTracker.set(userInfos = listOf(mainUser), selectedUserIndex = 0)
+            fakeSettings.putIntForUser(
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+                1,
+                mainUser.id,
+            )
+
+            val viewModel = createViewModel()
+            val swipeToHubEnabled by collectLastValue(viewModel.swipeToHubEnabled)
+            assertThat(swipeToHubEnabled).isFalse()
+
+            batteryRepository.fake.setDevicePluggedIn(true)
+            assertThat(swipeToHubEnabled).isTrue()
+
+            keyguardTransitionRepository.sendTransitionStep(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.AOD,
+                transitionState = TransitionState.STARTED,
+            )
+            assertThat(swipeToHubEnabled).isFalse()
+        }
+
     private suspend fun setIsMainUser(isMainUser: Boolean) {
         val user = if (isMainUser) MAIN_USER_INFO else SECONDARY_USER_INFO
         with(userRepository) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
index e051500..454c156 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
@@ -56,6 +56,7 @@
 import com.android.systemui.statusbar.phone.screenOffAnimationController
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.advanceTimeBy
@@ -105,7 +106,7 @@
     @Test
     fun nonPowerButtonFPS_vibrateSuccess() =
         testScope.runTest {
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             enrollFingerprint(FingerprintSensorType.UDFPS_ULTRASONIC)
             runCurrent()
             enterDeviceFromFingerprintUnlockLegacy()
@@ -116,7 +117,7 @@
     @Test
     fun powerButtonFPS_vibrateSuccess() =
         testScope.runTest {
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             enrollFingerprint(FingerprintSensorType.POWER_BUTTON)
             kosmos.fakeKeyEventRepository.setPowerButtonDown(false)
 
@@ -133,7 +134,7 @@
     @Test
     fun powerButtonFPS_powerDown_doNotVibrateSuccess() =
         testScope.runTest {
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             enrollFingerprint(FingerprintSensorType.POWER_BUTTON)
             kosmos.fakeKeyEventRepository.setPowerButtonDown(true) // power button is currently DOWN
 
@@ -150,7 +151,7 @@
     @Test
     fun powerButtonFPS_powerButtonRecentlyPressed_doNotVibrateSuccess() =
         testScope.runTest {
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             enrollFingerprint(FingerprintSensorType.POWER_BUTTON)
             kosmos.fakeKeyEventRepository.setPowerButtonDown(false)
 
@@ -174,14 +175,14 @@
         }
 
     @Test
-    fun nonPowerButtonFPS_coExFaceFailure_vibrateError() =
+    fun nonPowerButtonFPS_coExFaceFailure_doNotVibrateError() =
         testScope.runTest {
             val playErrorHaptic by collectLastValue(underTest.playErrorHaptic)
             enrollFingerprint(FingerprintSensorType.UDFPS_ULTRASONIC)
             enrollFace()
             runCurrent()
             faceFailure()
-            assertThat(playErrorHaptic).isNotNull()
+            assertThat(playErrorHaptic).isNull()
         }
 
     @Test
@@ -211,7 +212,7 @@
         testScope.runTest {
             kosmos.configureKeyguardBypass(isBypassAvailable = false)
             underTest = kosmos.deviceEntryHapticsInteractor
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             enrollFingerprint(FingerprintSensorType.UDFPS_ULTRASONIC)
             runCurrent()
             configureDeviceEntryFromBiometricSource(isFpUnlock = true)
@@ -225,7 +226,7 @@
         testScope.runTest {
             kosmos.configureKeyguardBypass(isBypassAvailable = false)
             underTest = kosmos.deviceEntryHapticsInteractor
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             enrollFingerprint(FingerprintSensorType.POWER_BUTTON)
             kosmos.fakeKeyEventRepository.setPowerButtonDown(false)
 
@@ -246,18 +247,19 @@
             enrollFace()
             kosmos.configureKeyguardBypass(isBypassAvailable = true)
             underTest = kosmos.deviceEntryHapticsInteractor
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             configureDeviceEntryFromBiometricSource(isFaceUnlock = true)
             verifyDeviceEntryFromFaceAuth()
             assertThat(playSuccessHaptic).isNotNull()
         }
 
+    @OptIn(ExperimentalCoroutinesApi::class)
     @EnableSceneContainer
     @Test
-    fun playSuccessHaptic_onFaceAuthSuccess_whenBypassDisabled_sceneContainer() =
+    fun skipSuccessHaptic_onFaceAuthSuccess_whenBypassDisabled_sceneContainer() =
         testScope.runTest {
             underTest = kosmos.deviceEntryHapticsInteractor
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
 
             enrollFace()
             kosmos.configureKeyguardBypass(isBypassAvailable = false)
@@ -265,7 +267,7 @@
             configureDeviceEntryFromBiometricSource(isFaceUnlock = true, bypassEnabled = false)
             kosmos.fakeDeviceEntryFaceAuthRepository.isAuthenticated.value = true
 
-            assertThat(playSuccessHaptic).isNotNull()
+            assertThat(playSuccessHaptic).isNull()
         }
 
     @EnableSceneContainer
@@ -274,7 +276,7 @@
         testScope.runTest {
             kosmos.configureKeyguardBypass(isBypassAvailable = false)
             underTest = kosmos.deviceEntryHapticsInteractor
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             enrollFingerprint(FingerprintSensorType.POWER_BUTTON)
             // power button is currently DOWN
             kosmos.fakeKeyEventRepository.setPowerButtonDown(true)
@@ -295,7 +297,7 @@
         testScope.runTest {
             kosmos.configureKeyguardBypass(isBypassAvailable = false)
             underTest = kosmos.deviceEntryHapticsInteractor
-            val playSuccessHaptic by collectLastValue(underTest.playSuccessHaptic)
+            val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
             enrollFingerprint(FingerprintSensorType.POWER_BUTTON)
             kosmos.fakeKeyEventRepository.setPowerButtonDown(false)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt
index 299105e..e41d46c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.dumpManager
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.testKosmos
@@ -29,6 +30,9 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.verify
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
@@ -99,6 +103,11 @@
             assertThat(fakePerDisplayInstanceProviderWithTeardown.destroyed).isEmpty()
         }
 
+    @Test
+    fun start_registersDumpable() {
+        verify(kosmos.dumpManager).registerNormalDumpable(anyString(), eq(underTest))
+    }
+
     private fun createDisplay(displayId: Int): Display =
         display(type = Display.TYPE_INTERNAL, id = displayId)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
index f373062..684af6f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
@@ -57,4 +57,17 @@
             repository.setPowerButtonDown(true)
             assertThat(isPowerDown).isTrue()
         }
+
+    @Test
+    fun testPowerButtonBeingLongPressedInteractor() =
+        runTest {
+            val isPowerButtonLongPressed by collectLastValue(
+                underTest.isPowerButtonLongPressed)
+
+            repository.setPowerButtonBeingLongPressed(false)
+            assertThat(isPowerButtonLongPressed).isFalse()
+
+            repository.setPowerButtonBeingLongPressed(true)
+            assertThat(isPowerButtonLongPressed).isTrue()
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 909acca..573216d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -49,9 +49,9 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SystemUIInitializerImpl;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -177,7 +177,8 @@
     @Test
     public void schedulesAlarm12hBefore() {
         long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(16);
-        AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null);
+        AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours,
+                null);
         mProvider.onNextAlarmChanged(alarmClockInfo);
 
         long twelveHours = TimeUnit.HOURS.toMillis(KeyguardSliceProvider.ALARM_VISIBILITY_HOURS);
@@ -189,7 +190,8 @@
     @Test
     public void updatingNextAlarmInvalidatesSlice() {
         long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(8);
-        AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null);
+        AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours,
+                null);
         mProvider.onNextAlarmChanged(alarmClockInfo);
 
         verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
@@ -204,7 +206,7 @@
     @Test
     public void addZenMode_addedToSlice() {
         ListBuilder listBuilder = spy(new ListBuilder(getContext(), mProvider.getUri(),
-            ListBuilder.INFINITY));
+                ListBuilder.INFINITY));
         mProvider.addZenModeLocked(listBuilder);
         verify(listBuilder, never()).addRow(any(ListBuilder.RowBuilder.class));
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
index c7f1525..9ab5f89 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.keyevent.data.repository.KeyEventRepositoryImpl
 import com.android.systemui.statusbar.CommandQueue
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
@@ -34,10 +35,10 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Captor
 import org.mockito.Mock
-import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class KeyEventRepositoryTest : SysuiTestCase() {
@@ -62,6 +63,15 @@
         }
 
     @Test
+    fun isPowerButtonBeingLongPressed_initialValueFalse() =
+        testScope.runTest {
+            val isPowerButtonLongPressed by collectLastValue(
+                underTest.isPowerButtonLongPressed)
+            runCurrent()
+            assertThat(isPowerButtonLongPressed).isFalse()
+        }
+
+    @Test
     fun isPowerButtonDown_onChange() =
         testScope.runTest {
             val isPowerButtonDown by collectLastValue(underTest.isPowerButtonDown)
@@ -77,4 +87,54 @@
             )
             assertThat(isPowerButtonDown).isFalse()
         }
+
+
+    @Test
+    fun isPowerButtonBeingLongPressed_onPowerButtonDown() =
+        testScope.runTest {
+            val isPowerButtonLongPressed by collectLastValue(
+                underTest.isPowerButtonLongPressed)
+
+            runCurrent()
+
+            verify(commandQueue).addCallback(commandQueueCallbacks.capture())
+
+            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_POWER)
+            commandQueueCallbacks.value.handleSystemKey(keyEvent)
+
+            assertThat(isPowerButtonLongPressed).isFalse()
+        }
+
+    @Test
+    fun isPowerButtonBeingLongPressed_onPowerButtonUp() =
+        testScope.runTest {
+            val isPowerButtonLongPressed by collectLastValue(
+                underTest.isPowerButtonLongPressed)
+
+            runCurrent()
+
+            verify(commandQueue).addCallback(commandQueueCallbacks.capture())
+
+            val keyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_POWER)
+            commandQueueCallbacks.value.handleSystemKey(keyEvent)
+
+            assertThat(isPowerButtonLongPressed).isFalse()
+        }
+
+    @Test
+    fun isPowerButtonBeingLongPressed_onPowerButtonDown_longPressFlagSet() =
+        testScope.runTest {
+            val isPowerButtonBeingLongPressed by collectLastValue(
+                underTest.isPowerButtonLongPressed)
+
+            runCurrent()
+
+            verify(commandQueue).addCallback(commandQueueCallbacks.capture())
+
+            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_POWER)
+            keyEvent.setFlags(KeyEvent.FLAG_LONG_PRESS)
+            commandQueueCallbacks.value.handleSystemKey(keyEvent)
+
+            assertThat(isPowerButtonBeingLongPressed).isTrue()
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt
index 2558d58..89a53f5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt
@@ -49,6 +49,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
 class KeyguardStateCallbackInteractorTest : SysuiTestCase() {
 
     private val kosmos = testKosmos()
@@ -81,7 +82,6 @@
         }
 
     @Test
-    @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
     fun test_lockscreenVisibility_notifyDismissSucceeded_ifNotVisible() =
         testScope.runTest {
             underTest.addCallback(callback)
@@ -109,7 +109,6 @@
         }
 
     @Test
-    @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
     fun test_lockscreenVisibility_reportsKeyguardShowingChanged() =
         testScope.runTest {
             underTest.addCallback(callback)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModelTest.kt
index 8533134..95a6e56 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModelTest.kt
@@ -21,15 +21,20 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags.FLAG_NOTIFICATION_SHADE_BLUR
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.flags.BrokenWithSceneContainer
+import com.android.systemui.flags.DisableSceneContainer
 import com.android.systemui.flags.andSceneContainer
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.keyguard.ui.transitions.blurConfig
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -43,6 +48,7 @@
     SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
+    private val repository = kosmos.fakeKeyguardTransitionRepository
     private lateinit var underTest: OccludedToPrimaryBouncerTransitionViewModel
 
     companion object {
@@ -63,6 +69,25 @@
     }
 
     @Test
+    @DisableSceneContainer
+    fun lockscreenAlphaImmediatelyToZero() =
+        testScope.runTest {
+            val alpha by collectLastValue(underTest.lockscreenAlpha)
+
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+            runCurrent()
+            assertThat(alpha).isEqualTo(0f)
+
+            repository.sendTransitionStep(step(0.1f, TransitionState.RUNNING))
+            runCurrent()
+            assertThat(alpha).isEqualTo(0f)
+
+            repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+            runCurrent()
+            assertThat(alpha).isEqualTo(0f)
+        }
+
+    @Test
     @BrokenWithSceneContainer(388068805)
     fun notificationsAreBlurredImmediatelyWhenBouncerIsOpenedAndShadeIsExpanded() =
         testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/log/LogWtfHandlerRuleTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/LogWtfHandlerRuleTest.kt
new file mode 100644
index 0000000..d5d256e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/LogWtfHandlerRuleTest.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.log
+
+import android.util.Log
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.model.Statement
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class LogWtfHandlerRuleTest : SysuiTestCase() {
+
+    val underTest = LogWtfHandlerRule()
+
+    @Test
+    fun passingTestWithoutWtf_shouldPass() {
+        val result = runTestCodeWithRule {
+            Log.e(TAG, "just an error", IndexOutOfBoundsException())
+        }
+        assertThat(result.isSuccess).isTrue()
+    }
+
+    @Test
+    fun passingTestWithWtf_shouldFail() {
+        val result = runTestCodeWithRule {
+            Log.wtf(TAG, "some terrible failure", IllegalStateException())
+        }
+        assertThat(result.isFailure).isTrue()
+        val exception = result.exceptionOrNull()
+        assertThat(exception).isInstanceOf(AssertionError::class.java)
+        assertThat(exception?.cause).isInstanceOf(Log.TerribleFailure::class.java)
+        assertThat(exception?.cause?.cause).isInstanceOf(IllegalStateException::class.java)
+    }
+
+    @Test
+    fun failingTestWithoutWtf_shouldFail() {
+        val result = runTestCodeWithRule {
+            Log.e(TAG, "just an error", IndexOutOfBoundsException())
+            throw NullPointerException("some npe")
+        }
+        assertThat(result.isFailure).isTrue()
+        assertThat(result.exceptionOrNull()).isInstanceOf(NullPointerException::class.java)
+    }
+
+    @Test
+    fun failingTestWithWtf_shouldFail() {
+        val result = runTestCodeWithRule {
+            Log.wtf(TAG, "some terrible failure", IllegalStateException())
+            throw NullPointerException("some npe")
+        }
+        assertThat(result.isFailure).isTrue()
+        assertThat(result.exceptionOrNull()).isInstanceOf(NullPointerException::class.java)
+        val suppressedExceptions = result.exceptionOrNull()!!.suppressedExceptions
+        assertThat(suppressedExceptions).hasSize(1)
+        val suppressed = suppressedExceptions.first()
+        assertThat(suppressed).isInstanceOf(AssertionError::class.java)
+        assertThat(suppressed.cause).isInstanceOf(Log.TerribleFailure::class.java)
+        assertThat(suppressed.cause?.cause).isInstanceOf(IllegalStateException::class.java)
+    }
+
+    @Test
+    fun passingTestWithExemptWtf_shouldPass() {
+        underTest.addFailureLogExemption { it.tag == TAG_EXPECTED }
+        val result = runTestCodeWithRule {
+            Log.wtf(TAG_EXPECTED, "some expected failure", IllegalStateException())
+        }
+        assertThat(result.isSuccess).isTrue()
+    }
+
+    @Test
+    fun failingTestWithExemptWtf_shouldFail() {
+        underTest.addFailureLogExemption { it.tag == TAG_EXPECTED }
+        val result = runTestCodeWithRule {
+            Log.wtf(TAG_EXPECTED, "some expected failure", IllegalStateException())
+            throw NullPointerException("some npe")
+        }
+        assertThat(result.isFailure).isTrue()
+        assertThat(result.exceptionOrNull()).isInstanceOf(NullPointerException::class.java)
+        val suppressedExceptions = result.exceptionOrNull()!!.suppressedExceptions
+        assertThat(suppressedExceptions).isEmpty()
+    }
+
+    @Test
+    fun passingTestWithOneExemptWtfOfTwo_shouldFail() {
+        underTest.addFailureLogExemption { it.tag == TAG_EXPECTED }
+        val result = runTestCodeWithRule {
+            Log.wtf(TAG_EXPECTED, "some expected failure", IllegalStateException())
+            Log.wtf(TAG, "some terrible failure", IllegalStateException())
+        }
+        assertThat(result.isFailure).isTrue()
+        val exception = result.exceptionOrNull()
+        assertThat(exception).isInstanceOf(AssertionError::class.java)
+        assertThat(exception?.cause).isInstanceOf(Log.TerribleFailure::class.java)
+        assertThat(exception?.cause?.cause).isInstanceOf(IllegalStateException::class.java)
+    }
+
+    @Test
+    fun failingTestWithOneExemptWtfOfTwo_shouldFail() {
+        underTest.addFailureLogExemption { it.tag == TAG_EXPECTED }
+        val result = runTestCodeWithRule {
+            Log.wtf(TAG_EXPECTED, "some expected failure", IllegalStateException())
+            Log.wtf(TAG, "some terrible failure", IllegalStateException())
+            throw NullPointerException("some npe")
+        }
+        assertThat(result.isFailure).isTrue()
+        assertThat(result.exceptionOrNull()).isInstanceOf(NullPointerException::class.java)
+        val suppressedExceptions = result.exceptionOrNull()!!.suppressedExceptions
+        assertThat(suppressedExceptions).hasSize(1)
+        val suppressed = suppressedExceptions.first()
+        assertThat(suppressed).isInstanceOf(AssertionError::class.java)
+        assertThat(suppressed.cause).isInstanceOf(Log.TerribleFailure::class.java)
+        assertThat(suppressed.cause?.cause).isInstanceOf(IllegalStateException::class.java)
+    }
+
+    private fun runTestCodeWithRule(testCode: () -> Unit): Result<Unit> {
+        val testCodeStatement =
+            object : Statement() {
+                override fun evaluate() {
+                    testCode()
+                }
+            }
+        val wrappedTest = underTest.apply(testCodeStatement, mock())
+        return try {
+            wrappedTest.evaluate()
+            Result.success(Unit)
+        } catch (e: Throwable) {
+            Result.failure(e)
+        }
+    }
+
+    companion object {
+        const val TAG = "LogWtfHandlerRuleTest"
+        const val TAG_EXPECTED = "EXPECTED"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/NotificationMediaManagerTest.kt
similarity index 99%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/NotificationMediaManagerTest.kt
index a7fe586..10b0085 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/NotificationMediaManagerTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar
+package com.android.systemui.media
 
 import android.media.MediaMetadata
 import android.media.session.MediaController
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java
index 2db2199..9c4d93c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java
@@ -48,10 +48,12 @@
 import com.android.media.flags.Flags;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.res.R;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.ListeningExecutorService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,6 +63,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executor;
 import java.util.stream.Collectors;
 
 @SmallTest
@@ -95,6 +98,8 @@
     private List<MediaDevice> mMediaDevices = new ArrayList<>();
     private List<MediaItem> mMediaItems = new ArrayList<>();
     MediaOutputSeekbar mSpyMediaOutputSeekbar;
+    Executor mMainExecutor = mContext.getMainExecutor();
+    ListeningExecutorService mBackgroundExecutor = ThreadUtils.getBackgroundExecutor();
 
     @Before
     public void setUp() {
@@ -108,6 +113,8 @@
         when(mMediaSwitchingController.getSessionVolumeMax()).thenReturn(TEST_MAX_VOLUME);
         when(mMediaSwitchingController.getSessionVolume()).thenReturn(TEST_CURRENT_VOLUME);
         when(mMediaSwitchingController.getSessionName()).thenReturn(TEST_SESSION_NAME);
+        when(mMediaSwitchingController.getColorSchemeLegacy()).thenReturn(
+                mock(MediaOutputColorSchemeLegacy.class));
         when(mIconCompat.toIcon(mContext)).thenReturn(mIcon);
         when(mMediaDevice1.getName()).thenReturn(TEST_DEVICE_NAME_1);
         when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_ID_1);
@@ -122,7 +129,8 @@
         mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice1, true));
         mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice2, false));
 
-        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mMainExecutor,
+                mBackgroundExecutor);
         mMediaOutputAdapter.updateItems();
         mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
                 .onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -148,7 +156,8 @@
 
     @Test
     public void onBindViewHolder_bindPairNew_verifyView() {
-        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mMainExecutor,
+                mBackgroundExecutor);
         mMediaOutputAdapter.updateItems();
         mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
                 .onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -173,7 +182,8 @@
                                 .map((item) -> item.getMediaDevice().get())
                                 .collect(Collectors.toList()));
         when(mMediaSwitchingController.getSessionName()).thenReturn(TEST_SESSION_NAME);
-        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mMainExecutor,
+                mBackgroundExecutor);
         mMediaOutputAdapter.updateItems();
         mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
                 .onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -195,7 +205,8 @@
                                 .map((item) -> item.getMediaDevice().get())
                                 .collect(Collectors.toList()));
         when(mMediaSwitchingController.getSessionName()).thenReturn(null);
-        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mMainExecutor,
+                mBackgroundExecutor);
         mMediaOutputAdapter.updateItems();
         mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
                 .onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -665,7 +676,8 @@
 
     @Test
     public void onItemClick_clickPairNew_verifyLaunchBluetoothPairing() {
-        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mMainExecutor,
+                mBackgroundExecutor);
         mMediaOutputAdapter.updateItems();
         mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
                 .onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -683,7 +695,8 @@
         assertThat(mMediaDevice2.getState()).isEqualTo(
                 LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
         when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_TRANSFER);
-        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mMainExecutor,
+                mBackgroundExecutor);
         mMediaOutputAdapter.updateItems();
         mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
                 .onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -701,7 +714,8 @@
         assertThat(mMediaDevice2.getState()).isEqualTo(
                 LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
         when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_TRANSFER);
-        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController,
+                mContext.getMainExecutor(), ThreadUtils.getBackgroundExecutor());
         mMediaOutputAdapter.updateItems();
         mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
                 .onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -723,7 +737,8 @@
         when(mMediaDevice2.getState()).thenReturn(
                 LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
         when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_GO_TO_APP);
-        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mMainExecutor,
+                mBackgroundExecutor);
         mMediaOutputAdapter.updateItems();
         mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
                 .onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -778,6 +793,8 @@
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2);
+        assertThat(mViewHolder.mTitleText.getAlpha())
+                .isEqualTo(MediaOutputAdapterLegacy.DEVICE_ACTIVE_ALPHA);
         assertThat(mViewHolder.mContainerLayout.isFocusable()).isTrue();
 
         mViewHolder.mContainerLayout.performClick();
@@ -799,6 +816,8 @@
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2);
+        assertThat(mViewHolder.mTitleText.getAlpha())
+                .isEqualTo(MediaOutputAdapterLegacy.DEVICE_ACTIVE_ALPHA);
         assertThat(mViewHolder.mContainerLayout.isFocusable()).isTrue();
 
         mViewHolder.mContainerLayout.performClick();
@@ -820,6 +839,8 @@
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2);
+        assertThat(mViewHolder.mTitleText.getAlpha())
+                .isEqualTo(MediaOutputAdapterLegacy.DEVICE_ACTIVE_ALPHA);
         assertThat(mViewHolder.mContainerLayout.isFocusable()).isTrue();
 
         mViewHolder.mContainerLayout.performClick();
@@ -841,6 +862,8 @@
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2);
+        assertThat(mViewHolder.mTitleText.getAlpha())
+                .isEqualTo(MediaOutputAdapterLegacy.DEVICE_ACTIVE_ALPHA);
         assertThat(mViewHolder.mContainerLayout.isFocusable()).isTrue();
 
         mViewHolder.mContainerLayout.performClick();
@@ -862,6 +885,8 @@
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2);
+        assertThat(mViewHolder.mTitleText.getAlpha())
+                .isEqualTo(MediaOutputAdapterLegacy.DEVICE_ACTIVE_ALPHA);
         assertThat(mViewHolder.mContainerLayout.isFocusable()).isTrue();
 
         mViewHolder.mContainerLayout.performClick();
@@ -883,6 +908,8 @@
         assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_2);
+        assertThat(mViewHolder.mTitleText.getAlpha())
+                .isEqualTo(MediaOutputAdapterLegacy.DEVICE_DISABLED_ALPHA);
         assertThat(mViewHolder.mContainerLayout.isFocusable()).isTrue();
 
         mViewHolder.mContainerLayout.performClick();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateOverrideTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateOverrideTest.kt
new file mode 100644
index 0000000..24bd8ad
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateOverrideTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito.never
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SysUIStateOverrideTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val defaultState = kosmos.sysUiState
+    private val callbackOnOverride = mock<SysUiState.SysUiStateCallback>()
+    private val dumpManager = kosmos.dumpManager
+
+    private val underTest = kosmos.sysUiStateOverrideFactory.invoke(DISPLAY_1)
+
+    @Before
+    fun setup() {
+        underTest.start()
+        underTest.addCallback(callbackOnOverride)
+        reset(callbackOnOverride)
+    }
+
+    @Test
+    fun setFlag_setOnDefaultState_propagatedToOverride() {
+        defaultState.setFlag(FLAG_1, true).commitUpdate()
+
+        verify(callbackOnOverride).onSystemUiStateChanged(FLAG_1, Display.DEFAULT_DISPLAY)
+        verify(callbackOnOverride).onSystemUiStateChanged(FLAG_1, DISPLAY_1)
+    }
+
+    @Test
+    fun setFlag_onOverride_overridesDefaultOnes() {
+        defaultState.setFlag(FLAG_1, false).setFlag(FLAG_2, true).commitUpdate()
+        underTest.setFlag(FLAG_1, true).setFlag(FLAG_2, false).commitUpdate()
+
+        assertThat(underTest.isFlagEnabled(FLAG_1)).isTrue()
+        assertThat(underTest.isFlagEnabled(FLAG_2)).isFalse()
+
+        assertThat(defaultState.isFlagEnabled(FLAG_1)).isFalse()
+        assertThat(defaultState.isFlagEnabled(FLAG_2)).isTrue()
+    }
+
+    @Test
+    fun destroy_callbacksForDefaultStateNotReceivedAnymore() {
+        defaultState.setFlag(FLAG_1, true).commitUpdate()
+
+        verify(callbackOnOverride).onSystemUiStateChanged(FLAG_1, Display.DEFAULT_DISPLAY)
+
+        reset(callbackOnOverride)
+        underTest.destroy()
+        defaultState.setFlag(FLAG_1, false).commitUpdate()
+
+        verify(callbackOnOverride, never()).onSystemUiStateChanged(FLAG_1, Display.DEFAULT_DISPLAY)
+    }
+
+    @Test
+    fun init_registersWithDumpManager() {
+        verify(dumpManager).registerNormalDumpable(any(), eq(underTest))
+    }
+
+    @Test
+    fun destroy_unregistersWithDumpManager() {
+        underTest.destroy()
+
+        verify(dumpManager).unregisterDumpable(ArgumentMatchers.anyString())
+    }
+
+    private companion object {
+        const val DISPLAY_1 = 1
+        const val FLAG_1 = 1L
+        const val FLAG_2 = 2L
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
index f6de629..5bb7f36 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
@@ -140,6 +140,8 @@
 
     @Test
     public void init_registersWithDumpManager() {
+        mFlagsContainer.start();
+
         verify(mDumpManager).registerNormalDumpable(any(), eq(mFlagsContainer));
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/ui/viewmodel/TileRequestDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/ui/viewmodel/TileRequestDialogViewModelTest.kt
index 3029928..cb13b11 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/ui/viewmodel/TileRequestDialogViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/ui/viewmodel/TileRequestDialogViewModelTest.kt
@@ -25,6 +25,7 @@
 import androidx.test.filters.SmallTest
 import com.android.app.iUriGrantsManager
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.ui.viewmodel.iconProvider
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.runCurrent
 import com.android.systemui.kosmos.runTest
@@ -32,6 +33,8 @@
 import com.android.systemui.lifecycle.activateIn
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.qs.external.TileData
+import com.android.systemui.qs.panels.ui.viewmodel.IconProvider
+import com.android.systemui.qs.panels.ui.viewmodel.toIconProvider
 import com.android.systemui.qs.panels.ui.viewmodel.toUiState
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
@@ -80,28 +83,32 @@
     @Test
     fun uiState_beforeActivation_hasDefaultIcon_andCorrectData() =
         kosmos.runTest {
-            val expectedState =
-                baseResultLegacyState.apply { icon = defaultIcon }.toUiState(mainResources)
+            val state = baseResultLegacyState.apply { icon = defaultIcon }
+
+            val expectedState = state.toUiState(mainResources)
+            val expectedIconProvider = state.toIconProvider()
 
             with(underTest.uiState) {
                 expect.that(label).isEqualTo(TEST_LABEL)
                 expect.that(secondaryLabel).isEmpty()
-                expect.that(state).isEqualTo(expectedState.state)
+                expect.that(this.state).isEqualTo(expectedState.state)
                 expect.that(handlesLongClick).isFalse()
                 expect.that(handlesSecondaryClick).isFalse()
-                expect.that(icon).isEqualTo(defaultIcon)
                 expect.that(sideDrawable).isNull()
                 expect.that(accessibilityUiState).isEqualTo(expectedState.accessibilityUiState)
             }
+
+            expect.that(underTest.iconProvider).isEqualTo(expectedIconProvider)
         }
 
     @Test
     fun uiState_afterActivation_hasCorrectIcon_andCorrectData() =
         kosmos.runTest {
-            val expectedState =
-                baseResultLegacyState
-                    .apply { icon = QSTileImpl.DrawableIcon(loadedDrawable) }
-                    .toUiState(mainResources)
+            val state =
+                baseResultLegacyState.apply { icon = QSTileImpl.DrawableIcon(loadedDrawable) }
+
+            val expectedState = state.toUiState(mainResources)
+            val expectedIconProvider = state.toIconProvider()
 
             underTest.activateIn(testScope)
             runCurrent()
@@ -109,13 +116,13 @@
             with(underTest.uiState) {
                 expect.that(label).isEqualTo(TEST_LABEL)
                 expect.that(secondaryLabel).isEmpty()
-                expect.that(state).isEqualTo(expectedState.state)
+                expect.that(this.state).isEqualTo(expectedState.state)
                 expect.that(handlesLongClick).isFalse()
                 expect.that(handlesSecondaryClick).isFalse()
-                expect.that(icon).isEqualTo(QSTileImpl.DrawableIcon(loadedDrawable))
                 expect.that(sideDrawable).isNull()
                 expect.that(accessibilityUiState).isEqualTo(expectedState.accessibilityUiState)
             }
+            expect.that(underTest.iconProvider).isEqualTo(expectedIconProvider)
         }
 
     @Test
@@ -135,7 +142,7 @@
             underTest.activateIn(testScope)
             runCurrent()
 
-            assertThat(underTest.uiState.icon).isEqualTo(defaultIcon)
+            assertThat(underTest.iconProvider).isEqualTo(IconProvider.ConstantIcon(defaultIcon))
         }
 
     companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/IconProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/IconProviderTest.kt
new file mode 100644
index 0000000..7257a89
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/IconProviderTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.ui.viewmodel
+
+import android.graphics.drawable.TestStubDrawable
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
+import com.android.systemui.res.R
+import com.google.common.truth.Truth.assertThat
+import java.util.function.Supplier
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconProviderTest : SysuiTestCase() {
+
+    @Test
+    fun iconAndSupplier_prefersIcon() {
+        val state =
+            QSTile.State().apply {
+                icon = ResourceIcon.get(R.drawable.android)
+                iconSupplier = Supplier { QSTileImpl.DrawableIcon(TestStubDrawable()) }
+            }
+        val iconProvider = state.toIconProvider()
+
+        assertThat(iconProvider).isEqualTo(IconProvider.ConstantIcon(state.icon))
+    }
+
+    @Test
+    fun iconOnly_hasIcon() {
+        val state = QSTile.State().apply { icon = ResourceIcon.get(R.drawable.android) }
+        val iconProvider = state.toIconProvider()
+
+        assertThat(iconProvider).isEqualTo(IconProvider.ConstantIcon(state.icon))
+    }
+
+    @Test
+    fun supplierOnly_hasIcon() {
+        val state =
+            QSTile.State().apply {
+                iconSupplier = Supplier { ResourceIcon.get(R.drawable.android) }
+            }
+        val iconProvider = state.toIconProvider()
+
+        assertThat(iconProvider).isEqualTo(IconProvider.IconSupplier(state.iconSupplier))
+    }
+
+    @Test
+    fun noIconOrSupplier_iconNull() {
+        val state = QSTile.State()
+        val iconProvider = state.toIconProvider()
+
+        assertThat(iconProvider).isEqualTo(IconProvider.Empty)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt
index 9c8e322..b144f06 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt
@@ -18,7 +18,6 @@
 
 import android.content.res.Resources
 import android.content.res.mainResources
-import android.graphics.drawable.TestStubDrawable
 import android.service.quicksettings.Tile
 import android.widget.Button
 import android.widget.Switch
@@ -27,12 +26,9 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.qs.QSTile
-import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
 import com.android.systemui.res.R
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
-import java.util.function.Supplier
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -267,45 +263,6 @@
             .contains(resources.getString(R.string.tile_unavailable))
     }
 
-    @Test
-    fun iconAndSupplier_prefersIcon() {
-        val state =
-            QSTile.State().apply {
-                icon = ResourceIcon.get(R.drawable.android)
-                iconSupplier = Supplier { QSTileImpl.DrawableIcon(TestStubDrawable()) }
-            }
-        val uiState = state.toUiState()
-
-        assertThat(uiState.icon).isEqualTo(state.icon)
-    }
-
-    @Test
-    fun iconOnly_hasIcon() {
-        val state = QSTile.State().apply { icon = ResourceIcon.get(R.drawable.android) }
-        val uiState = state.toUiState()
-
-        assertThat(uiState.icon).isEqualTo(state.icon)
-    }
-
-    @Test
-    fun supplierOnly_hasIcon() {
-        val state =
-            QSTile.State().apply {
-                iconSupplier = Supplier { ResourceIcon.get(R.drawable.android) }
-            }
-        val uiState = state.toUiState()
-
-        assertThat(uiState.icon).isEqualTo(state.iconSupplier.get())
-    }
-
-    @Test
-    fun noIconOrSupplier_iconNull() {
-        val state = QSTile.State()
-        val uiState = state.toUiState()
-
-        assertThat(uiState.icon).isNull()
-    }
-
     private fun QSTile.State.toUiState() = toUiState(resources)
 }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileUserActionInteractorTest.kt
index 00ee1c3..1b497a2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileUserActionInteractorTest.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.accessibility.hearingaid.HearingDevicesUiEventLogger.Companion.LAUNCH_SOURCE_QS_TILE
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
 import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
 import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
@@ -40,6 +41,7 @@
 import org.mockito.junit.MockitoRule
 import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @EnabledOnRavenwood
@@ -53,14 +55,18 @@
 
     @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
     @Mock private lateinit var dialogManager: HearingDevicesDialogManager
+    @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository
 
     @Before
     fun setUp() {
+        whenever(settingsPackageRepository.getSettingsPackageName())
+            .thenReturn(SETTINGS_PACKAGE_NAME)
         underTest =
             HearingDevicesTileUserActionInteractor(
                 testScope.coroutineContext,
                 inputHandler,
                 dialogManager,
+                settingsPackageRepository,
             )
     }
 
@@ -91,6 +97,11 @@
 
             QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
                 assertThat(it.intent.action).isEqualTo(Settings.ACTION_HEARING_DEVICES_SETTINGS)
+                assertThat(it.intent.`package`).isEqualTo(SETTINGS_PACKAGE_NAME)
             }
         }
+
+    companion object {
+        private const val SETTINGS_PACKAGE_NAME = "com.android.settings"
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 9adf24f..1743e05 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -863,7 +863,7 @@
             whenever(kosmos.keyguardUpdateMonitor.isDeviceInteractive).thenReturn(true)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playSuccessHaptic by
-                collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+                collectLastValue(deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry)
 
             setupBiometricAuth(hasUdfps = true)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
@@ -885,7 +885,7 @@
             whenever(kosmos.keyguardUpdateMonitor.isDeviceInteractive).thenReturn(true)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playSuccessHaptic by
-                collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+                collectLastValue(deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry)
 
             setupBiometricAuth(hasUdfps = true)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
@@ -907,7 +907,7 @@
             whenever(kosmos.keyguardUpdateMonitor.isDeviceInteractive).thenReturn(true)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playSuccessHaptic by
-                collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+                collectLastValue(deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry)
 
             setupBiometricAuth(hasSfps = true)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
@@ -930,7 +930,7 @@
             whenever(kosmos.keyguardUpdateMonitor.isDeviceInteractive).thenReturn(true)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playSuccessHaptic by
-                collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+                collectLastValue(deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry)
 
             setupBiometricAuth(hasSfps = true)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
@@ -1033,7 +1033,7 @@
             whenever(kosmos.keyguardUpdateMonitor.isDeviceInteractive).thenReturn(true)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playSuccessHaptic by
-                collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+                collectLastValue(deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry)
 
             setupBiometricAuth(hasSfps = true)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
@@ -1056,7 +1056,7 @@
             whenever(kosmos.keyguardUpdateMonitor.isDeviceInteractive).thenReturn(true)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playSuccessHaptic by
-                collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+                collectLastValue(deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry)
 
             setupBiometricAuth(hasSfps = true)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
@@ -1079,7 +1079,7 @@
             whenever(kosmos.keyguardUpdateMonitor.isDeviceInteractive).thenReturn(true)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playSuccessHaptic by
-                collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+                collectLastValue(deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry)
 
             setupBiometricAuth(hasSfps = true)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
@@ -1102,7 +1102,7 @@
             whenever(kosmos.keyguardUpdateMonitor.isDeviceInteractive).thenReturn(true)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playSuccessHaptic by
-                collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+                collectLastValue(deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry)
 
             setupBiometricAuth(hasSfps = true)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
@@ -1160,7 +1160,7 @@
 
     @Test
     @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
-    fun playsFaceErrorHaptics_nonSfps_coEx() =
+    fun skipsFaceErrorHaptics_nonSfps_coEx() =
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic)
@@ -1172,15 +1172,14 @@
             underTest.start()
             updateFaceAuthStatus(isSuccess = false)
 
-            assertThat(playErrorHaptic).isNotNull()
-            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
-            verify(vibratorHelper).vibrateAuthError(anyString())
+            assertThat(playErrorHaptic).isNull()
+            verify(vibratorHelper, never()).vibrateAuthError(anyString())
             verify(vibratorHelper, never()).vibrateAuthSuccess(anyString())
         }
 
     @Test
     @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
-    fun playsMSDLFaceErrorHaptics_nonSfps_coEx() =
+    fun skipsMSDLFaceErrorHaptics_nonSfps_coEx() =
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic)
@@ -1192,10 +1191,9 @@
             underTest.start()
             updateFaceAuthStatus(isSuccess = false)
 
-            assertThat(playErrorHaptic).isNotNull()
-            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
-            assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.FAILURE)
-            assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(authInteractionProperties)
+            assertThat(playErrorHaptic).isNull()
+            assertThat(msdlPlayer.latestTokenPlayed).isNull()
+            assertThat(msdlPlayer.latestPropertiesPlayed).isNull()
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 2c852c3..94db429 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -598,7 +598,8 @@
                 mKeyguardClockPositionAlgorithm,
                 mMSDLPlayer,
                 mBrightnessMirrorShowingRepository,
-                new BlurConfig(0f, 0f));
+                new BlurConfig(0f, 0f),
+                () -> mKosmos.getFakeShadeDisplaysRepository());
         mNotificationPanelViewController.initDependencies(
                 mCentralSurfaces,
                 null,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index f54c367..89263fc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -195,9 +195,7 @@
     @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
     public void updateSystemUiStateFlags_updatesSysuiStateInteractor() {
         var DISPLAY_ID = 10;
-        var displayMock = display(TYPE_INTERNAL, /* flags= */ 0, /* id= */DISPLAY_ID,
-                /* state= */ null);
-        when(mView.getDisplay()).thenReturn(displayMock);
+        mKosmos.getFakeShadeDisplaysRepository().setPendingDisplayId(DISPLAY_ID);
 
         mNotificationPanelViewController.updateSystemUiStateFlags();
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 3407cd5..4a30407 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -41,7 +41,6 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.flag.junit.FlagsParameterization;
-import android.provider.Settings;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.View;
 import android.view.WindowManager;
@@ -71,7 +70,6 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.android.systemui.util.settings.FakeSettings;
 
 import com.google.common.util.concurrent.MoreExecutors;
 
@@ -113,7 +111,6 @@
     @Captor private ArgumentCaptor<WindowManager.LayoutParams> mLayoutParameters;
     @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListener;
 
-    private FakeSettings mSecureSettings;
     private final Executor mMainExecutor = MoreExecutors.directExecutor();
     private final Executor mBackgroundExecutor = MoreExecutors.directExecutor();
     private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
@@ -135,9 +132,6 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mSecureSettings = new FakeSettings();
-        mSecureSettings.putInt(Settings.Secure.DISABLE_SECURE_WINDOWS, 0);
-
         // Preferred refresh rate is equal to the first displayMode's refresh rate
         mPreferredRefreshRate = mContext.getDisplay().getSystemSupportedModes()[0].getRefreshRate();
         overrideResource(
@@ -171,7 +165,6 @@
                 () -> mSelectedUserInteractor,
                 mUserTracker,
                 mKosmos.getNotificationShadeWindowModel(),
-                mSecureSettings,
                 mKosmos::getCommunalInteractor,
                 mKosmos.getShadeLayoutParams());
         mNotificationShadeWindowController.setScrimsVisibilityListener((visibility) -> {});
@@ -355,19 +348,6 @@
     }
 
     @Test
-    public void setKeyguardShowingWithSecureWindowsDisabled_disablesSecureFlag() {
-        mSecureSettings.putInt(Settings.Secure.DISABLE_SECURE_WINDOWS, 1);
-        mNotificationShadeWindowController.setBouncerShowing(true);
-
-        verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
-        assertThat((mLayoutParameters.getValue().flags & FLAG_SECURE) == 0).isTrue();
-        assertThat(
-                (mLayoutParameters.getValue().inputFeatures & INPUT_FEATURE_SENSITIVE_FOR_PRIVACY)
-                        != 0)
-                .isTrue();
-    }
-
-    @Test
     public void setKeyguardNotShowing_disablesSecureFlag() {
         mNotificationShadeWindowController.setBouncerShowing(false);
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
index 9498daa..c635c7f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
@@ -67,7 +67,7 @@
     fun policy_changing_propagatedFromTheLatestPolicy() =
         testScope.runTest {
             val underTest = createUnderTest()
-            val displayIds by collectValues(underTest.displayId)
+            val displayIds by collectValues(underTest.pendingDisplayId)
 
             assertThat(displayIds).containsExactly(0)
 
@@ -98,7 +98,7 @@
                 DEVELOPMENT_SHADE_DISPLAY_AWARENESS,
                 FakeShadeDisplayPolicy.name,
             )
-            val displayId by collectLastValue(underTest.displayId)
+            val displayId by collectLastValue(underTest.pendingDisplayId)
 
             displayRepository.addDisplay(displayId = 1)
 
@@ -161,7 +161,7 @@
                 FakeShadeDisplayPolicy.name,
             )
 
-            val displayId by collectLastValue(underTest.displayId)
+            val displayId by collectLastValue(underTest.pendingDisplayId)
 
             displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
             FakeShadeDisplayPolicy.setDisplayId(2)
@@ -176,4 +176,17 @@
 
             assertThat(displayId).isEqualTo(2)
         }
+
+    @Test
+    fun onDisplayChangedSucceeded_displayIdChanges() =
+        testScope.runTest {
+            val underTest = createUnderTest()
+            val displayId by collectLastValue(underTest.displayId)
+
+            assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
+
+            underTest.onDisplayChangedSucceeded(1)
+
+            assertThat(displayId).isEqualTo(1)
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
index fd6bc98..f51d41b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
@@ -69,7 +69,7 @@
     @Test
     fun commandShadeDisplayOverride_resetsDisplayId() =
         testScope.runTest {
-            val displayId by collectLastValue(shadeDisplaysRepository.displayId)
+            val displayId by collectLastValue(shadeDisplaysRepository.pendingDisplayId)
             assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
 
             val newDisplayId = 2
@@ -87,7 +87,7 @@
     @Test
     fun commandShadeDisplayOverride_anyExternalDisplay_notOnDefaultAnymore() =
         testScope.runTest {
-            val displayId by collectLastValue(shadeDisplaysRepository.displayId)
+            val displayId by collectLastValue(shadeDisplaysRepository.pendingDisplayId)
             assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
             val newDisplayId = 2
             displayRepository.addDisplay(displayId = newDisplayId)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt
index e43c46b..dd0ba00 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shade.display
 
+import android.platform.test.annotations.EnableFlags
 import android.view.Display
 import android.view.Display.TYPE_EXTERNAL
 import android.view.MotionEvent
@@ -31,6 +32,7 @@
 import com.android.systemui.shade.data.repository.statusBarTouchShadeDisplayPolicy
 import com.android.systemui.shade.domain.interactor.notificationElement
 import com.android.systemui.shade.domain.interactor.qsElement
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
@@ -41,6 +43,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@EnableFlags(ShadeWindowGoesAround.FLAG_NAME)
 class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
     private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val testScope = kosmos.testScope
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
index 0ad60b6..24593f4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
@@ -18,16 +18,17 @@
 
 import android.content.res.Configuration
 import android.content.res.mockResources
+import android.platform.test.annotations.EnableFlags
 import android.view.Display
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.ui.data.repository.configurationRepository
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.scene.ui.view.mockShadeRootView
 import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
 import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
 import com.android.systemui.statusbar.notification.row.notificationRebindingTracker
@@ -48,6 +49,7 @@
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
+@EnableFlags(ShadeWindowGoesAround.FLAG_NAME)
 class ShadeDisplaysInteractorTest : SysuiTestCase() {
     private val kosmos = testKosmos().useUnconfinedTestDispatcher()
 
@@ -82,7 +84,7 @@
     fun start_shadeInCorrectPosition_notAddedOrRemoved() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(0)
+            positionRepository.setPendingDisplayId(0)
 
             underTest.start()
 
@@ -93,18 +95,19 @@
     fun start_shadeInWrongPosition_changes() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
 
             underTest.start()
 
             verify(shadeContext).reparentToDisplay(eq(1))
+            assertThat(positionRepository.displayId.value).isEqualTo(1)
         }
 
     @Test
     fun start_shadeInWrongPosition_logsStartToLatencyTracker() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
 
             underTest.start()
 
@@ -115,7 +118,7 @@
     fun start_shadeInWrongPosition_someNotificationsVisible_hiddenThenShown() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
             activeNotificationRepository.setActiveNotifs(1)
 
             underTest.start()
@@ -129,7 +132,7 @@
     fun start_shadeInWrongPosition_someNotificationsVisible_waitsForInflationsBeforeShowingNssl() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
             activeNotificationRepository.setActiveNotifs(1)
 
             val endRebinding = notificationRebindingTracker.trackRebinding("test")
@@ -155,7 +158,7 @@
     fun start_shadeInWrongPosition_noNotifications_nsslNotHidden() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
             activeNotificationRepository.setActiveNotifs(0)
 
             underTest.start()
@@ -170,7 +173,7 @@
     fun start_shadeInWrongPosition_waitsUntilMovedToDisplayReceived() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
             activeNotificationRepository.setActiveNotifs(1)
 
             underTest.start()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index 4f30103..0642467 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -19,6 +19,8 @@
 import android.content.res.Resources
 import android.graphics.Color
 import android.graphics.drawable.Drawable
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.util.TypedValue
 import android.view.LayoutInflater
 import android.widget.FrameLayout
@@ -29,6 +31,7 @@
 import com.android.systemui.plugins.clocks.ClockId
 import com.android.systemui.plugins.clocks.ClockSettings
 import com.android.systemui.plugins.clocks.ThemeConfig
+import com.android.systemui.shared.Flags
 import com.android.systemui.shared.clocks.DefaultClockController.Companion.DOZE_COLOR
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
@@ -103,14 +106,34 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_AMBIENT_AOD)
+    fun defaultClock_initialize_flagOff() {
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
+        verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA)
+
+        clock.initialize(true, 0f, 0f, null)
+
+        // This is the default darkTheme color
+        val expectedColor = context.resources.getColor(android.R.color.system_accent1_100)
+        verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor)
+        verify(mockLargeClockView).setColors(DOZE_COLOR, expectedColor)
+        verify(mockSmallClockView).onTimeZoneChanged(notNull())
+        verify(mockLargeClockView).onTimeZoneChanged(notNull())
+        verify(mockSmallClockView).refreshTime()
+        verify(mockLargeClockView).refreshTime()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_AMBIENT_AOD)
     fun defaultClock_initialize() {
         val clock = provider.createClock(DEFAULT_CLOCK_ID)
         verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
         verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA)
 
-        clock.initialize(true, 0f, 0f, {})
+        clock.initialize(true, 0f, 0f, null)
 
-        val expectedColor = 0
+        val expectedColor = Color.MAGENTA
         verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor)
         verify(mockLargeClockView).setColors(DOZE_COLOR, expectedColor)
         verify(mockSmallClockView).onTimeZoneChanged(notNull())
@@ -165,8 +188,10 @@
     }
 
     @Test
-    fun defaultClock_events_onThemeChanged_noSeed() {
-        val expectedColor = 0
+    @DisableFlags(Flags.FLAG_AMBIENT_AOD)
+    fun defaultClock_events_onThemeChanged_noSeed_flagOff() {
+        // This is the default darkTheme color
+        val expectedColor = context.resources.getColor(android.R.color.system_accent1_100)
         val clock = provider.createClock(DEFAULT_CLOCK_ID)
 
         verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
@@ -180,6 +205,22 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_AMBIENT_AOD)
+    fun defaultClock_events_onThemeChanged_noSeedn() {
+        val expectedColor = Color.TRANSPARENT
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+
+        verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
+        verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA)
+
+        clock.smallClock.events.onThemeChanged(ThemeConfig(true, null))
+        clock.largeClock.events.onThemeChanged(ThemeConfig(true, null))
+
+        verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
+        verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA)
+    }
+
+    @Test
     fun defaultClock_events_onThemeChanged_newSeed() {
         val initSeedColor = 10
         val newSeedColor = 20
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
index 4bd02e0..17509dc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
@@ -19,6 +19,10 @@
 @RunWith(AndroidJUnit4::class)
 class ConditionExtensionsTest : SysuiTestCase() {
     private lateinit var testScope: TestScope
+    private val testCallback =
+        Condition.Callback {
+            // This is a no-op
+        }
 
     @Before
     fun setUp() {
@@ -33,7 +37,7 @@
 
             assertThat(condition.isConditionSet).isFalse()
 
-            condition.start()
+            condition.testStart()
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isTrue()
         }
@@ -46,7 +50,7 @@
 
             assertThat(condition.isConditionSet).isFalse()
 
-            condition.start()
+            condition.testStart()
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isFalse()
         }
@@ -56,7 +60,7 @@
         testScope.runTest {
             val flow = emptyFlow<Boolean>()
             val condition = flow.toCondition(scope = this, Condition.START_EAGERLY)
-            condition.start()
+            condition.testStop()
 
             assertThat(condition.isConditionSet).isFalse()
             assertThat(condition.isConditionMet).isFalse()
@@ -72,7 +76,7 @@
                     strategy = Condition.START_EAGERLY,
                     initialValue = true,
                 )
-            condition.start()
+            condition.testStart()
 
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isTrue()
@@ -88,7 +92,7 @@
                     strategy = Condition.START_EAGERLY,
                     initialValue = false,
                 )
-            condition.start()
+            condition.testStart()
 
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isFalse()
@@ -99,7 +103,7 @@
         testScope.runTest {
             val flow = MutableStateFlow(false)
             val condition = flow.toCondition(scope = this, strategy = Condition.START_EAGERLY)
-            condition.start()
+            condition.testStart()
 
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isFalse()
@@ -110,7 +114,7 @@
             flow.value = false
             assertThat(condition.isConditionMet).isFalse()
 
-            condition.stop()
+            condition.testStop()
         }
 
     @Test
@@ -120,10 +124,18 @@
             val condition = flow.toCondition(scope = this, strategy = Condition.START_EAGERLY)
             assertThat(flow.subscriptionCount.value).isEqualTo(0)
 
-            condition.start()
+            condition.testStart()
             assertThat(flow.subscriptionCount.value).isEqualTo(1)
 
-            condition.stop()
+            condition.testStop()
             assertThat(flow.subscriptionCount.value).isEqualTo(0)
         }
+
+    fun Condition.testStart() {
+        addCallback(testCallback)
+    }
+
+    fun Condition.testStop() {
+        removeCallback(testCallback)
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
index 5416536..da660e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
@@ -40,7 +40,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
index 064fd48..b80ff34 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
@@ -33,6 +33,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.log.LogAssertKt;
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginLifecycleManager;
 import com.android.systemui.plugins.PluginListener;
@@ -138,11 +139,12 @@
 
         mVersionCheckResult = false;
         assertFalse(mPluginInstance.hasError());
-
         mPluginInstanceFactory.create(
                 mContext, mAppInfo, wrongVersionTestPluginComponentName,
                 TestPlugin.class, mPluginListener);
-        mPluginInstance.onCreate();
+        LogAssertKt.assertRunnableLogsWtf(()-> {
+            mPluginInstance.onCreate();
+        });
         assertTrue(mPluginInstance.hasError());
         assertNull(mPluginInstance.getPlugin());
     }
@@ -193,8 +195,10 @@
         mPluginInstance.onCreate();
         assertFalse(mPluginInstance.hasError());
 
-        Object result = mPluginInstance.getPlugin().methodThrowsError();
-        assertNotNull(result);  // Wrapper function should return non-null;
+        LogAssertKt.assertRunnableLogsWtf(()-> {
+            Object result = mPluginInstance.getPlugin().methodThrowsError();
+            assertNotNull(result);  // Wrapper function should return non-null;
+        });
         assertTrue(mPluginInstance.hasError());
         assertNull(mPluginInstance.getPlugin());
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 326d8ff..8165d45 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeExpansionChangeEvent
+import com.android.systemui.shared.Flags as SharedFlags
 import com.android.systemui.statusbar.phone.BiometricUnlockController
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.ScrimController
@@ -43,10 +44,11 @@
 import com.android.systemui.testKosmos
 import com.android.systemui.util.WallpaperController
 import com.android.systemui.util.mockito.eq
-import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor
 import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor
 import com.android.wm.shell.appzoomout.AppZoomOut
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import java.util.function.Consumer
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -67,8 +69,6 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.junit.MockitoJUnit
-import java.util.Optional
-import java.util.function.Consumer
 
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper
@@ -76,7 +76,6 @@
 class NotificationShadeDepthControllerTest : SysuiTestCase() {
     private val kosmos = testKosmos()
 
-    private val applicationScope = kosmos.testScope.backgroundScope
     @Mock private lateinit var windowRootViewBlurInteractor: WindowRootViewBlurInteractor
     @Mock private lateinit var statusBarStateController: StatusBarStateController
     @Mock private lateinit var blurUtils: BlurUtils
@@ -85,7 +84,6 @@
     @Mock private lateinit var keyguardInteractor: KeyguardInteractor
     @Mock private lateinit var choreographer: Choreographer
     @Mock private lateinit var wallpaperController: WallpaperController
-    @Mock private lateinit var wallpaperInteractor: WallpaperInteractor
     @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
     @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var appZoomOutOptional: Optional<AppZoomOut>
@@ -130,14 +128,12 @@
                 keyguardInteractor,
                 choreographer,
                 wallpaperController,
-                wallpaperInteractor,
                 notificationShadeWindowController,
                 dozeParameters,
                 context,
                 ResourcesSplitShadeStateController(),
                 windowRootViewBlurInteractor,
                 appZoomOutOptional,
-                applicationScope,
                 dumpManager,
                 configurationController,
             )
@@ -314,24 +310,22 @@
     }
 
     @Test
-    fun onDozeAmountChanged_doesNotApplyBlurWithAmbientAod() {
-        notificationShadeDepthController.wallpaperSupportsAmbientMode = false
-
-        statusBarStateListener.onDozeAmountChanged(1f, 1f)
-        notificationShadeDepthController.updateBlurCallback.doFrame(0)
-        verify(blurUtils).applyBlur(any(), eq(0), eq(false))
-    }
-
-    @Test
-    fun onDozeAmountChanged_appliesBlurWithAmbientAod() {
-        notificationShadeDepthController.wallpaperSupportsAmbientMode = true
-
+    @DisableFlags(SharedFlags.FLAG_AMBIENT_AOD)
+    fun onDozeAmountChanged_appliesBlur() {
         statusBarStateListener.onDozeAmountChanged(1f, 1f)
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
     }
 
     @Test
+    @EnableFlags(SharedFlags.FLAG_AMBIENT_AOD)
+    fun onDozeAmountChanged_doesNotApplyBlurWithAmbientAod() {
+        statusBarStateListener.onDozeAmountChanged(1f, 1f)
+        notificationShadeDepthController.updateBlurCallback.doFrame(0)
+        verify(blurUtils).applyBlur(any(), eq(0), eq(false))
+    }
+
+    @Test
     fun setFullShadeTransition_appliesBlur_onlyIfSupported() {
         reset(blurUtils)
         `when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
index fda4ab0..b085ba4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
@@ -26,7 +26,7 @@
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.collectLastValue
 import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
@@ -46,7 +46,6 @@
 import com.android.systemui.util.time.fakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
-import kotlinx.coroutines.test.runTest
 import org.junit.runner.RunWith
 import org.mockito.kotlin.any
 import org.mockito.kotlin.mock
@@ -71,7 +70,7 @@
     private val mockExpandable: Expandable =
         mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) }
 
-    private val underTest by lazy { kosmos.callChipViewModel }
+    private val Kosmos.underTest by Kosmos.Fixture { callChipViewModel }
 
     @Test
     fun chip_noCall_isHidden() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
index 5d19506..7f8f5f4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
@@ -39,6 +40,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@EnableFlags(StatusBarNotifChips.FLAG_NAME)
 class SingleNotificationChipInteractorTest : SysuiTestCase() {
     private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     val factory = kosmos.singleNotificationChipInteractorFactory
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
index 7ed2bd3..0b9b297 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
@@ -34,6 +34,8 @@
 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.addNotif
+import com.android.systemui.statusbar.notification.data.repository.removeNotif
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.notification.shared.CallType
@@ -409,6 +411,63 @@
 
     @Test
     @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun shownNotificationChips_lastAppVisibleTimeMaintainedAcrossNotifAddsAndRemoves() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.shownNotificationChips)
+
+            val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
+            val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
+
+            // Have notif1's app start as showing and then hide later so we get the chip
+            activityManagerRepository.fake.startingIsAppVisibleValue = true
+            fakeSystemClock.setCurrentTimeMillis(9_000)
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = notif1Info.key,
+                    uid = notif1Info.uid,
+                    statusBarChipIcon = notif1Info.icon,
+                    promotedContent =
+                        PromotedNotificationContentModel.Builder(notif1Info.key).build(),
+                )
+            )
+            activityManagerRepository.fake.setIsAppVisible(notif1Info.uid, isAppVisible = false)
+
+            assertThat(latest!![0].key).isEqualTo(notif1Info.key)
+            assertThat(latest!![0].lastAppVisibleTime).isEqualTo(9_000)
+
+            // WHEN a new notification is added
+            activityManagerRepository.fake.startingIsAppVisibleValue = true
+            fakeSystemClock.setCurrentTimeMillis(10_000)
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = notif2Info.key,
+                    uid = notif2Info.uid,
+                    statusBarChipIcon = notif2Info.icon,
+                    promotedContent =
+                        PromotedNotificationContentModel.Builder(notif2Info.key).build(),
+                )
+            )
+            activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = false)
+
+            // THEN the new notification is first
+            assertThat(latest!![0].key).isEqualTo(notif2Info.key)
+            assertThat(latest!![0].lastAppVisibleTime).isEqualTo(10_000)
+
+            // And THEN the original notification maintains its lastAppVisibleTime
+            assertThat(latest!![1].key).isEqualTo(notif1Info.key)
+            assertThat(latest!![1].lastAppVisibleTime).isEqualTo(9_000)
+
+            // WHEN notif1 is removed
+            fakeSystemClock.setCurrentTimeMillis(11_000)
+            activeNotificationListRepository.removeNotif(notif1Info.key)
+
+            // THEN notif2 still has its lastAppVisibleTime
+            assertThat(latest!![0].key).isEqualTo(notif2Info.key)
+            assertThat(latest!![0].lastAppVisibleTime).isEqualTo(10_000)
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun shownNotificationChips_sortedByLastAppVisibleTime() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.shownNotificationChips)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index 1b5b0d6..e2d1498 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -16,18 +16,19 @@
 
 package com.android.systemui.statusbar.chips.ui.viewmodel
 
+import android.content.Context
 import android.content.DialogInterface
 import android.content.packageManager
 import android.content.pm.PackageManager
 import android.graphics.Bitmap
 import android.graphics.drawable.BitmapDrawable
 import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Expandable
+import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.collectLastValue
@@ -181,7 +182,7 @@
 
             val latest by collectLastValue(underTest.primaryChip)
 
-            assertIsCallChip(latest, notificationKey)
+            assertIsCallChip(latest, notificationKey, context)
         }
 
     @Test
@@ -196,7 +197,7 @@
 
             val latest by collectLastValue(underTest.primaryChip)
 
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
 
             // WHEN the higher priority media projection chip is added
             mediaProjectionState.value =
@@ -241,7 +242,7 @@
             mediaProjectionState.value = MediaProjectionState.NotProjecting
 
             // THEN the lower priority call is used
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
         }
 
     /** Regression test for b/347726238. */
@@ -395,18 +396,29 @@
             assertThat(icon.res).isEqualTo(R.drawable.ic_present_to_all)
         }
 
-        fun assertIsCallChip(latest: OngoingActivityChipModel?, notificationKey: String) {
+        fun assertIsCallChip(
+            latest: OngoingActivityChipModel?,
+            notificationKey: String,
+            context: Context,
+        ) {
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active::class.java)
             assertThat((latest as OngoingActivityChipModel.Active).key).isEqualTo(notificationKey)
 
             if (StatusBarConnectedDisplays.isEnabled) {
                 assertNotificationIcon(latest, notificationKey)
-                return
+            } else {
+                val contentDescription =
+                    if (latest.icon is OngoingActivityChipModel.ChipIcon.SingleColorIcon) {
+                        ((latest.icon) as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
+                            .impl
+                            .contentDescription
+                    } else {
+                        (latest.icon as OngoingActivityChipModel.ChipIcon.StatusBarView)
+                            .contentDescription
+                    }
+                assertThat(contentDescription.loadContentDescription(context))
+                    .contains(context.getString(R.string.ongoing_call_content_description))
             }
-            val icon =
-                ((latest.icon) as OngoingActivityChipModel.ChipIcon.SingleColorIcon).impl
-                    as Icon.Resource
-            assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
         }
 
         private fun assertNotificationIcon(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
index e3f93f2..670ebadc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
@@ -62,6 +62,7 @@
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
 import com.android.systemui.statusbar.notification.data.repository.addNotif
 import com.android.systemui.statusbar.notification.data.repository.addNotifs
+import com.android.systemui.statusbar.notification.data.repository.removeNotif
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -254,7 +255,7 @@
             val unused by collectLastValue(underTest.chips)
 
             assertIsScreenRecordChip(latest!!.primary)
-            assertIsCallChip(latest!!.secondary, callNotificationKey)
+            assertIsCallChip(latest!!.secondary, callNotificationKey, context)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
         }
 
@@ -285,7 +286,7 @@
 
             assertThat(latest!!.active.size).isEqualTo(2)
             assertIsScreenRecordChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(2)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
@@ -349,6 +350,36 @@
                 .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
         }
 
+    @EnableChipsModernization
+    @Test
+    fun chips_threeChips_isSmallPortrait_allSquished() =
+        kosmos.runTest {
+            screenRecordState.value = ScreenRecordModel.Recording
+            addOngoingCallState(key = "call")
+
+            val promotedContentBuilder =
+                PromotedNotificationContentModel.Builder("notif").apply {
+                    this.shortCriticalText = "Some text here"
+                }
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = "notif",
+                    statusBarChipIcon = createStatusBarIconViewOrNull(),
+                    promotedContent = promotedContentBuilder.build(),
+                )
+            )
+
+            val latest by collectLastValue(underTest.chips)
+
+            // Squished chips are icon only
+            assertThat(latest!!.active[0])
+                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
+            assertThat(latest!!.active[1])
+                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
+            assertThat(latest!!.active[2])
+                .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
+        }
+
     @DisableChipsModernization
     @Test
     fun chipsLegacy_countdownChipAndTimerChip_countdownNotSquished_butTimerSquished() =
@@ -617,7 +648,7 @@
             val unused by collectLastValue(underTest.chips)
 
             assertIsShareToAppChip(latest!!.primary)
-            assertIsCallChip(latest!!.secondary, callNotificationKey)
+            assertIsCallChip(latest!!.secondary, callNotificationKey, context)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
         }
 
@@ -636,7 +667,7 @@
 
             assertThat(latest!!.active.size).isEqualTo(2)
             assertIsShareToAppChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(2)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
@@ -654,7 +685,7 @@
 
             val latest by collectLastValue(underTest.primaryChip)
 
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
         }
 
     @DisableChipsModernization
@@ -671,7 +702,7 @@
             val latest by collectLastValue(underTest.chipsLegacy)
             val unused by collectLastValue(underTest.chips)
 
-            assertIsCallChip(latest!!.primary, callNotificationKey)
+            assertIsCallChip(latest!!.primary, callNotificationKey, context)
             assertThat(latest!!.secondary)
                 .isInstanceOf(OngoingActivityChipModel.Inactive::class.java)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
@@ -691,7 +722,7 @@
             val unused by collectLastValue(underTest.chipsLegacy)
 
             assertThat(latest!!.active.size).isEqualTo(1)
-            assertIsCallChip(latest!!.active[0], callNotificationKey)
+            assertIsCallChip(latest!!.active[0], callNotificationKey, context)
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(3)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
@@ -851,7 +882,7 @@
 
     @EnableChipsModernization
     @Test
-    fun chips_threePromotedNotifs_topTwoActiveThirdInOverflow() =
+    fun chips_fourPromotedNotifs_topThreeActiveFourthInOverflow() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.chips)
             val unused by collectLastValue(underTest.chipsLegacy)
@@ -859,6 +890,7 @@
             val firstIcon = createStatusBarIconViewOrNull()
             val secondIcon = createStatusBarIconViewOrNull()
             val thirdIcon = createStatusBarIconViewOrNull()
+            val fourthIcon = createStatusBarIconViewOrNull()
             setNotifs(
                 listOf(
                     activeNotificationModel(
@@ -879,20 +911,27 @@
                         promotedContent =
                             PromotedNotificationContentModel.Builder("thirdNotif").build(),
                     ),
+                    activeNotificationModel(
+                        key = "fourthNotif",
+                        statusBarChipIcon = thirdIcon,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("fourthNotif").build(),
+                    ),
                 )
             )
 
-            assertThat(latest!!.active.size).isEqualTo(2)
+            assertThat(latest!!.active.size).isEqualTo(3)
             assertIsNotifChip(latest!!.active[0], context, firstIcon, "firstNotif")
             assertIsNotifChip(latest!!.active[1], context, secondIcon, "secondNotif")
+            assertIsNotifChip(latest!!.active[2], context, thirdIcon, "thirdNotif")
             assertThat(latest!!.overflow.size).isEqualTo(1)
-            assertIsNotifChip(latest!!.overflow[0], context, thirdIcon, "thirdNotif")
+            assertIsNotifChip(latest!!.overflow[0], context, fourthIcon, "fourthNotif")
             assertThat(latest!!.inactive.size).isEqualTo(4)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
         }
 
     @Test
-    fun visibleChipKeys_threePromotedNotifs_topTwoInList() =
+    fun visibleChipKeys_fourPromotedNotifs_topThreeInList() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.visibleChipKeys)
 
@@ -916,10 +955,16 @@
                         promotedContent =
                             PromotedNotificationContentModel.Builder("thirdNotif").build(),
                     ),
+                    activeNotificationModel(
+                        key = "fourthNotif",
+                        statusBarChipIcon = createStatusBarIconViewOrNull(),
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("fourthNotif").build(),
+                    ),
                 )
             )
 
-            assertThat(latest).containsExactly("firstNotif", "secondNotif").inOrder()
+            assertThat(latest).containsExactly("firstNotif", "secondNotif", "thirdNotif").inOrder()
         }
 
     @DisableChipsModernization
@@ -950,14 +995,14 @@
                 )
             )
 
-            assertIsCallChip(latest!!.primary, callNotificationKey)
+            assertIsCallChip(latest!!.primary, callNotificationKey, context)
             assertIsNotifChip(latest!!.secondary, context, firstIcon, "firstNotif")
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
         }
 
     @EnableChipsModernization
     @Test
-    fun chips_callAndPromotedNotifs_callAndFirstNotifActiveSecondNotifInOverflow() =
+    fun chips_callAndPromotedNotifs_callAndFirstTwoNotifsActive_thirdNotifInOverflow() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.chips)
             val unused by collectLastValue(underTest.chipsLegacy)
@@ -965,6 +1010,7 @@
             val callNotificationKey = "call"
             val firstIcon = createStatusBarIconViewOrNull()
             val secondIcon = createStatusBarIconViewOrNull()
+            val thirdIcon = createStatusBarIconViewOrNull()
             addOngoingCallState(key = callNotificationKey)
             activeNotificationListRepository.addNotifs(
                 listOf(
@@ -980,21 +1026,28 @@
                         promotedContent =
                             PromotedNotificationContentModel.Builder("secondNotif").build(),
                     ),
+                    activeNotificationModel(
+                        key = "thirdNotif",
+                        statusBarChipIcon = thirdIcon,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("thirdNotif").build(),
+                    ),
                 )
             )
 
-            assertThat(latest!!.active.size).isEqualTo(2)
-            assertIsCallChip(latest!!.active[0], callNotificationKey)
+            assertThat(latest!!.active.size).isEqualTo(3)
+            assertIsCallChip(latest!!.active[0], callNotificationKey, context)
             assertIsNotifChip(latest!!.active[1], context, firstIcon, "firstNotif")
+            assertIsNotifChip(latest!!.active[2], context, secondIcon, "secondNotif")
             assertThat(latest!!.overflow.size).isEqualTo(1)
-            assertIsNotifChip(latest!!.overflow[0], context, secondIcon, "secondNotif")
+            assertIsNotifChip(latest!!.overflow[0], context, thirdIcon, "thirdNotif")
             assertThat(latest!!.inactive.size).isEqualTo(3)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
         }
 
     @DisableChipsModernization
     @Test
-    fun chipsLegacy_screenRecordAndCallAndPromotedNotifs_notifsNotShown() =
+    fun chipsLegacy_screenRecordAndCallAndPromotedNotif_notifNotShown() =
         kosmos.runTest {
             val callNotificationKey = "call"
             val latest by collectLastValue(underTest.chipsLegacy)
@@ -1011,12 +1064,12 @@
             )
 
             assertIsScreenRecordChip(latest!!.primary)
-            assertIsCallChip(latest!!.secondary, callNotificationKey)
+            assertIsCallChip(latest!!.secondary, callNotificationKey, context)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
         }
 
     @Test
-    fun visibleChipKeys_screenRecordAndCallAndPromotedNotifs_topTwoInList() =
+    fun visibleChipKeys_screenRecordAndCallAndPromotedNotifs_topThreeInList() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.visibleChipKeys)
 
@@ -1025,20 +1078,27 @@
             screenRecordState.value = ScreenRecordModel.Recording
             activeNotificationListRepository.addNotif(
                 activeNotificationModel(
-                    key = "notif",
+                    key = "notif1",
                     statusBarChipIcon = createStatusBarIconViewOrNull(),
-                    promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
+                    promotedContent = PromotedNotificationContentModel.Builder("notif1").build(),
+                )
+            )
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = "notif2",
+                    statusBarChipIcon = createStatusBarIconViewOrNull(),
+                    promotedContent = PromotedNotificationContentModel.Builder("notif2").build(),
                 )
             )
 
             assertThat(latest)
-                .containsExactly(ScreenRecordChipViewModel.KEY, callNotificationKey)
+                .containsExactly(ScreenRecordChipViewModel.KEY, callNotificationKey, "notif1")
                 .inOrder()
         }
 
     @EnableChipsModernization
     @Test
-    fun chips_screenRecordAndCallAndPromotedNotif_notifInOverflow() =
+    fun chips_screenRecordAndCallAndPromotedNotifs_secondNotifInOverflow() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.chips)
             val unused by collectLastValue(underTest.chipsLegacy)
@@ -1055,11 +1115,22 @@
             )
             addOngoingCallState(key = callNotificationKey)
 
-            assertThat(latest!!.active.size).isEqualTo(2)
+            // This is the overflow notif
+            val notifIcon2 = createStatusBarIconViewOrNull()
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = "notif2",
+                    statusBarChipIcon = notifIcon2,
+                    promotedContent = PromotedNotificationContentModel.Builder("notif2").build(),
+                )
+            )
+
+            assertThat(latest!!.active.size).isEqualTo(3)
             assertIsScreenRecordChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
+            assertIsNotifChip(latest!!.active[2], context, notifIcon, "notif")
             assertThat(latest!!.overflow.size).isEqualTo(1)
-            assertIsNotifChip(latest!!.overflow[0], context, notifIcon, "notif")
+            assertIsNotifChip(latest!!.overflow[0], context, notifIcon2, "notif2")
             assertThat(latest!!.inactive.size).isEqualTo(2)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
         }
@@ -1092,7 +1163,7 @@
             addOngoingCallState(callNotificationKey)
 
             // THEN the higher priority call chip is used
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
 
             // WHEN the higher priority media projection chip is added
             mediaProjectionState.value =
@@ -1145,7 +1216,7 @@
             mediaProjectionState.value = MediaProjectionState.NotProjecting
 
             // THEN the lower priority call is used
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
 
             // WHEN the higher priority call is removed
             removeOngoingCallState(key = callNotificationKey)
@@ -1186,7 +1257,7 @@
 
             // THEN the higher priority call chip is used as primary and notif is demoted to
             // secondary
-            assertIsCallChip(latest!!.primary, callNotificationKey)
+            assertIsCallChip(latest!!.primary, callNotificationKey, context)
             assertIsNotifChip(latest!!.secondary, context, notifIcon, "notif")
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
 
@@ -1201,7 +1272,7 @@
             // THEN the higher priority media projection chip is used as primary and call is demoted
             // to secondary (and notif is dropped altogether)
             assertIsShareToAppChip(latest!!.primary)
-            assertIsCallChip(latest!!.secondary, callNotificationKey)
+            assertIsCallChip(latest!!.secondary, callNotificationKey, context)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
 
             // WHEN the higher priority screen record chip is added
@@ -1234,15 +1305,16 @@
     @Test
     fun chips_movesChipsAroundAccordingToPriority() =
         kosmos.runTest {
+            systemClock.setCurrentTimeMillis(10_000)
             val callNotificationKey = "call"
             // Start with just the lowest priority chip active
-            val notifIcon = createStatusBarIconViewOrNull()
+            val notif1Icon = createStatusBarIconViewOrNull()
             setNotifs(
                 listOf(
                     activeNotificationModel(
-                        key = "notif",
-                        statusBarChipIcon = notifIcon,
-                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
+                        key = "notif1",
+                        statusBarChipIcon = notif1Icon,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif1").build(),
                     )
                 )
             )
@@ -1254,7 +1326,7 @@
             val unused by collectLastValue(underTest.chipsLegacy)
 
             assertThat(latest!!.active.size).isEqualTo(1)
-            assertIsNotifChip(latest!!.active[0], context, notifIcon, "notif")
+            assertIsNotifChip(latest!!.active[0], context, notif1Icon, "notif1")
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(4)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
@@ -1262,10 +1334,10 @@
             // WHEN the higher priority call chip is added
             addOngoingCallState(key = callNotificationKey)
 
-            // THEN the higher priority call chip and notif are active in that order
+            // THEN the higher priority call chip and notif1 are active in that order
             assertThat(latest!!.active.size).isEqualTo(2)
-            assertIsCallChip(latest!!.active[0], callNotificationKey)
-            assertIsNotifChip(latest!!.active[1], context, notifIcon, "notif")
+            assertIsCallChip(latest!!.active[0], callNotificationKey, context)
+            assertIsNotifChip(latest!!.active[1], context, notif1Icon, "notif1")
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(3)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
@@ -1278,56 +1350,63 @@
                     createTask(taskId = 1),
                 )
 
-            // THEN the higher priority media projection chip and call are active in that order, and
-            // notif is demoted to overflow
-            assertThat(latest!!.active.size).isEqualTo(2)
+            // THEN media projection, then call, then notif1 are active
+            assertThat(latest!!.active.size).isEqualTo(3)
             assertIsShareToAppChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
-            assertThat(latest!!.overflow.size).isEqualTo(1)
-            assertIsNotifChip(latest!!.overflow[0], context, notifIcon, "notif")
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
+            assertIsNotifChip(latest!!.active[2], context, notif1Icon, "notif1")
+            assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(2)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
 
-            // WHEN the higher priority screen record chip is added
+            // WHEN the screen record chip is added, which replaces media projection
             screenRecordState.value = ScreenRecordModel.Recording
-
-            // THEN the higher priority screen record chip and call are active in that order, and
-            // media projection and notif are demoted in overflow
-            assertThat(latest!!.active.size).isEqualTo(2)
-            assertIsScreenRecordChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
-            assertThat(latest!!.overflow.size).isEqualTo(2)
-            assertIsShareToAppChip(latest!!.overflow[0])
-            assertIsNotifChip(latest!!.overflow[1], context, notifIcon, "notif")
-            assertThat(latest!!.inactive.size).isEqualTo(1)
-            assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
-
-            // WHEN screen record and call is dropped
-            screenRecordState.value = ScreenRecordModel.DoingNothing
-            setNotifs(
-                listOf(
-                    activeNotificationModel(
-                        key = "notif",
-                        statusBarChipIcon = notifIcon,
-                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
-                    )
+            // AND another notification is added
+            systemClock.advanceTime(2_000)
+            val notif2Icon = createStatusBarIconViewOrNull()
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = "notif2",
+                    statusBarChipIcon = notif2Icon,
+                    promotedContent = PromotedNotificationContentModel.Builder("notif2").build(),
                 )
             )
 
-            // THEN media projection and notif remain
-            assertThat(latest!!.active.size).isEqualTo(2)
+            // THEN screen record, then call, then notif2 are active
+            assertThat(latest!!.active.size).isEqualTo(3)
+            assertIsScreenRecordChip(latest!!.active[0])
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
+            assertIsNotifChip(latest!!.active[2], context, notif2Icon, "notif2")
+
+            // AND notif1 and media projection is demoted in overflow
+            assertThat(latest!!.overflow.size).isEqualTo(2)
+            assertIsShareToAppChip(latest!!.overflow[0])
+            assertIsNotifChip(latest!!.overflow[1], context, notif1Icon, "notif1")
+            assertThat(latest!!.inactive.size).isEqualTo(1)
+            assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
+
+            // WHEN screen record and call are dropped
+            screenRecordState.value = ScreenRecordModel.DoingNothing
+            removeOngoingCallState(callNotificationKey)
+
+            // THEN media projection, notif2, and notif1 remain
+            assertThat(latest!!.active.size).isEqualTo(3)
             assertIsShareToAppChip(latest!!.active[0])
-            assertIsNotifChip(latest!!.active[1], context, notifIcon, "notif")
+            assertIsNotifChip(latest!!.active[1], context, notif2Icon, "notif2")
+            assertIsNotifChip(latest!!.active[2], context, notif1Icon, "notif1")
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(3)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
 
             // WHEN media projection is dropped
             mediaProjectionState.value = MediaProjectionState.NotProjecting
+            // AND notif2 is dropped
+            systemClock.advanceTime(2_000)
+            activeNotificationListRepository.removeNotif("notif2")
 
-            // THEN only notif is active
+            // THEN only notif1 is active
             assertThat(latest!!.active.size).isEqualTo(1)
-            assertIsNotifChip(latest!!.active[0], context, notifIcon, "notif")
+            assertIsNotifChip(latest!!.active[0], context, notif1Icon, "notif1")
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(4)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationCloseButtonTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationCloseButtonTest.kt
new file mode 100644
index 0000000..e4b2e6c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationCloseButtonTest.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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
+
+import android.app.Notification
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.testing.TestableLooper
+import android.view.MotionEvent
+import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.stub
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import org.junit.Before
+
+private fun getCloseButton(row: ExpandableNotificationRow): View {
+    val contractedView = row.showingLayout?.contractedChild!!
+    return contractedView.findViewById(com.android.internal.R.id.close_button)
+}
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationCloseButtonTest : SysuiTestCase() {
+    private lateinit var helper: NotificationTestHelper
+
+    @Before
+    fun setUp() {
+        helper = NotificationTestHelper(
+            mContext,
+            mDependency,
+            TestableLooper.get(this)
+        )
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_NOTIFICATION_ADD_X_ON_HOVER_TO_DISMISS)
+    fun verifyWhenFeatureDisabled() {
+        // Enable the notification row to dismiss.
+        helper.dismissibilityProvider.stub {
+            on { isDismissable(any()) } doReturn true
+        }
+
+        // By default, the close button should be gone.
+        val row = createNotificationRow()
+        val closeButton = getCloseButton(row)
+        assertThat(closeButton).isNotNull()
+        assertThat(closeButton.visibility).isEqualTo(View.GONE)
+
+        val hoverEnterEvent = MotionEvent.obtain(
+            0/*downTime=*/,
+            0/*eventTime=*/,
+            MotionEvent.ACTION_HOVER_ENTER,
+            0f/*x=*/,
+            0f/*y=*/,
+            0/*metaState*/
+        )
+
+        // The close button should not show if the feature is disabled.
+        row.onInterceptHoverEvent(hoverEnterEvent)
+        assertThat(closeButton.visibility).isEqualTo(View.GONE)
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_NOTIFICATION_ADD_X_ON_HOVER_TO_DISMISS)
+    fun verifyOnDismissableNotification() {
+        // Enable the notification row to dismiss.
+        helper.dismissibilityProvider.stub {
+            on { isDismissable(any()) } doReturn true
+        }
+
+        // By default, the close button should be gone.
+        val row = createNotificationRow()
+        val closeButton = getCloseButton(row)
+        assertThat(closeButton).isNotNull()
+        assertThat(closeButton.visibility).isEqualTo(View.GONE)
+
+        val hoverEnterEvent = MotionEvent.obtain(
+            0/*downTime=*/,
+            0/*eventTime=*/,
+            MotionEvent.ACTION_HOVER_ENTER,
+            0f/*x=*/,
+            0f/*y=*/,
+            0/*metaState*/
+        )
+
+        // When the row is hovered, the close button should show.
+        row.onInterceptHoverEvent(hoverEnterEvent)
+        assertThat(closeButton.visibility).isEqualTo(View.VISIBLE)
+
+        val hoverExitEvent = MotionEvent.obtain(
+            0/*downTime=*/,
+            0/*eventTime=*/,
+            MotionEvent.ACTION_HOVER_EXIT,
+            0f/*x=*/,
+            0f/*y=*/,
+            0/*metaState*/
+        )
+
+        // When hover exits the row, the close button should be gone again.
+        row.onInterceptHoverEvent(hoverExitEvent)
+        assertThat(closeButton.visibility).isEqualTo(View.GONE)
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_NOTIFICATION_ADD_X_ON_HOVER_TO_DISMISS)
+    fun verifyOnUndismissableNotification() {
+        // By default, the close button should be gone.
+        val row = createNotificationRow()
+        val closeButton = getCloseButton(row)
+        assertThat(closeButton).isNotNull()
+        assertThat(closeButton.visibility).isEqualTo(View.GONE)
+
+        val hoverEnterEvent = MotionEvent.obtain(
+            0/*downTime=*/,
+            0/*eventTime=*/,
+            MotionEvent.ACTION_HOVER_ENTER,
+            0f/*x=*/,
+            0f/*y=*/,
+            0/*metaState*/
+        )
+
+        // Because the host notification cannot be dismissed, the close button should not show.
+        row.onInterceptHoverEvent(hoverEnterEvent)
+        assertThat(closeButton.visibility).isEqualTo(View.GONE)
+    }
+
+    private fun createNotificationRow(): ExpandableNotificationRow {
+        val notification = Notification.Builder(context, "channel")
+            .setContentTitle("title")
+            .setContentText("text")
+            .setSmallIcon(R.drawable.ic_person)
+            .build()
+
+       return helper.createRow(notification)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
index 0f1cdac..fdc6657 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
@@ -31,6 +31,8 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.shade.domain.interactor.enableDualShade
+import com.android.systemui.shade.domain.interactor.enableSingleShade
 import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
 import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_DELAYED_STACK_FADE_IN
@@ -69,6 +71,7 @@
     @Test
     fun updateBounds() =
         testScope.runTest {
+            kosmos.enableSingleShade()
             val radius = MutableStateFlow(32)
             val leftOffset = MutableStateFlow(0)
             val shape by
@@ -106,7 +109,7 @@
                     )
                 )
 
-            // When: QuickSettings shows up full screen
+            // When: QuickSettings shows up full screen on single shade.
             fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
@@ -115,6 +118,10 @@
             sceneInteractor.setTransitionState(transitionState)
             // Then: shape is null
             assertThat(shape).isNull()
+
+            // Same scenario on Dual Shade, shape should have clipping bounds
+            kosmos.enableDualShade()
+            assertThat(shape).isNotNull()
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
similarity index 68%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
index 83fd5dc..a13b864 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
@@ -34,123 +34,122 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper
-class BundleEntryTest : SysuiTestCase() {
-    private lateinit var underTest: BundleEntry
+class BundleEntryAdapterTest : SysuiTestCase() {
+    private lateinit var underTest: BundleEntryAdapter
 
-    @get:Rule
-    val setFlagsRule = SetFlagsRule()
+    @get:Rule val setFlagsRule = SetFlagsRule()
 
     @Before
     fun setUp() {
-        underTest = BundleEntry("key")
+        underTest = BundleEntryAdapter(BundleEntry("key"))
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getParent_adapter() {
-        assertThat(underTest.entryAdapter.parent).isEqualTo(GroupEntry.ROOT_ENTRY)
+        assertThat(underTest.parent).isEqualTo(GroupEntry.ROOT_ENTRY)
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isTopLevelEntry_adapter() {
-        assertThat(underTest.entryAdapter.isTopLevelEntry).isTrue()
+        assertThat(underTest.isTopLevelEntry).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getRow_adapter() {
-        assertThat(underTest.entryAdapter.row).isNull()
+        assertThat(underTest.row).isNull()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isGroupRoot_adapter() {
-        assertThat(underTest.entryAdapter.isGroupRoot).isTrue()
+        assertThat(underTest.isGroupRoot).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getKey_adapter() {
-        assertThat(underTest.entryAdapter.key).isEqualTo("key")
+        assertThat(underTest.key).isEqualTo("key")
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isClearable_adapter() {
-        assertThat(underTest.entryAdapter.isClearable).isTrue()
+        assertThat(underTest.isClearable).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getSummarization_adapter() {
-        assertThat(underTest.entryAdapter.summarization).isNull()
+        assertThat(underTest.summarization).isNull()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getContrastedColor_adapter() {
-        assertThat(underTest.entryAdapter.getContrastedColor(context, false, Color.WHITE))
+        assertThat(underTest.getContrastedColor(context, false, Color.WHITE))
             .isEqualTo(Notification.COLOR_DEFAULT)
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun canPeek_adapter() {
-        assertThat(underTest.entryAdapter.canPeek()).isFalse()
+        assertThat(underTest.canPeek()).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getWhen_adapter() {
-        assertThat(underTest.entryAdapter.`when`).isEqualTo(0)
+        assertThat(underTest.`when`).isEqualTo(0)
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isColorized() {
-        assertThat(underTest.entryAdapter.isColorized).isFalse()
+        assertThat(underTest.isColorized).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getSbn() {
-        assertThat(underTest.entryAdapter.sbn).isNull()
+        assertThat(underTest.sbn).isNull()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun canDragAndDrop() {
-        assertThat(underTest.entryAdapter.canDragAndDrop()).isFalse()
+        assertThat(underTest.canDragAndDrop()).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isBubble() {
-        assertThat(underTest.entryAdapter.isBubbleCapable).isFalse()
+        assertThat(underTest.isBubbleCapable).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getStyle() {
-        assertThat(underTest.entryAdapter.style).isNull()
+        assertThat(underTest.style).isNull()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getSectionBucket() {
-        assertThat(underTest.entryAdapter.sectionBucket).isEqualTo(underTest.bucket)
+        assertThat(underTest.sectionBucket).isEqualTo(underTest.entry.bucket)
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isAmbient() {
-        assertThat(underTest.entryAdapter.isAmbient).isFalse()
+        assertThat(underTest.isAmbient).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun canShowFullScreen() {
-        assertThat(underTest.entryAdapter.isFullScreenCapable()).isFalse()
+        assertThat(underTest.isFullScreenCapable()).isFalse()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
new file mode 100644
index 0000000..b6889af
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.collection
+
+import android.app.ActivityManager
+import android.app.Notification
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.RankingBuilder
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class NotificationEntryAdapterTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val factory: EntryAdapterFactory = kosmos.entryAdapterFactory
+    private lateinit var underTest: NotificationEntryAdapter
+
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getParent_adapter() {
+        val ge = GroupEntryBuilder().build()
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .setParent(ge)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.parent).isEqualTo(entry.parent)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isTopLevelEntry_adapter() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .setParent(GroupEntry.ROOT_ENTRY)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isTopLevelEntry).isTrue()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getKey_adapter() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.key).isEqualTo(entry.key)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getRow_adapter() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.row).isEqualTo(entry.row)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isGroupRoot_adapter_groupSummary() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setGroupSummary(true)
+                .setGroup("key")
+                .build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .setParent(GroupEntry.ROOT_ENTRY)
+                .build()
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isGroupRoot).isFalse()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isGroupRoot_adapter_groupChild() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setGroupSummary(true)
+                .setGroup("key")
+                .build()
+
+        val parent = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
+        val groupEntry = GroupEntryBuilder().setSummary(parent)
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .setParent(groupEntry.build())
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isGroupRoot).isFalse()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isClearable_adapter() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isClearable).isEqualTo(entry.isClearable)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getSummarization_adapter() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+        val ranking = RankingBuilder(entry.ranking).setSummarization("hello").build()
+        entry.setRanking(ranking)
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.summarization).isEqualTo("hello")
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getIcons_adapter() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.icons).isEqualTo(entry.icons)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isColorized() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setColorized(true)
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isColorized).isEqualTo(entry.sbn.notification.isColorized)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getSbn() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.sbn).isEqualTo(entry.sbn)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun canDragAndDrop() {
+        val pi = Mockito.mock(PendingIntent::class.java)
+        Mockito.`when`(pi.isActivity).thenReturn(true)
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentIntent(pi)
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.canDragAndDrop()).isTrue()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isBubble() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setFlag(Notification.FLAG_BUBBLE, true)
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isBubbleCapable).isEqualTo(entry.isBubble)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getStyle() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setStyle(Notification.BigTextStyle())
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.style).isEqualTo(entry.notificationStyle)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getSectionBucket() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setStyle(Notification.BigTextStyle())
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+        entry.bucket = BUCKET_ALERTING
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.sectionBucket).isEqualTo(BUCKET_ALERTING)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isAmbient() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(NotificationManager.IMPORTANCE_MIN)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isAmbient).isTrue()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun canShowFullScreen() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setFullScreenIntent(Mockito.mock(PendingIntent::class.java), true)
+                .build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(NotificationManager.IMPORTANCE_MIN)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isFullScreenCapable).isTrue()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun onNotificationBubbleIconClicked() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(NotificationManager.IMPORTANCE_MIN)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+
+        underTest.onNotificationBubbleIconClicked()
+        verify((factory as? EntryAdapterFactoryImpl)?.getNotificationActivityStarter())
+            ?.onNotificationBubbleIconClicked(entry)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 4810813..790b2c3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -21,24 +21,17 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.Notification.FLAG_BUBBLE;
 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
 import static android.app.Notification.FLAG_PROMOTED_ONGOING;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 
 import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
 import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
-
-import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -66,8 +59,6 @@
 import com.android.systemui.statusbar.SbnBuilder;
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
 import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
@@ -458,336 +449,6 @@
         // no crash, good
     }
 
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getParent_adapter() {
-        GroupEntry ge = new GroupEntryBuilder()
-                .build();
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setParent(ge)
-                .build();
-
-        assertThat(entry.getEntryAdapter().getParent()).isEqualTo(entry.getParent());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isTopLevelEntry_adapter() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setParent(GroupEntry.ROOT_ENTRY)
-                .build();
-
-        assertThat(entry.getEntryAdapter().isTopLevelEntry()).isTrue();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getKey_adapter() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-
-        assertThat(entry.getEntryAdapter().getKey()).isEqualTo(entry.getKey());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getRow_adapter() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().getRow()).isEqualTo(entry.getRow());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isGroupRoot_adapter_groupSummary() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setGroupSummary(true)
-                .setGroup("key")
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setParent(GroupEntry.ROOT_ENTRY)
-                .build();
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().isGroupRoot()).isFalse();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isGroupRoot_adapter_groupChild() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setGroupSummary(true)
-                .setGroup("key")
-                .build();
-
-        NotificationEntry parent = new NotificationEntryBuilder()
-                .setParent(GroupEntry.ROOT_ENTRY)
-                .build();
-        GroupEntryBuilder groupEntry = new GroupEntryBuilder()
-                .setSummary(parent);
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setParent(groupEntry.build())
-                .build();
-
-        assertThat(entry.getEntryAdapter().isGroupRoot()).isFalse();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isClearable_adapter() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().isClearable()).isEqualTo(entry.isClearable());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getSummarization_adapter() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-        Ranking ranking = new RankingBuilder(entry.getRanking())
-                .setSummarization("hello")
-                .build();
-        entry.setRanking(ranking);
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().getSummarization()).isEqualTo("hello");
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getIcons_adapter() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().getIcons()).isEqualTo(entry.getIcons());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isColorized() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setColorized(true)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().isColorized()).isEqualTo(
-                entry.getSbn().getNotification().isColorized());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getSbn() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().getSbn()).isEqualTo(
-                entry.getSbn());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void canDragAndDrop() {
-        PendingIntent pi = mock(PendingIntent.class);
-        when(pi.isActivity()).thenReturn(true);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentIntent(pi)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().canDragAndDrop()).isTrue();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isBubble() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setFlag(FLAG_BUBBLE, true)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().isBubbleCapable()).isEqualTo(entry.isBubble());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getStyle() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setStyle(new Notification.BigTextStyle())
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().getStyle()).isEqualTo(entry.getNotificationStyle());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getSectionBucket() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setStyle(new Notification.BigTextStyle())
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        entry.setBucket(BUCKET_ALERTING);
-
-        assertThat(entry.getEntryAdapter().getSectionBucket()).isEqualTo(BUCKET_ALERTING);
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isAmbient() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .setImportance(IMPORTANCE_MIN)
-                .build();
-
-        assertThat(entry.getEntryAdapter().isAmbient()).isTrue();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void canShowFullScreen() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setFullScreenIntent(mock(PendingIntent.class), true)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .setImportance(IMPORTANCE_MIN)
-                .build();
-
-        assertThat(entry.getEntryAdapter().isFullScreenCapable()).isTrue();
-    }
-
     private Notification.Action createContextualAction(String title) {
         return new Notification.Action.Builder(
                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
index 8e6aedca..9e27c79 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.notification.collection.render
 
-import android.os.Build
-import android.os.UserHandle
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
@@ -26,6 +24,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.assertLogsWtf
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -36,12 +35,13 @@
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
-import org.junit.Assume
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -54,11 +54,11 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class GroupExpansionManagerTest : SysuiTestCase() {
-    @get:Rule
-    val setFlagsRule = SetFlagsRule()
+    @get:Rule val setFlagsRule = SetFlagsRule()
 
     private lateinit var underTest: GroupExpansionManagerImpl
 
+    private val kosmos = testKosmos()
     private lateinit var testHelper: NotificationTestHelper
     private val dumpManager: DumpManager = mock()
     private val groupMembershipManager: GroupMembershipManager = mock()
@@ -66,15 +66,14 @@
     private val pipeline: NotifPipeline = mock()
     private lateinit var beforeRenderListListener: OnBeforeRenderListListener
 
+    private val factory: EntryAdapterFactoryImpl = kosmos.entryAdapterFactory
     private lateinit var summary1: NotificationEntry
     private lateinit var summary2: NotificationEntry
     private lateinit var entries: List<ListEntry>
 
     private fun notificationEntry(pkg: String, id: Int, parent: ExpandableNotificationRow?) =
         NotificationEntryBuilder().setPkg(pkg).setId(id).build().apply {
-            row = testHelper.createRow().apply {
-                setIsChildInGroup(true, parent)
-            }
+            row = testHelper.createRow().apply { setIsChildInGroup(true, parent) }
         }
 
     @Before
@@ -91,7 +90,7 @@
                         listOf(
                             notificationEntry("foo", 2, summary1.row),
                             notificationEntry("foo", 3, summary1.row),
-                            notificationEntry("foo", 4, summary1.row)
+                            notificationEntry("foo", 4, summary1.row),
                         )
                     )
                     .build(),
@@ -101,11 +100,11 @@
                         listOf(
                             notificationEntry("bar", 2, summary2.row),
                             notificationEntry("bar", 3, summary2.row),
-                            notificationEntry("bar", 4, summary2.row)
+                            notificationEntry("bar", 4, summary2.row),
                         )
                     )
                     .build(),
-                notificationEntry("baz", 1, null)
+                notificationEntry("baz", 1, null),
             )
 
         whenever(groupMembershipManager.getGroupSummary(summary1)).thenReturn(summary1)
@@ -135,18 +134,20 @@
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun notifyOnlyOnChange_withEntryAdapter() {
+        val entryAdapter1 = factory.create(summary1)
+        val entryAdapter2 = factory.create(summary2)
         var listenerCalledCount = 0
         underTest.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
 
-        underTest.setGroupExpanded(summary1.entryAdapter, false)
+        underTest.setGroupExpanded(entryAdapter1, false)
         assertThat(listenerCalledCount).isEqualTo(0)
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
+        underTest.setGroupExpanded(entryAdapter1, true)
         assertThat(listenerCalledCount).isEqualTo(1)
-        underTest.setGroupExpanded(summary2.entryAdapter, true)
+        underTest.setGroupExpanded(entryAdapter2, true)
         assertThat(listenerCalledCount).isEqualTo(2)
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
+        underTest.setGroupExpanded(entryAdapter1, true)
         assertThat(listenerCalledCount).isEqualTo(2)
-        underTest.setGroupExpanded(summary2.entryAdapter, false)
+        underTest.setGroupExpanded(entryAdapter2, false)
         assertThat(listenerCalledCount).isEqualTo(3)
     }
 
@@ -168,16 +169,17 @@
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun expandUnattachedEntryAdapter() {
+        val entryAdapter = factory.create(summary1)
         // First, expand the entry when it is attached.
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
-        assertThat(underTest.isGroupExpanded(summary1.entryAdapter)).isTrue()
+        underTest.setGroupExpanded(entryAdapter, true)
+        assertThat(underTest.isGroupExpanded(entryAdapter)).isTrue()
 
         // Un-attach it, and un-expand it.
         NotificationEntryBuilder.setNewParent(summary1, null)
-        underTest.setGroupExpanded(summary1.entryAdapter, false)
+        underTest.setGroupExpanded(entryAdapter, false)
 
         // Expanding again should throw.
-        assertLogsWtf { underTest.setGroupExpanded(summary1.entryAdapter, true) }
+        assertLogsWtf { underTest.setGroupExpanded(entryAdapter, true) }
     }
 
     @Test
@@ -207,6 +209,7 @@
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun syncWithPipeline_withEntryAdapter() {
+        val entryAdapter = factory.create(summary1)
         underTest.attach(pipeline)
         beforeRenderListListener = withArgCaptor {
             verify(pipeline).addOnBeforeRenderListListener(capture())
@@ -219,7 +222,7 @@
         verify(listener, never()).onGroupExpansionChange(any(), any())
 
         // Expand one of the groups.
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
+        underTest.setGroupExpanded(entryAdapter, true)
         verify(listener).onGroupExpansionChange(summary1.row, true)
 
         // Empty the pipeline list and verify that the group is no longer expanded.
@@ -231,11 +234,15 @@
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isGroupExpanded() {
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
+        val entryAdapter = summary1.row.entryAdapter
+        underTest.setGroupExpanded(entryAdapter, true)
 
-        assertThat(underTest.isGroupExpanded(summary1.entryAdapter)).isTrue();
-        assertThat(underTest.isGroupExpanded(
-            (entries[0] as? GroupEntry)?.getChildren()?.get(0)?.entryAdapter))
-            .isTrue();
+        assertThat(underTest.isGroupExpanded(entryAdapter)).isTrue()
+        assertThat(
+                underTest.isGroupExpanded(
+                    (entries[0] as? GroupEntry)?.getChildren()?.get(0)?.row?.entryAdapter
+                )
+            )
+            .isTrue()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
index 2bbf094..0ccf585 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
@@ -22,10 +22,13 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -35,8 +38,10 @@
 @RunWith(AndroidJUnit4::class)
 class GroupMembershipManagerTest : SysuiTestCase() {
 
-    @get:Rule
-    val setFlagsRule = SetFlagsRule()
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    private val kosmos = testKosmos()
+    private val factory: EntryAdapterFactoryImpl = kosmos.entryAdapterFactory
 
     private var underTest = GroupMembershipManagerImpl()
 
@@ -144,14 +149,14 @@
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isChildEntryAdapterInGroup_topLevel() {
         val topLevelEntry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
-        assertThat(underTest.isChildInGroup(topLevelEntry.entryAdapter)).isFalse()
+        assertThat(underTest.isChildInGroup(factory.create(topLevelEntry))).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isChildEntryAdapterInGroup_noParent() {
         val noParentEntry = NotificationEntryBuilder().setParent(null).build()
-        assertThat(underTest.isChildInGroup(noParentEntry.entryAdapter)).isFalse()
+        assertThat(underTest.isChildInGroup(factory.create(noParentEntry))).isFalse()
     }
 
     @Test
@@ -165,7 +170,7 @@
                 .build()
         GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
 
-        assertThat(underTest.isChildInGroup(summary.entryAdapter)).isFalse()
+        assertThat(underTest.isChildInGroup(factory.create(summary))).isFalse()
     }
 
     @Test
@@ -180,14 +185,14 @@
         val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build()
         GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build()
 
-        assertThat(underTest.isChildInGroup(entry.entryAdapter)).isTrue()
+        assertThat(underTest.isChildInGroup(factory.create(entry))).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isGroupRoot_topLevelEntry() {
         val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
-        assertThat(underTest.isGroupRoot(entry.entryAdapter)).isFalse()
+        assertThat(underTest.isGroupRoot(factory.create(entry))).isFalse()
     }
 
     @Test
@@ -201,7 +206,7 @@
                 .build()
         GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
 
-        assertThat(underTest.isGroupRoot(summary.entryAdapter)).isTrue()
+        assertThat(underTest.isGroupRoot(factory.create(summary))).isTrue()
     }
 
     @Test
@@ -216,6 +221,6 @@
         val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build()
         GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build()
 
-        assertThat(underTest.isGroupRoot(entry.entryAdapter)).isFalse()
+        assertThat(underTest.isGroupRoot(factory.create(entry))).isFalse()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
index e22acd5..9804932 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.log.assertLogsWtfs
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.shade.shadeTestUtil
@@ -205,8 +206,7 @@
     fun pinnedHeadsUpStatuses_pinnedByUser_butFlagOff_returnsNotPinned() {
         val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
         entry.row = testHelper.createRow()
-        underTest.showNotification(entry, isPinnedByUser = true)
-
+        assertLogsWtfs { underTest.showNotification(entry, isPinnedByUser = true) }
         assertThat(underTest.hasPinnedHeadsUp()).isFalse()
         assertThat(underTest.pinnedHeadsUpStatus()).isEqualTo(PinnedStatus.NotPinned)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
index 216fd2d..3116143 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
@@ -57,7 +57,8 @@
 
     private val underTest = kosmos.promotedNotificationContentExtractor
     private val systemClock = kosmos.fakeSystemClock
-    private val rowImageInflater = RowImageInflater.newInstance(previousIndex = null)
+    private val rowImageInflater =
+        RowImageInflater.newInstance(previousIndex = null, reinflating = false)
     private val imageModelProvider by lazy { rowImageInflater.useForContentModel() }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index f060cae..bb12eff 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -37,9 +37,12 @@
 import com.android.systemui.statusbar.SbnBuilder
 import com.android.systemui.statusbar.SmartReplyController
 import com.android.systemui.statusbar.notification.ColorUpdateLogger
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.collection.EntryAdapter
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactory
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
 import com.android.systemui.statusbar.notification.collection.render.FakeNodeController
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
@@ -47,6 +50,7 @@
 import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController.BUBBLES_SETTING_URI
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
@@ -112,6 +116,7 @@
     private val uiEventLogger: UiEventLogger = mock()
     private val msdlPlayer: MSDLPlayer = mock()
     private val rebindingTracker: NotificationRebindingTracker = mock()
+    private val entryAdapterFactory: EntryAdapterFactory = mock()
     private lateinit var controller: ExpandableNotificationRowController
 
     @Before
@@ -154,6 +159,7 @@
                 uiEventLogger,
                 msdlPlayer,
                 rebindingTracker,
+                entryAdapterFactory,
             )
         whenever(view.childrenContainer).thenReturn(childrenContainer)
 
@@ -277,8 +283,10 @@
         whenever(view.privateLayout).thenReturn(childView)
         val entryAdapter = mock(EntryAdapter::class.java)
         val sbn =
-            SbnBuilder().setNotification(Notification.Builder(mContext).build())
-                .setUser(UserHandle.of(view.entry.sbn.userId)).build()
+            SbnBuilder()
+                .setNotification(Notification.Builder(mContext).build())
+                .setUser(UserHandle.of(view.entry.sbn.userId))
+                .build()
         whenever(entryAdapter.sbn).thenReturn(sbn)
         whenever(view.entryAdapter).thenReturn(entryAdapter)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
index ce3aee1..31413b0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
@@ -41,7 +41,6 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor
-import com.android.systemui.statusbar.notification.collection.EntryAdapter
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
@@ -204,7 +203,7 @@
         val result =
             NotificationRowContentBinderImpl.InflationProgress(
                 packageContext = mContext,
-                rowImageInflater = RowImageInflater.newInstance(null),
+                rowImageInflater = RowImageInflater.newInstance(null, reinflating = false),
                 remoteViews = NewRemoteViews(),
                 contentModel = NotificationContentModel(headsUpStatusBarModel),
                 promotedContent = null,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index c376fad..6415f8c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -60,20 +60,24 @@
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.flags.FakeFeatureFlagsClassic;
 import com.android.systemui.flags.FeatureFlagsClassic;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.media.controls.util.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
+import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
@@ -87,6 +91,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -101,11 +106,6 @@
 import com.android.systemui.util.time.SystemClockImpl;
 import com.android.systemui.wmshell.BubblesTestActivity;
 
-import kotlin.coroutines.CoroutineContext;
-
-import kotlinx.coroutines.flow.StateFlowKt;
-import kotlinx.coroutines.test.TestScope;
-
 import org.mockito.ArgumentCaptor;
 
 import java.util.List;
@@ -114,6 +114,10 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
+import kotlin.coroutines.CoroutineContext;
+import kotlinx.coroutines.flow.StateFlowKt;
+import kotlinx.coroutines.test.TestScope;
+
 /**
  * A helper class to create {@link ExpandableNotificationRow} (for both individual and group
  * notifications).
@@ -734,7 +738,16 @@
         mBindPipelineEntryListener.onEntryInit(entry);
         mBindPipeline.manageRow(entry, row);
 
+        EntryAdapter entryAdapter = new EntryAdapterFactoryImpl(
+                mock(NotificationActivityStarter.class),
+                mock(MetricsLogger.class),
+                mock(PeopleNotificationIdentifier.class),
+                mock(NotificationIconStyleProvider.class),
+                mock(VisualStabilityCoordinator.class)
+        ).create(entry);
+
         row.initialize(
+                entryAdapter,
                 entry,
                 mock(RemoteInputViewSubcomponent.Factory.class),
                 APP_NAME,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index 14bbd38..761ed61 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -27,6 +27,7 @@
 import android.view.View;
 import android.widget.RemoteViews;
 
+import androidx.compose.ui.platform.ComposeView;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -35,7 +36,9 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModelImpl;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -273,6 +276,22 @@
         Assert.assertEquals(1f, header.getTopRoundness(), 0.001f);
     }
 
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    public void initBundleHeader_composeview_is_initialized_once() {
+        View currentView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
+        Assert.assertFalse(currentView instanceof ComposeView);
+
+        BundleHeaderViewModelImpl viewModel = new BundleHeaderViewModelImpl();
+        mChildrenContainer.initBundleHeader(viewModel);
+        currentView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
+        Assert.assertTrue(currentView instanceof ComposeView);
+
+        mChildrenContainer.initBundleHeader(viewModel);
+        View finalView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
+        Assert.assertEquals(currentView, finalView);
+    }
+
     private NotificationHeaderView createHeaderView(boolean lowPriority) {
         Notification notification = mNotificationTestHelper.createNotification();
         final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
index f6c031f..8e3bdc4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
@@ -219,7 +219,6 @@
             )
     }
 
-    @DisableFlags(Flags.FLAG_PHYSICAL_NOTIFICATION_MOVEMENT)
     @Test
     @EnableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME)
     fun startAnimationForEvents_headsUpFromBottom_startsHeadsUpAppearAnim_flagOn() {
@@ -246,7 +245,7 @@
     }
 
     @Test
-    @DisableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME)
+    @DisableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME, Flags.FLAG_PHYSICAL_NOTIFICATION_MOVEMENT)
     fun startAnimationForEvents_startsHeadsUpDisappearAnim_flagOff() {
         val disappearDuration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR.toLong()
         val event = AnimationEvent(view, AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR)
@@ -277,6 +276,7 @@
 
     @Test
     @EnableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME)
+    @DisableFlags(Flags.FLAG_PHYSICAL_NOTIFICATION_MOVEMENT)
     fun startAnimationForEvents_startsHeadsUpDisappearAnim_flagOn() {
         val disappearDuration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR.toLong()
         val event = AnimationEvent(view, AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
index 14e7cdc..3b836b7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
-import android.testing.TestableLooper.RunWithLooper
 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.flags.EnableSceneContainer
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackAppearanceInteractor
 import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
@@ -32,7 +32,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-@RunWithLooper
+@EnableSceneContainer
 class NotificationsPlaceholderViewModelTest : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val underTest by lazy { kosmos.notificationsPlaceholderViewModel }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index e2330f4..1ea41de 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -61,8 +61,8 @@
 import com.android.systemui.keyguard.shared.model.TransitionState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.log.SessionTracker;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt
index 47967b3..670c195 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.commandQueue
 import com.android.systemui.statusbar.lockscreenShadeTransitionController
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.domain.interactor.notificationAlertsInteractor
@@ -54,6 +55,7 @@
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
 import com.android.systemui.statusbar.notification.stack.notificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.visualInterruptionDecisionProvider
@@ -105,10 +107,14 @@
     private val notificationAlertsInteractor = kosmos.notificationAlertsInteractor
     private val visualInterruptionDecisionProvider = kosmos.visualInterruptionDecisionProvider
 
+    private lateinit var factory: EntryAdapterFactoryImpl
+
     private lateinit var underTest: StatusBarNotificationPresenter
 
     @Before
     fun setup() {
+        factory = kosmos.entryAdapterFactory
+
         underTest = createPresenter()
         if (VisualInterruptionRefactor.isEnabled) {
             verifyAndCaptureSuppressors()
@@ -451,7 +457,7 @@
     private fun createRow(entry: NotificationEntry): ExpandableNotificationRow {
         val row: ExpandableNotificationRow = mock()
         if (NotificationBundleUi.isEnabled) {
-            whenever(row.entryAdapter).thenReturn(entry.entryAdapter)
+            whenever(row.entryAdapter).thenReturn(factory.create(entry))
         } else {
             whenever(row.entry).thenReturn(entry)
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 345ddae..c23e0e7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -46,7 +46,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry.NotifEntryAdapter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryAdapter;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationContentView;
@@ -135,7 +135,7 @@
         final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class);
         final NotificationContentView privateLayout = mock(NotificationContentView.class);
         final NotificationEntry enrEntry = mock(NotificationEntry.class);
-        final NotifEntryAdapter enrEntryAdapter = mock(NotifEntryAdapter.class);
+        final NotificationEntryAdapter enrEntryAdapter = mock(NotificationEntryAdapter.class);
 
         when(enr.getPrivateLayout()).thenReturn(privateLayout);
         when(enr.getEntry()).thenReturn(enrEntry);
@@ -178,7 +178,7 @@
 
         // THEN
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
         verify(enr).setUserExpanded(true);
         verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
     }
@@ -203,7 +203,7 @@
 
         // THEN
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
         verify(enr).setUserExpanded(true);
         verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
     }
@@ -217,7 +217,7 @@
         final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class);
         final NotificationContentView privateLayout = mock(NotificationContentView.class);
         final NotificationEntry enrEntry = mock(NotificationEntry.class);
-        final NotifEntryAdapter enrEntryAdapter = mock(NotifEntryAdapter.class);
+        final NotificationEntryAdapter enrEntryAdapter = mock(NotificationEntryAdapter.class);
 
         when(enr.getPrivateLayout()).thenReturn(privateLayout);
         when(enr.getEntry()).thenReturn(enrEntry);
@@ -260,7 +260,7 @@
 
         // THEN
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(enrEntry);
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(privateLayout, never()).setOnExpandedVisibleListener(any());
     }
@@ -290,7 +290,7 @@
         verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
     }
 
     @Test
@@ -318,7 +318,7 @@
         verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner);
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
     }
 
     @Test
@@ -346,7 +346,7 @@
         verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
     }
 
     @Test
@@ -374,6 +374,6 @@
         verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner);
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
index bab349a..398f3fb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
@@ -92,6 +92,7 @@
             assertThat(model.intent).isSameInstanceAs(testIntent)
             assertThat(model.notificationKey).isEqualTo(key)
             assertThat(model.promotedContent).isSameInstanceAs(testPromotedContent)
+            assertThat(model.isAppVisible).isFalse()
         }
 
     @Test
@@ -114,15 +115,16 @@
                 promotedContent = testPromotedContent,
             )
 
-            // Verify model is InCallWithVisibleApp and has the correct icon, intent, and promoted
-            // content.
-            assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
-            val model = latest as OngoingCallModel.InCallWithVisibleApp
+            // Verify model is InCall with visible app and has the correct icon, intent, and
+            // promoted content.
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+            val model = latest as OngoingCallModel.InCall
             assertThat(model.startTimeMs).isEqualTo(startTimeMs)
             assertThat(model.notificationIconView).isSameInstanceAs(testIconView)
             assertThat(model.intent).isSameInstanceAs(testIntent)
             assertThat(model.notificationKey).isEqualTo(key)
             assertThat(model.promotedContent).isSameInstanceAs(testPromotedContent)
+            assertThat(model.isAppVisible).isTrue()
         }
 
     @Test
@@ -144,7 +146,8 @@
 
             addOngoingCallState(uid = UID)
 
-            assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((latest as OngoingCallModel.InCall).isAppVisible).isTrue()
         }
 
     @Test
@@ -156,6 +159,7 @@
             addOngoingCallState(uid = UID)
 
             assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((latest as OngoingCallModel.InCall).isAppVisible).isFalse()
         }
 
     @Test
@@ -167,14 +171,17 @@
             kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false
             addOngoingCallState(uid = UID)
             assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((latest as OngoingCallModel.InCall).isAppVisible).isFalse()
 
             // App becomes visible
             kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true)
-            assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((latest as OngoingCallModel.InCall).isAppVisible).isTrue()
 
             // App becomes invisible again
             kosmos.activityManagerRepository.fake.setIsAppVisible(UID, false)
             assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((latest as OngoingCallModel.InCall).isAppVisible).isFalse()
         }
 
     @Test
@@ -243,13 +250,14 @@
             addOngoingCallState(uid = UID)
 
             assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((ongoingCallState as OngoingCallModel.InCall).isAppVisible).isFalse()
             assertThat(requiresStatusBarVisibleInRepository).isTrue()
             assertThat(requiresStatusBarVisibleInWindowController).isTrue()
 
             kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true)
 
-            assertThat(ongoingCallState)
-                .isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
+            assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((ongoingCallState as OngoingCallModel.InCall).isAppVisible).isTrue()
             assertThat(requiresStatusBarVisibleInRepository).isFalse()
             assertThat(requiresStatusBarVisibleInWindowController).isFalse()
         }
@@ -265,6 +273,7 @@
             addOngoingCallState()
 
             assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((ongoingCallState as OngoingCallModel.InCall).isAppVisible).isFalse()
             verify(kosmos.swipeStatusBarAwayGestureHandler, never())
                 .addOnGestureDetectedCallback(any(), any())
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosTest.kt
index c89dc57..3368993 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosTest.kt
@@ -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.
@@ -26,789 +26,701 @@
 import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
 import com.android.settingslib.mobile.TelephonyIcons
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS
+import com.android.systemui.flags.fake
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kairos.ActivatedKairosFixture
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.MutableState
+import com.android.systemui.kairos.kairos
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.log.table.logcatTableLogBuffer
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.THREE_G
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
-import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyString
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
 
+@OptIn(ExperimentalKairosApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class MobileIconInteractorKairosTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
+    private val kosmos =
+        testKosmos().apply {
+            useUnconfinedTestDispatcher()
+            featureFlagsClassic.fake.apply { setDefault(FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS) }
+        }
 
-    private lateinit var underTest: MobileIconInteractorKairos
-    private val mobileMappingsProxy = FakeMobileMappingsProxy()
-    private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
+    private val Kosmos.tableLogBuffer by Fixture {
+        logcatTableLogBuffer(this, "MobileIconInteractorKairosTest")
+    }
 
-    private val connectionRepository =
-        FakeMobileConnectionRepository(
-            SUB_1_ID,
-            logcatTableLogBuffer(kosmos, "MobileIconInteractorTest"),
+    private var Kosmos.overrides: MobileIconCarrierIdOverrides by Fixture {
+        MobileIconCarrierIdOverridesImpl()
+    }
+
+    private val Kosmos.defaultSubscriptionHasDataEnabled by Fixture { MutableState(kairos, true) }
+
+    private val Kosmos.alwaysShowDataRatIcon by Fixture { MutableState(kairos, false) }
+
+    private val Kosmos.alwaysUseCdmaLevel by Fixture { MutableState(kairos, false) }
+
+    private val Kosmos.isSingleCarrier by Fixture { MutableState(kairos, true) }
+
+    private val Kosmos.mobileIsDefault by Fixture { MutableState(kairos, false) }
+
+    private val Kosmos.defaultMobileIconMapping by Fixture {
+        MutableState(kairos, fakeMobileIconsInteractor.TEST_MAPPING)
+    }
+
+    private val Kosmos.defaultMobileIconGroup by Fixture { MutableState(kairos, TelephonyIcons.G) }
+
+    private val Kosmos.isDefaultConnectionFailed by Fixture { MutableState(kairos, false) }
+
+    private val Kosmos.isForceHidden by Fixture { MutableState(kairos, false) }
+
+    private val Kosmos.underTest by ActivatedKairosFixture {
+        MobileIconInteractorKairosImpl(
+            defaultSubscriptionHasDataEnabled,
+            alwaysShowDataRatIcon,
+            alwaysUseCdmaLevel,
+            isSingleCarrier,
+            mobileIsDefault,
+            defaultMobileIconMapping,
+            defaultMobileIconGroup,
+            isDefaultConnectionFailed,
+            isForceHidden,
+            connectionRepository = connectionRepo,
+            context = context,
+            carrierIdOverrides = overrides,
         )
+    }
 
-    private val testDispatcher = UnconfinedTestDispatcher()
-    private val testScope = TestScope(testDispatcher)
+    private val Kosmos.connectionRepo by Fixture {
+        FakeMobileConnectionRepositoryKairos(SUB_1_ID, kairos, tableLogBuffer).apply {
+            dataEnabled.setValue(true)
+            isInService.setValue(true)
+        }
+    }
 
-    @Before
-    fun setUp() {
-        underTest = createInteractor()
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        kosmos.run { runKairosTest { block() } }
 
-        mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
-        connectionRepository.isInService.value = true
+    @Test
+    fun gsm_usesGsmLevel() = runTest {
+        connectionRepo.isGsm.setValue(true)
+        connectionRepo.primaryLevel.setValue(GSM_LEVEL)
+        connectionRepo.cdmaLevel.setValue(CDMA_LEVEL)
+
+        val latest by underTest.signalLevelIcon.collectLastValue()
+
+        assertThat(latest?.level).isEqualTo(GSM_LEVEL)
     }
 
     @Test
-    fun gsm_usesGsmLevel() =
-        testScope.runTest {
-            connectionRepository.isGsm.value = true
-            connectionRepository.primaryLevel.value = GSM_LEVEL
-            connectionRepository.cdmaLevel.value = CDMA_LEVEL
+    fun gsm_alwaysShowCdmaTrue_stillUsesGsmLevel() = runTest {
+        connectionRepo.isGsm.setValue(true)
+        connectionRepo.primaryLevel.setValue(GSM_LEVEL)
+        connectionRepo.cdmaLevel.setValue(CDMA_LEVEL)
+        //            mobileIconsInteractor.alwaysUseCdmaLevel.setValue(true)
+        alwaysUseCdmaLevel.setValue(true)
 
-            var latest: Int? = null
-            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            assertThat(latest).isEqualTo(GSM_LEVEL)
-
-            job.cancel()
-        }
+        assertThat(latest?.level).isEqualTo(GSM_LEVEL)
+    }
 
     @Test
-    fun gsm_alwaysShowCdmaTrue_stillUsesGsmLevel() =
-        testScope.runTest {
-            connectionRepository.isGsm.value = true
-            connectionRepository.primaryLevel.value = GSM_LEVEL
-            connectionRepository.cdmaLevel.value = CDMA_LEVEL
-            mobileIconsInteractor.alwaysUseCdmaLevel.value = true
+    fun notGsm_level_default_unknown() = runTest {
+        connectionRepo.isGsm.setValue(false)
 
-            var latest: Int? = null
-            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            assertThat(latest).isEqualTo(GSM_LEVEL)
-
-            job.cancel()
-        }
+        assertThat(latest?.level).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+    }
 
     @Test
-    fun notGsm_level_default_unknown() =
-        testScope.runTest {
-            connectionRepository.isGsm.value = false
+    fun notGsm_alwaysShowCdmaTrue_usesCdmaLevel() = runTest {
+        connectionRepo.isGsm.setValue(false)
+        connectionRepo.primaryLevel.setValue(GSM_LEVEL)
+        connectionRepo.cdmaLevel.setValue(CDMA_LEVEL)
+        //            mobileIconsInteractor.alwaysUseCdmaLevel.setValue(true)
+        alwaysUseCdmaLevel.setValue(true)
 
-            var latest: Int? = null
-            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
-            job.cancel()
-        }
+        assertThat(latest?.level).isEqualTo(CDMA_LEVEL)
+    }
 
     @Test
-    fun notGsm_alwaysShowCdmaTrue_usesCdmaLevel() =
-        testScope.runTest {
-            connectionRepository.isGsm.value = false
-            connectionRepository.primaryLevel.value = GSM_LEVEL
-            connectionRepository.cdmaLevel.value = CDMA_LEVEL
-            mobileIconsInteractor.alwaysUseCdmaLevel.value = true
+    fun notGsm_alwaysShowCdmaFalse_usesPrimaryLevel() = runTest {
+        connectionRepo.isGsm.setValue(false)
+        connectionRepo.primaryLevel.setValue(GSM_LEVEL)
+        connectionRepo.cdmaLevel.setValue(CDMA_LEVEL)
+        //            mobileIconsInteractor.alwaysUseCdmaLevel.setValue(false)
+        alwaysUseCdmaLevel.setValue(false)
 
-            var latest: Int? = null
-            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            assertThat(latest).isEqualTo(CDMA_LEVEL)
-
-            job.cancel()
-        }
+        assertThat(latest?.level).isEqualTo(GSM_LEVEL)
+    }
 
     @Test
-    fun notGsm_alwaysShowCdmaFalse_usesPrimaryLevel() =
-        testScope.runTest {
-            connectionRepository.isGsm.value = false
-            connectionRepository.primaryLevel.value = GSM_LEVEL
-            connectionRepository.cdmaLevel.value = CDMA_LEVEL
-            mobileIconsInteractor.alwaysUseCdmaLevel.value = false
+    fun numberOfLevels_comesFromRepo_whenApplicable() = runTest {
+        val latest by
+            underTest.signalLevelIcon
+                .map { (it as? SignalIconModel.Cellular)?.numberOfLevels }
+                .collectLastValue()
 
-            var latest: Int? = null
-            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+        connectionRepo.numberOfLevels.setValue(5)
+        assertThat(latest).isEqualTo(5)
 
-            assertThat(latest).isEqualTo(GSM_LEVEL)
-
-            job.cancel()
-        }
+        connectionRepo.numberOfLevels.setValue(4)
+        assertThat(latest).isEqualTo(4)
+    }
 
     @Test
-    fun numberOfLevels_comesFromRepo_whenApplicable() =
-        testScope.runTest {
-            var latest: Int? = null
-            val job =
-                underTest.signalLevelIcon
-                    .onEach { latest = (it as? SignalIconModel.Cellular)?.numberOfLevels }
-                    .launchIn(this)
+    fun inflateSignalStrength_arbitrarilyAddsOneToTheReportedLevel() = runTest {
+        connectionRepo.inflateSignalStrength.setValue(false)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            connectionRepository.numberOfLevels.value = 5
-            assertThat(latest).isEqualTo(5)
+        connectionRepo.primaryLevel.setValue(4)
+        assertThat(latest!!.level).isEqualTo(4)
 
-            connectionRepository.numberOfLevels.value = 4
-            assertThat(latest).isEqualTo(4)
+        connectionRepo.inflateSignalStrength.setValue(true)
+        connectionRepo.primaryLevel.setValue(4)
 
-            job.cancel()
-        }
+        // when INFLATE_SIGNAL_STRENGTH is true, we add 1 to the reported signal level
+        assertThat(latest!!.level).isEqualTo(5)
+    }
 
     @Test
-    fun inflateSignalStrength_arbitrarilyAddsOneToTheReportedLevel() =
-        testScope.runTest {
-            connectionRepository.inflateSignalStrength.value = false
-            val latest by collectLastValue(underTest.signalLevelIcon)
+    fun networkSlice_configOn_hasPrioritizedCaps_showsSlice() = runTest {
+        connectionRepo.allowNetworkSliceIndicator.setValue(true)
+        val latest by underTest.showSliceAttribution.collectLastValue()
 
-            connectionRepository.primaryLevel.value = 4
-            assertThat(latest!!.level).isEqualTo(4)
+        connectionRepo.hasPrioritizedNetworkCapabilities.setValue(true)
 
-            connectionRepository.inflateSignalStrength.value = true
-            connectionRepository.primaryLevel.value = 4
-
-            // when INFLATE_SIGNAL_STRENGTH is true, we add 1 to the reported signal level
-            assertThat(latest!!.level).isEqualTo(5)
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun networkSlice_configOn_hasPrioritizedCaps_showsSlice() =
-        testScope.runTest {
-            connectionRepository.allowNetworkSliceIndicator.value = true
-            val latest by collectLastValue(underTest.showSliceAttribution)
+    fun networkSlice_configOn_noPrioritizedCaps_noSlice() = runTest {
+        connectionRepo.allowNetworkSliceIndicator.setValue(true)
+        val latest by underTest.showSliceAttribution.collectLastValue()
 
-            connectionRepository.hasPrioritizedNetworkCapabilities.value = true
+        connectionRepo.hasPrioritizedNetworkCapabilities.setValue(false)
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun networkSlice_configOn_noPrioritizedCaps_noSlice() =
-        testScope.runTest {
-            connectionRepository.allowNetworkSliceIndicator.value = true
-            val latest by collectLastValue(underTest.showSliceAttribution)
+    fun networkSlice_configOff_hasPrioritizedCaps_noSlice() = runTest {
+        connectionRepo.allowNetworkSliceIndicator.setValue(false)
+        val latest by underTest.showSliceAttribution.collectLastValue()
 
-            connectionRepository.hasPrioritizedNetworkCapabilities.value = false
+        connectionRepo.hasPrioritizedNetworkCapabilities.setValue(true)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun networkSlice_configOff_hasPrioritizedCaps_noSlice() =
-        testScope.runTest {
-            connectionRepository.allowNetworkSliceIndicator.value = false
-            val latest by collectLastValue(underTest.showSliceAttribution)
+    fun networkSlice_configOff_noPrioritizedCaps_noSlice() = runTest {
+        connectionRepo.allowNetworkSliceIndicator.setValue(false)
+        val latest by underTest.showSliceAttribution.collectLastValue()
 
-            connectionRepository.hasPrioritizedNetworkCapabilities.value = true
+        connectionRepo.hasPrioritizedNetworkCapabilities.setValue(false)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun networkSlice_configOff_noPrioritizedCaps_noSlice() =
-        testScope.runTest {
-            connectionRepository.allowNetworkSliceIndicator.value = false
-            val latest by collectLastValue(underTest.showSliceAttribution)
+    fun iconGroup_three_g() = runTest {
+        connectionRepo.resolvedNetworkType.setValue(
+            DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+        )
 
-            connectionRepository.hasPrioritizedNetworkCapabilities.value = false
+        val latest by underTest.networkTypeIconGroup.collectLastValue()
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G))
+    }
 
     @Test
-    fun iconGroup_three_g() =
-        testScope.runTest {
-            connectionRepository.resolvedNetworkType.value =
-                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+    fun iconGroup_updates_on_change() = runTest {
+        connectionRepo.resolvedNetworkType.setValue(
+            DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+        )
 
-            var latest: NetworkTypeIconModel? = null
-            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+        val latest by underTest.networkTypeIconGroup.collectLastValue()
 
-            assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G))
+        connectionRepo.resolvedNetworkType.setValue(
+            DefaultNetworkType(mobileMappingsProxy.toIconKey(FOUR_G))
+        )
 
-            job.cancel()
-        }
+        assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.FOUR_G))
+    }
 
     @Test
-    fun iconGroup_updates_on_change() =
-        testScope.runTest {
-            connectionRepository.resolvedNetworkType.value =
-                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+    fun iconGroup_5g_override_type() = runTest {
+        connectionRepo.resolvedNetworkType.setValue(
+            OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE))
+        )
 
-            var latest: NetworkTypeIconModel? = null
-            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+        val latest by underTest.networkTypeIconGroup.collectLastValue()
 
-            connectionRepository.resolvedNetworkType.value =
-                DefaultNetworkType(mobileMappingsProxy.toIconKey(FOUR_G))
-
-            assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.FOUR_G))
-
-            job.cancel()
-        }
+        assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.NR_5G))
+    }
 
     @Test
-    fun iconGroup_5g_override_type() =
-        testScope.runTest {
-            connectionRepository.resolvedNetworkType.value =
-                OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE))
+    fun iconGroup_default_if_no_lookup() = runTest {
+        connectionRepo.resolvedNetworkType.setValue(
+            DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN))
+        )
 
-            var latest: NetworkTypeIconModel? = null
-            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+        val latest by underTest.networkTypeIconGroup.collectLastValue()
 
-            assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.NR_5G))
-
-            job.cancel()
-        }
+        assertThat(latest)
+            .isEqualTo(NetworkTypeIconModel.DefaultIcon(FakeMobileIconsInteractor.DEFAULT_ICON))
+    }
 
     @Test
-    fun iconGroup_default_if_no_lookup() =
-        testScope.runTest {
-            connectionRepository.resolvedNetworkType.value =
-                DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN))
+    fun iconGroup_carrierMerged_usesOverride() = runTest {
+        connectionRepo.resolvedNetworkType.setValue(CarrierMergedNetworkType)
 
-            var latest: NetworkTypeIconModel? = null
-            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+        val latest by underTest.networkTypeIconGroup.collectLastValue()
 
-            assertThat(latest)
-                .isEqualTo(NetworkTypeIconModel.DefaultIcon(FakeMobileIconsInteractor.DEFAULT_ICON))
-
-            job.cancel()
-        }
+        assertThat(latest)
+            .isEqualTo(NetworkTypeIconModel.DefaultIcon(CarrierMergedNetworkType.iconGroupOverride))
+    }
 
     @Test
-    fun iconGroup_carrierMerged_usesOverride() =
-        testScope.runTest {
-            connectionRepository.resolvedNetworkType.value = CarrierMergedNetworkType
+    fun overrideIcon_usesCarrierIdOverride() = runTest {
+        overrides =
+            mock<MobileIconCarrierIdOverrides> {
+                on { carrierIdEntryExists(anyInt()) } doReturn true
+                on { getOverrideFor(anyInt(), anyString(), any()) } doReturn 1234
+            }
 
-            var latest: NetworkTypeIconModel? = null
-            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+        connectionRepo.resolvedNetworkType.setValue(
+            DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+        )
 
-            assertThat(latest)
-                .isEqualTo(
-                    NetworkTypeIconModel.DefaultIcon(CarrierMergedNetworkType.iconGroupOverride)
-                )
+        val latest by underTest.networkTypeIconGroup.collectLastValue()
 
-            job.cancel()
-        }
+        assertThat(latest)
+            .isEqualTo(NetworkTypeIconModel.OverriddenIcon(TelephonyIcons.THREE_G, 1234))
+    }
 
     @Test
-    fun overrideIcon_usesCarrierIdOverride() =
-        testScope.runTest {
-            val overrides =
-                mock<MobileIconCarrierIdOverrides>().also {
-                    whenever(it.carrierIdEntryExists(anyInt())).thenReturn(true)
-                    whenever(it.getOverrideFor(anyInt(), anyString(), any())).thenReturn(1234)
-                }
+    fun alwaysShowDataRatIcon_matchesParent() = runTest {
+        val latest by underTest.alwaysShowDataRatIcon.collectLastValue()
 
-            underTest = createInteractor(overrides)
+        //            mobileIconsInteractor.alwaysShowDataRatIcon.setValue(true)
+        alwaysShowDataRatIcon.setValue(true)
 
-            connectionRepository.resolvedNetworkType.value =
-                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+        assertThat(latest).isTrue()
 
-            var latest: NetworkTypeIconModel? = null
-            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+        //            mobileIconsInteractor.alwaysShowDataRatIcon.setValue(false)
+        alwaysShowDataRatIcon.setValue(false)
 
-            assertThat(latest)
-                .isEqualTo(NetworkTypeIconModel.OverriddenIcon(TelephonyIcons.THREE_G, 1234))
-
-            job.cancel()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun alwaysShowDataRatIcon_matchesParent() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.alwaysShowDataRatIcon.onEach { latest = it }.launchIn(this)
+    fun dataState_connected() = runTest {
+        val latest by underTest.isDataConnected.collectLastValue()
 
-            mobileIconsInteractor.alwaysShowDataRatIcon.value = true
-            assertThat(latest).isTrue()
+        connectionRepo.dataConnectionState.setValue(DataConnectionState.Connected)
 
-            mobileIconsInteractor.alwaysShowDataRatIcon.value = false
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun dataState_connected() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
+    fun dataState_notConnected() = runTest {
+        val latest by underTest.isDataConnected.collectLastValue()
 
-            connectionRepository.dataConnectionState.value = DataConnectionState.Connected
+        connectionRepo.dataConnectionState.setValue(DataConnectionState.Disconnected)
 
-            assertThat(latest).isTrue()
-
-            job.cancel()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun dataState_notConnected() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
+    fun isInService_usesRepositoryValue() = runTest {
+        val latest by underTest.isInService.collectLastValue()
 
-            connectionRepository.dataConnectionState.value = DataConnectionState.Disconnected
+        connectionRepo.isInService.setValue(true)
 
-            assertThat(latest).isFalse()
+        assertThat(latest).isTrue()
 
-            job.cancel()
-        }
+        connectionRepo.isInService.setValue(false)
+
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun isInService_usesRepositoryValue() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isInService.onEach { latest = it }.launchIn(this)
+    fun roaming_isGsm_usesConnectionModel() = runTest {
+        val latest by underTest.isRoaming.collectLastValue()
 
-            connectionRepository.isInService.value = true
+        connectionRepo.cdmaRoaming.setValue(true)
+        connectionRepo.isGsm.setValue(true)
+        connectionRepo.isRoaming.setValue(false)
 
-            assertThat(latest).isTrue()
+        assertThat(latest).isFalse()
 
-            connectionRepository.isInService.value = false
+        connectionRepo.isRoaming.setValue(true)
 
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun roaming_isGsm_usesConnectionModel() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+    fun roaming_isCdma_usesCdmaRoamingBit() = runTest {
+        val latest by underTest.isRoaming.collectLastValue()
 
-            connectionRepository.cdmaRoaming.value = true
-            connectionRepository.isGsm.value = true
-            connectionRepository.isRoaming.value = false
+        connectionRepo.cdmaRoaming.setValue(false)
+        connectionRepo.isGsm.setValue(false)
+        connectionRepo.isRoaming.setValue(true)
 
-            assertThat(latest).isFalse()
+        assertThat(latest).isFalse()
 
-            connectionRepository.isRoaming.value = true
+        connectionRepo.cdmaRoaming.setValue(true)
+        connectionRepo.isGsm.setValue(false)
+        connectionRepo.isRoaming.setValue(false)
 
-            assertThat(latest).isTrue()
-
-            job.cancel()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun roaming_isCdma_usesCdmaRoamingBit() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+    fun roaming_falseWhileCarrierNetworkChangeActive() = runTest {
+        val latest by underTest.isRoaming.collectLastValue()
 
-            connectionRepository.cdmaRoaming.value = false
-            connectionRepository.isGsm.value = false
-            connectionRepository.isRoaming.value = true
+        connectionRepo.cdmaRoaming.setValue(true)
+        connectionRepo.isGsm.setValue(false)
+        connectionRepo.isRoaming.setValue(true)
+        connectionRepo.carrierNetworkChangeActive.setValue(true)
 
-            assertThat(latest).isFalse()
+        assertThat(latest).isFalse()
 
-            connectionRepository.cdmaRoaming.value = true
-            connectionRepository.isGsm.value = false
-            connectionRepository.isRoaming.value = false
+        connectionRepo.cdmaRoaming.setValue(true)
+        connectionRepo.isGsm.setValue(true)
 
-            assertThat(latest).isTrue()
-
-            job.cancel()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun roaming_falseWhileCarrierNetworkChangeActive() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+    fun networkName_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() = runTest {
+        val latest by underTest.networkName.collectLastValue()
 
-            connectionRepository.cdmaRoaming.value = true
-            connectionRepository.isGsm.value = false
-            connectionRepository.isRoaming.value = true
-            connectionRepository.carrierNetworkChangeActive.value = true
+        val testOperatorName = "operatorAlphaShort"
 
-            assertThat(latest).isFalse()
+        // Default network name, operator name is non-null, uses the operator name
+        connectionRepo.networkName.setValue(DEFAULT_NAME_MODEL)
+        connectionRepo.operatorAlphaShort.setValue(testOperatorName)
 
-            connectionRepository.cdmaRoaming.value = true
-            connectionRepository.isGsm.value = true
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
 
-            assertThat(latest).isFalse()
+        // Default network name, operator name is null, uses the default
+        connectionRepo.operatorAlphaShort.setValue(null)
 
-            job.cancel()
-        }
+        assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+        // Derived network name, operator name non-null, uses the derived name
+        connectionRepo.networkName.setValue(DERIVED_NAME_MODEL)
+        connectionRepo.operatorAlphaShort.setValue(testOperatorName)
+
+        assertThat(latest).isEqualTo(DERIVED_NAME_MODEL)
+    }
 
     @Test
-    fun networkName_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
-        testScope.runTest {
-            var latest: NetworkNameModel? = null
-            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+    fun networkNameForSubId_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() = runTest {
+        val latest by underTest.carrierName.collectLastValue()
 
-            val testOperatorName = "operatorAlphaShort"
+        val testOperatorName = "operatorAlphaShort"
 
-            // Default network name, operator name is non-null, uses the operator name
-            connectionRepository.networkName.value = DEFAULT_NAME_MODEL
-            connectionRepository.operatorAlphaShort.value = testOperatorName
+        // Default network name, operator name is non-null, uses the operator name
+        connectionRepo.carrierName.setValue(DEFAULT_NAME_MODEL)
+        connectionRepo.operatorAlphaShort.setValue(testOperatorName)
 
-            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
+        assertThat(latest).isEqualTo(testOperatorName)
 
-            // Default network name, operator name is null, uses the default
-            connectionRepository.operatorAlphaShort.value = null
+        // Default network name, operator name is null, uses the default
+        connectionRepo.operatorAlphaShort.setValue(null)
 
-            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+        assertThat(latest).isEqualTo(DEFAULT_NAME)
 
-            // Derived network name, operator name non-null, uses the derived name
-            connectionRepository.networkName.value = DERIVED_NAME_MODEL
-            connectionRepository.operatorAlphaShort.value = testOperatorName
+        // Derived network name, operator name non-null, uses the derived name
+        connectionRepo.carrierName.setValue(NetworkNameModel.SubscriptionDerived(DERIVED_NAME))
+        connectionRepo.operatorAlphaShort.setValue(testOperatorName)
 
-            assertThat(latest).isEqualTo(DERIVED_NAME_MODEL)
-
-            job.cancel()
-        }
+        assertThat(latest).isEqualTo(DERIVED_NAME)
+    }
 
     @Test
-    fun networkNameForSubId_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
-        testScope.runTest {
-            var latest: String? = null
-            val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+    fun isSingleCarrier_matchesParent() = runTest {
+        val latest by underTest.isSingleCarrier.collectLastValue()
 
-            val testOperatorName = "operatorAlphaShort"
+        //            mobileIconsInteractor.isSingleCarrier.setValue(true)
+        isSingleCarrier.setValue(true)
+        assertThat(latest).isTrue()
 
-            // Default network name, operator name is non-null, uses the operator name
-            connectionRepository.carrierName.value = DEFAULT_NAME_MODEL
-            connectionRepository.operatorAlphaShort.value = testOperatorName
-
-            assertThat(latest).isEqualTo(testOperatorName)
-
-            // Default network name, operator name is null, uses the default
-            connectionRepository.operatorAlphaShort.value = null
-
-            assertThat(latest).isEqualTo(DEFAULT_NAME)
-
-            // Derived network name, operator name non-null, uses the derived name
-            connectionRepository.carrierName.value =
-                NetworkNameModel.SubscriptionDerived(DERIVED_NAME)
-            connectionRepository.operatorAlphaShort.value = testOperatorName
-
-            assertThat(latest).isEqualTo(DERIVED_NAME)
-
-            job.cancel()
-        }
+        //            mobileIconsInteractor.isSingleCarrier.setValue(false)
+        isSingleCarrier.setValue(false)
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun isSingleCarrier_matchesParent() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+    fun isForceHidden_matchesParent() = runTest {
+        val latest by underTest.isForceHidden.collectLastValue()
 
-            mobileIconsInteractor.isSingleCarrier.value = true
-            assertThat(latest).isTrue()
+        //            mobileIconsInteractor.isForceHidden.setValue(true)
+        isForceHidden.setValue(true)
+        assertThat(latest).isTrue()
 
-            mobileIconsInteractor.isSingleCarrier.value = false
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
+        //            mobileIconsInteractor.isForceHidden.setValue(false)
+        isForceHidden.setValue(false)
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun isForceHidden_matchesParent() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this)
+    fun isAllowedDuringAirplaneMode_matchesRepo() = runTest {
+        val latest by underTest.isAllowedDuringAirplaneMode.collectLastValue()
 
-            mobileIconsInteractor.isForceHidden.value = true
-            assertThat(latest).isTrue()
+        connectionRepo.isAllowedDuringAirplaneMode.setValue(true)
+        assertThat(latest).isTrue()
 
-            mobileIconsInteractor.isForceHidden.value = false
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
+        connectionRepo.isAllowedDuringAirplaneMode.setValue(false)
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun isAllowedDuringAirplaneMode_matchesRepo() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+    fun cellBasedIconId_correctLevel_notCutout() = runTest {
+        connectionRepo.isNonTerrestrial.setValue(false)
+        connectionRepo.isInService.setValue(true)
+        connectionRepo.primaryLevel.setValue(1)
+        connectionRepo.dataEnabled.setValue(true)
+        connectionRepo.isNonTerrestrial.setValue(false)
 
-            connectionRepository.isAllowedDuringAirplaneMode.value = true
-            assertThat(latest).isTrue()
+        val latest by
+            underTest.signalLevelIcon.map { it as? SignalIconModel.Cellular }.collectLastValue()
 
-            connectionRepository.isAllowedDuringAirplaneMode.value = false
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest?.level).isEqualTo(1)
+
+        // TODO: need to provision MobileIconsInteractorKairos#isDefaultConnectionFailed +
+        // defaultSubscriptionHasDataEnabled?
+        assertThat(latest?.showExclamationMark).isEqualTo(false)
+    }
 
     @Test
-    fun cellBasedIconId_correctLevel_notCutout() =
-        testScope.runTest {
-            connectionRepository.isNonTerrestrial.value = false
-            connectionRepository.isInService.value = true
-            connectionRepository.primaryLevel.value = 1
-            connectionRepository.setDataEnabled(false)
-            connectionRepository.isNonTerrestrial.value = false
+    fun icon_usesLevelFromInteractor() = runTest {
+        connectionRepo.isNonTerrestrial.setValue(false)
+        connectionRepo.isInService.setValue(true)
 
-            var latest: SignalIconModel.Cellular? = null
-            val job =
-                underTest.signalLevelIcon
-                    .onEach { latest = it as? SignalIconModel.Cellular }
-                    .launchIn(this)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            assertThat(latest?.level).isEqualTo(1)
-            assertThat(latest?.showExclamationMark).isFalse()
+        connectionRepo.primaryLevel.setValue(3)
+        assertThat(latest!!.level).isEqualTo(3)
 
-            job.cancel()
-        }
+        connectionRepo.primaryLevel.setValue(1)
+        assertThat(latest!!.level).isEqualTo(1)
+    }
 
     @Test
-    fun icon_usesLevelFromInteractor() =
-        testScope.runTest {
-            connectionRepository.isNonTerrestrial.value = false
-            connectionRepository.isInService.value = true
+    fun cellBasedIcon_usesNumberOfLevelsFromInteractor() = runTest {
+        connectionRepo.isNonTerrestrial.setValue(false)
 
-            var latest: SignalIconModel? = null
-            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+        val latest by
+            underTest.signalLevelIcon.map { it as? SignalIconModel.Cellular }.collectLastValue()
 
-            connectionRepository.primaryLevel.value = 3
-            assertThat(latest!!.level).isEqualTo(3)
+        connectionRepo.numberOfLevels.setValue(5)
+        assertThat(latest!!.numberOfLevels).isEqualTo(5)
 
-            connectionRepository.primaryLevel.value = 1
-            assertThat(latest!!.level).isEqualTo(1)
-
-            job.cancel()
-        }
+        connectionRepo.numberOfLevels.setValue(2)
+        assertThat(latest!!.numberOfLevels).isEqualTo(2)
+    }
 
     @Test
-    fun cellBasedIcon_usesNumberOfLevelsFromInteractor() =
-        testScope.runTest {
-            connectionRepository.isNonTerrestrial.value = false
+    fun cellBasedIcon_defaultDataDisabled_showExclamationTrue() = runTest {
+        connectionRepo.isNonTerrestrial.setValue(false)
+        connectionRepo.dataEnabled.setValue(false)
+        defaultSubscriptionHasDataEnabled.setValue(false)
 
-            var latest: SignalIconModel.Cellular? = null
-            val job =
-                underTest.signalLevelIcon
-                    .onEach { latest = it as? SignalIconModel.Cellular }
-                    .launchIn(this)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            connectionRepository.numberOfLevels.value = 5
-            assertThat(latest!!.numberOfLevels).isEqualTo(5)
-
-            connectionRepository.numberOfLevels.value = 2
-            assertThat(latest!!.numberOfLevels).isEqualTo(2)
-
-            job.cancel()
-        }
+        assertThat((latest!! as SignalIconModel.Cellular).showExclamationMark).isTrue()
+    }
 
     @Test
-    fun cellBasedIcon_defaultDataDisabled_showExclamationTrue() =
-        testScope.runTest {
-            connectionRepository.isNonTerrestrial.value = false
-            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = false
+    fun cellBasedIcon_defaultConnectionFailed_showExclamationTrue() = runTest {
+        connectionRepo.isNonTerrestrial.setValue(false)
+        //            mobileIconsInteractor.isDefaultConnectionFailed.setValue(true)
+        isDefaultConnectionFailed.setValue(true)
 
-            var latest: SignalIconModel.Cellular? = null
-            val job =
-                underTest.signalLevelIcon
-                    .onEach { latest = it as? SignalIconModel.Cellular }
-                    .launchIn(this)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            assertThat(latest!!.showExclamationMark).isTrue()
-
-            job.cancel()
-        }
+        assertThat((latest!! as SignalIconModel.Cellular).showExclamationMark).isTrue()
+    }
 
     @Test
-    fun cellBasedIcon_defaultConnectionFailed_showExclamationTrue() =
-        testScope.runTest {
-            connectionRepository.isNonTerrestrial.value = false
-            mobileIconsInteractor.isDefaultConnectionFailed.value = true
+    fun cellBasedIcon_enabledAndNotFailed_showExclamationFalse() = runTest {
+        connectionRepo.isNonTerrestrial.setValue(false)
+        connectionRepo.isInService.setValue(true)
+        connectionRepo.dataEnabled.setValue(true)
+        //            mobileIconsInteractor.isDefaultConnectionFailed.setValue(false)
+        isDefaultConnectionFailed.setValue(false)
 
-            var latest: SignalIconModel.Cellular? = null
-            val job =
-                underTest.signalLevelIcon
-                    .onEach { latest = it as? SignalIconModel.Cellular }
-                    .launchIn(this)
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            assertThat(latest!!.showExclamationMark).isTrue()
-
-            job.cancel()
-        }
+        assertThat((latest!! as SignalIconModel.Cellular).showExclamationMark).isFalse()
+    }
 
     @Test
-    fun cellBasedIcon_enabledAndNotFailed_showExclamationFalse() =
-        testScope.runTest {
-            connectionRepository.isNonTerrestrial.value = false
-            connectionRepository.isInService.value = true
-            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
-            mobileIconsInteractor.isDefaultConnectionFailed.value = false
+    fun cellBasedIcon_usesEmptyState_whenNotInService() = runTest {
+        val latest by
+            underTest.signalLevelIcon.map { it as SignalIconModel.Cellular }.collectLastValue()
 
-            var latest: SignalIconModel.Cellular? = null
-            val job =
-                underTest.signalLevelIcon
-                    .onEach { latest = it as? SignalIconModel.Cellular }
-                    .launchIn(this)
+        connectionRepo.isNonTerrestrial.setValue(false)
+        connectionRepo.isInService.setValue(false)
 
-            assertThat(latest!!.showExclamationMark).isFalse()
+        assertThat(latest?.level).isEqualTo(0)
+        assertThat(latest?.showExclamationMark).isTrue()
 
-            job.cancel()
-        }
+        // Changing the level doesn't overwrite the disabled state
+        connectionRepo.primaryLevel.setValue(2)
+        assertThat(latest?.level).isEqualTo(0)
+        assertThat(latest?.showExclamationMark).isTrue()
+
+        // Once back in service, the regular icon appears
+        connectionRepo.isInService.setValue(true)
+        assertThat(latest?.level).isEqualTo(2)
+        assertThat(latest?.showExclamationMark).isFalse()
+    }
 
     @Test
-    fun cellBasedIcon_usesEmptyState_whenNotInService() =
-        testScope.runTest {
-            var latest: SignalIconModel.Cellular? = null
-            val job =
-                underTest.signalLevelIcon
-                    .onEach { latest = it as? SignalIconModel.Cellular }
-                    .launchIn(this)
+    fun cellBasedIcon_usesCarrierNetworkState_whenInCarrierNetworkChangeMode() = runTest {
+        val latest by
+            underTest.signalLevelIcon.map { it as SignalIconModel.Cellular }.collectLastValue()
 
-            connectionRepository.isNonTerrestrial.value = false
-            connectionRepository.isInService.value = false
+        connectionRepo.isNonTerrestrial.setValue(false)
+        connectionRepo.isInService.setValue(true)
+        connectionRepo.carrierNetworkChangeActive.setValue(true)
+        connectionRepo.primaryLevel.setValue(1)
+        connectionRepo.cdmaLevel.setValue(1)
 
-            assertThat(latest?.level).isEqualTo(0)
-            assertThat(latest?.showExclamationMark).isTrue()
+        assertThat(latest!!.level).isEqualTo(1)
+        assertThat(latest!!.carrierNetworkChange).isTrue()
 
-            // Changing the level doesn't overwrite the disabled state
-            connectionRepository.primaryLevel.value = 2
-            assertThat(latest?.level).isEqualTo(0)
-            assertThat(latest?.showExclamationMark).isTrue()
+        // SignalIconModel respects the current level
+        connectionRepo.primaryLevel.setValue(2)
 
-            // Once back in service, the regular icon appears
-            connectionRepository.isInService.value = true
-            assertThat(latest?.level).isEqualTo(2)
-            assertThat(latest?.showExclamationMark).isFalse()
-
-            job.cancel()
-        }
+        assertThat(latest!!.level).isEqualTo(2)
+        assertThat(latest!!.carrierNetworkChange).isTrue()
+    }
 
     @Test
-    fun cellBasedIcon_usesCarrierNetworkState_whenInCarrierNetworkChangeMode() =
-        testScope.runTest {
-            var latest: SignalIconModel.Cellular? = null
-            val job =
-                underTest.signalLevelIcon
-                    .onEach { latest = it as? SignalIconModel.Cellular? }
-                    .launchIn(this)
+    fun satBasedIcon_isUsedWhenNonTerrestrial() = runTest {
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            connectionRepository.isNonTerrestrial.value = false
-            connectionRepository.isInService.value = true
-            connectionRepository.carrierNetworkChangeActive.value = true
-            connectionRepository.primaryLevel.value = 1
-            connectionRepository.cdmaLevel.value = 1
+        // Start off using cellular
+        assertThat(latest).isInstanceOf(SignalIconModel.Cellular::class.java)
 
-            assertThat(latest!!.level).isEqualTo(1)
-            assertThat(latest!!.carrierNetworkChange).isTrue()
+        connectionRepo.isNonTerrestrial.setValue(true)
 
-            // SignalIconModel respects the current level
-            connectionRepository.primaryLevel.value = 2
-
-            assertThat(latest!!.level).isEqualTo(2)
-            assertThat(latest!!.carrierNetworkChange).isTrue()
-
-            job.cancel()
-        }
-
-    @Test
-    fun satBasedIcon_isUsedWhenNonTerrestrial() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.signalLevelIcon)
-
-            // Start off using cellular
-            assertThat(latest).isInstanceOf(SignalIconModel.Cellular::class.java)
-
-            connectionRepository.isNonTerrestrial.value = true
-
-            assertThat(latest).isInstanceOf(SignalIconModel.Satellite::class.java)
-        }
+        assertThat(latest).isInstanceOf(SignalIconModel.Satellite::class.java)
+    }
 
     @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
     @Test
     // See b/346904529 for more context
-    fun satBasedIcon_doesNotInflateSignalStrength_flagOff() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.signalLevelIcon)
+    fun satBasedIcon_doesNotInflateSignalStrength_flagOff() = runTest {
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            // GIVEN a satellite connection
-            connectionRepository.isNonTerrestrial.value = true
-            // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
-            connectionRepository.inflateSignalStrength.value = true
+        // GIVEN a satellite connection
+        connectionRepo.isNonTerrestrial.setValue(true)
+        // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
+        connectionRepo.inflateSignalStrength.setValue(true)
 
-            connectionRepository.primaryLevel.value = 4
-            assertThat(latest!!.level).isEqualTo(4)
+        connectionRepo.primaryLevel.setValue(4)
+        assertThat(latest!!.level).isEqualTo(4)
 
-            connectionRepository.inflateSignalStrength.value = true
-            connectionRepository.primaryLevel.value = 4
+        connectionRepo.inflateSignalStrength.setValue(true)
+        connectionRepo.primaryLevel.setValue(4)
 
-            // Icon level is unaffected
-            assertThat(latest!!.level).isEqualTo(4)
-        }
+        // Icon level is unaffected
+        assertThat(latest!!.level).isEqualTo(4)
+    }
 
     @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
     @Test
     // See b/346904529 for more context
-    fun satBasedIcon_doesNotInflateSignalStrength_flagOn() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.signalLevelIcon)
+    fun satBasedIcon_doesNotInflateSignalStrength_flagOn() = runTest {
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            // GIVEN a satellite connection
-            connectionRepository.isNonTerrestrial.value = true
-            // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
-            connectionRepository.inflateSignalStrength.value = true
+        // GIVEN a satellite connection
+        connectionRepo.isNonTerrestrial.setValue(true)
+        // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
+        connectionRepo.inflateSignalStrength.setValue(true)
 
-            connectionRepository.satelliteLevel.value = 4
-            assertThat(latest!!.level).isEqualTo(4)
+        connectionRepo.satelliteLevel.setValue(4)
+        assertThat(latest!!.level).isEqualTo(4)
 
-            connectionRepository.inflateSignalStrength.value = true
-            connectionRepository.primaryLevel.value = 4
+        connectionRepo.inflateSignalStrength.setValue(true)
+        connectionRepo.primaryLevel.setValue(4)
 
-            // Icon level is unaffected
-            assertThat(latest!!.level).isEqualTo(4)
-        }
+        // Icon level is unaffected
+        assertThat(latest!!.level).isEqualTo(4)
+    }
 
     @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
     @Test
-    fun satBasedIcon_usesPrimaryLevel_flagOff() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.signalLevelIcon)
+    fun satBasedIcon_usesPrimaryLevel_flagOff() = runTest {
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            // GIVEN a satellite connection
-            connectionRepository.isNonTerrestrial.value = true
+        // GIVEN a satellite connection
+        connectionRepo.isNonTerrestrial.setValue(true)
 
-            // GIVEN primary level is set
-            connectionRepository.primaryLevel.value = 4
-            connectionRepository.satelliteLevel.value = 0
+        // GIVEN primary level is set
+        connectionRepo.primaryLevel.setValue(4)
+        connectionRepo.satelliteLevel.setValue(0)
 
-            // THEN icon uses the primary level because the flag is off
-            assertThat(latest!!.level).isEqualTo(4)
-        }
+        // THEN icon uses the primary level because the flag is off
+        assertThat(latest!!.level).isEqualTo(4)
+    }
 
     @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
     @Test
-    fun satBasedIcon_usesSatelliteLevel_flagOn() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.signalLevelIcon)
+    fun satBasedIcon_usesSatelliteLevel_flagOn() = runTest {
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            // GIVEN a satellite connection
-            connectionRepository.isNonTerrestrial.value = true
+        // GIVEN a satellite connection
+        connectionRepo.isNonTerrestrial.setValue(true)
 
-            // GIVEN satellite level is set
-            connectionRepository.satelliteLevel.value = 4
-            connectionRepository.primaryLevel.value = 0
+        // GIVEN satellite level is set
+        connectionRepo.satelliteLevel.setValue(4)
+        connectionRepo.primaryLevel.setValue(0)
 
-            // THEN icon uses the satellite level because the flag is on
-            assertThat(latest!!.level).isEqualTo(4)
-        }
+        // THEN icon uses the satellite level because the flag is on
+        assertThat(latest!!.level).isEqualTo(4)
+    }
 
     /**
      * Context (b/377518113), this test will not be needed after FLAG_CARRIER_ROAMING_NB_IOT_NTN is
@@ -816,43 +728,23 @@
      */
     @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
     @Test
-    fun satBasedIcon_reportsLevelZeroWhenOutOfService() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.signalLevelIcon)
+    fun satBasedIcon_reportsLevelZeroWhenOutOfService() = runTest {
+        val latest by underTest.signalLevelIcon.collectLastValue()
 
-            // GIVEN a satellite connection
-            connectionRepository.isNonTerrestrial.value = true
-            // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
-            connectionRepository.inflateSignalStrength.value = true
+        // GIVEN a satellite connection
+        connectionRepo.isNonTerrestrial.setValue(true)
+        // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
+        connectionRepo.inflateSignalStrength.setValue(true)
 
-            connectionRepository.primaryLevel.value = 4
-            assertThat(latest!!.level).isEqualTo(4)
+        connectionRepo.primaryLevel.setValue(4)
+        assertThat(latest!!.level).isEqualTo(4)
 
-            connectionRepository.isInService.value = false
-            connectionRepository.primaryLevel.value = 4
+        connectionRepo.isInService.setValue(false)
+        connectionRepo.primaryLevel.setValue(4)
 
-            // THEN level reports 0, by policy
-            assertThat(latest!!.level).isEqualTo(0)
-        }
-
-    private fun createInteractor(
-        overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl()
-    ) =
-        MobileIconInteractorKairosImpl(
-            testScope.backgroundScope,
-            mobileIconsInteractor.activeDataConnectionHasDataEnabled,
-            mobileIconsInteractor.alwaysShowDataRatIcon,
-            mobileIconsInteractor.alwaysUseCdmaLevel,
-            mobileIconsInteractor.isSingleCarrier,
-            mobileIconsInteractor.mobileIsDefault,
-            mobileIconsInteractor.defaultMobileIconMapping,
-            mobileIconsInteractor.defaultMobileIconGroup,
-            mobileIconsInteractor.isDefaultConnectionFailed,
-            mobileIconsInteractor.isForceHidden,
-            connectionRepository,
-            context,
-            overrides,
-        )
+        // THEN level reports 0, by policy
+        assertThat(latest!!.level).isEqualTo(0)
+    }
 
     companion object {
         private const val GSM_LEVEL = 1
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosTest.kt
index a9360d1..4f6439d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosTest.kt
@@ -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.
@@ -28,186 +28,164 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.fake
 import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.runKairosTest
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.collectLastValue
 import com.android.systemui.kosmos.runCurrent
 import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.core.NewStatusBarIcons
 import com.android.systemui.statusbar.core.StatusBarRootModernization
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepositoryLogbufferName
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepositoryKairos
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
 import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
 import com.android.systemui.statusbar.pipeline.shared.data.repository.fake
-import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
 import com.android.systemui.testKosmos
-import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.carrierConfigTracker
 import com.google.common.truth.Truth.assertThat
 import java.util.UUID
 import kotlinx.coroutines.test.advanceTimeBy
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
 
+@OptIn(ExperimentalKairosApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class MobileIconsInteractorKairosTest : SysuiTestCase() {
-    private val kosmos by lazy {
+
+    private val kosmos =
         testKosmos().apply {
-            mobileConnectionsRepositoryLogbufferName = "MobileIconsInteractorTest"
-            mobileConnectionsRepository.fake.run {
-                setMobileConnectionRepositoryMap(
-                    mapOf(
-                        SUB_1_ID to FakeMobileConnectionRepository(SUB_1_ID, mock()),
-                        SUB_2_ID to FakeMobileConnectionRepository(SUB_2_ID, mock()),
-                        SUB_3_ID to FakeMobileConnectionRepository(SUB_3_ID, mock()),
-                        SUB_4_ID to FakeMobileConnectionRepository(SUB_4_ID, mock()),
-                    )
-                )
-                setActiveMobileDataSubscriptionId(SUB_1_ID)
-            }
+            useUnconfinedTestDispatcher()
+            mobileConnectionsRepositoryKairos =
+                fakeMobileConnectionsRepositoryKairos.apply {
+                    setActiveMobileDataSubscriptionId(SUB_1_ID)
+                    subscriptions.setValue(listOf(SUB_1, SUB_2, SUB_3_OPP, SUB_4_OPP))
+                }
             featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
         }
-    }
 
-    // shortcut rename
-    private val Kosmos.connectionsRepository by Fixture { mobileConnectionsRepository.fake }
+    private val Kosmos.underTest
+        get() = mobileIconsInteractorKairos
 
-    private val Kosmos.carrierConfigTracker by Fixture { mock<CarrierConfigTracker>() }
-
-    private val Kosmos.underTest by Fixture {
-        MobileIconsInteractorKairosImpl(
-            mobileConnectionsRepository,
-            carrierConfigTracker,
-            tableLogger = mock(),
-            connectivityRepository,
-            FakeUserSetupRepository(),
-            testScope.backgroundScope,
-            context,
-            featureFlagsClassic,
-        )
-    }
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        kosmos.run { runKairosTest { block() } }
 
     @Test
-    fun filteredSubscriptions_default() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+    fun filteredSubscriptions_default() = runTest {
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(emptyList())
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf<SubscriptionModel>())
-        }
+        assertThat(latest).isEqualTo(emptyList<SubscriptionModel>())
+    }
 
     // Based on the logic from the old pipeline, we'll never filter subs when there are more than 2
     @Test
-    fun filteredSubscriptions_moreThanTwo_doesNotFilter() =
-        kosmos.runTest {
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
+    fun filteredSubscriptions_moreThanTwo_doesNotFilter() = runTest {
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(
+            listOf(SUB_1, SUB_3_OPP, SUB_4_OPP)
+        )
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_4_ID)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
-        }
+        assertThat(latest).isEqualTo(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
+    }
 
     @Test
-    fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
-        kosmos.runTest {
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+    fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() = runTest {
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1, SUB_2))
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2))
-        }
+        assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2))
+    }
 
     @Test
-    fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() =
-        kosmos.runTest {
-            connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+    fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() = runTest {
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_3_OPP, SUB_4_OPP))
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_3_ID)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf(SUB_3_OPP, SUB_4_OPP))
-        }
+        assertThat(latest).isEqualTo(listOf(SUB_3_OPP, SUB_4_OPP))
+    }
 
     @Test
-    fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() =
-        kosmos.runTest {
-            val (sub1, sub2) =
-                createSubscriptionPair(
-                    subscriptionIds = Pair(SUB_1_ID, SUB_2_ID),
-                    opportunistic = Pair(true, true),
-                    grouped = false,
-                )
-            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
+    fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() = runTest {
+        val (sub1, sub2) =
+            createSubscriptionPair(
+                subscriptionIds = Pair(SUB_1_ID, SUB_2_ID),
+                opportunistic = Pair(true, true),
+                grouped = false,
+            )
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1, sub2))
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_1_ID)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf(sub1, sub2))
-        }
+        assertThat(latest).isEqualTo(listOf(sub1, sub2))
+    }
 
     @Test
-    fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() =
-        kosmos.runTest {
-            val (sub3, sub4) =
-                createSubscriptionPair(
-                    subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
-                    opportunistic = Pair(true, true),
-                    grouped = true,
-                )
-            connectionsRepository.setSubscriptions(listOf(sub3, sub4))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
-            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
-                .thenReturn(false)
+    fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() = runTest {
+        val (sub3, sub4) =
+            createSubscriptionPair(
+                subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+                opportunistic = Pair(true, true),
+                grouped = true,
+            )
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub3, sub4))
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_3_ID)
+        whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+            .thenReturn(false)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            // Filtered subscriptions should show the active one when the config is false
-            assertThat(latest).isEqualTo(listOf(sub3))
-        }
+        // Filtered subscriptions should show the active one when the config is false
+        assertThat(latest).isEqualTo(listOf(sub3))
+    }
 
     @Test
-    fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() =
-        kosmos.runTest {
-            val (sub3, sub4) =
-                createSubscriptionPair(
-                    subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
-                    opportunistic = Pair(true, true),
-                    grouped = true,
-                )
-            connectionsRepository.setSubscriptions(listOf(sub3, sub4))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
-            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
-                .thenReturn(false)
+    fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() = runTest {
+        val (sub3, sub4) =
+            createSubscriptionPair(
+                subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+                opportunistic = Pair(true, true),
+                grouped = true,
+            )
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub3, sub4))
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_4_ID)
+        whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+            .thenReturn(false)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            // Filtered subscriptions should show the active one when the config is false
-            assertThat(latest).isEqualTo(listOf(sub4))
-        }
+        // Filtered subscriptions should show the active one when the config is false
+        assertThat(latest).isEqualTo(listOf(sub4))
+    }
 
     @Test
     fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_active_1() =
-        kosmos.runTest {
+        runTest {
             val (sub1, sub3) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
                     opportunistic = Pair(false, true),
                     grouped = true,
                 )
-            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
+            mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1, sub3))
+            mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_1_ID)
             whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
                 .thenReturn(true)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+            val latest by underTest.filteredSubscriptions.collectLastValue()
 
             // Filtered subscriptions should show the primary (non-opportunistic) if the config is
             // true
@@ -216,19 +194,19 @@
 
     @Test
     fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_nonActive_1() =
-        kosmos.runTest {
+        runTest {
             val (sub1, sub3) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
                     opportunistic = Pair(false, true),
                     grouped = true,
                 )
-            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+            mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1, sub3))
+            mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_3_ID)
             whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
                 .thenReturn(true)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+            val latest by underTest.filteredSubscriptions.collectLastValue()
 
             // Filtered subscriptions should show the primary (non-opportunistic) if the config is
             // true
@@ -236,135 +214,130 @@
         }
 
     @Test
-    fun filteredSubscriptions_vcnSubId_agreesWithActiveSubId_usesActiveAkaVcnSub() =
-        kosmos.runTest {
-            val (sub1, sub3) =
-                createSubscriptionPair(
-                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
-                    opportunistic = Pair(true, true),
-                    grouped = true,
-                )
-            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
-            kosmos.connectivityRepository.fake.vcnSubId.value = SUB_3_ID
-            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
-                .thenReturn(false)
+    fun filteredSubscriptions_vcnSubId_agreesWithActiveSubId_usesActiveAkaVcnSub() = runTest {
+        val (sub1, sub3) =
+            createSubscriptionPair(
+                subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                opportunistic = Pair(true, true),
+                grouped = true,
+            )
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1, sub3))
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_3_ID)
+        kosmos.connectivityRepository.fake.vcnSubId.value = SUB_3_ID
+        whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+            .thenReturn(false)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf(sub3))
-        }
+        assertThat(latest).isEqualTo(listOf(sub3))
+    }
 
     @Test
-    fun filteredSubscriptions_vcnSubId_disagreesWithActiveSubId_usesVcnSub() =
-        kosmos.runTest {
-            val (sub1, sub3) =
-                createSubscriptionPair(
-                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
-                    opportunistic = Pair(true, true),
-                    grouped = true,
-                )
-            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
-            kosmos.connectivityRepository.fake.vcnSubId.value = SUB_1_ID
-            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
-                .thenReturn(false)
+    fun filteredSubscriptions_vcnSubId_disagreesWithActiveSubId_usesVcnSub() = runTest {
+        val (sub1, sub3) =
+            createSubscriptionPair(
+                subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                opportunistic = Pair(true, true),
+                grouped = true,
+            )
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1, sub3))
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_3_ID)
+        kosmos.connectivityRepository.fake.vcnSubId.value = SUB_1_ID
+        whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+            .thenReturn(false)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf(sub1))
-        }
+        assertThat(latest).isEqualTo(listOf(sub1))
+    }
 
     @Test
-    fun filteredSubscriptions_doesNotFilterProvisioningWhenFlagIsFalse() =
-        kosmos.runTest {
-            // GIVEN the flag is false
-            featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
+    fun filteredSubscriptions_doesNotFilterProvisioningWhenFlagIsFalse() = runTest {
+        // GIVEN the flag is false
+        featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
 
-            // GIVEN 1 sub that is in PROFILE_CLASS_PROVISIONING
-            val sub1 =
-                SubscriptionModel(
-                    subscriptionId = SUB_1_ID,
-                    isOpportunistic = false,
-                    carrierName = "Carrier 1",
-                    profileClass = PROFILE_CLASS_PROVISIONING,
-                )
+        // GIVEN 1 sub that is in PROFILE_CLASS_PROVISIONING
+        val sub1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                isOpportunistic = false,
+                carrierName = "Carrier 1",
+                profileClass = PROFILE_CLASS_PROVISIONING,
+            )
 
-            connectionsRepository.setSubscriptions(listOf(sub1))
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1))
 
-            // WHEN filtering is applied
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        // WHEN filtering is applied
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            // THEN the provisioning sub is still present (unfiltered)
-            assertThat(latest).isEqualTo(listOf(sub1))
-        }
+        // THEN the provisioning sub is still present (unfiltered)
+        assertThat(latest).isEqualTo(listOf(sub1))
+    }
 
     @Test
-    fun filteredSubscriptions_filtersOutProvisioningSubs() =
-        kosmos.runTest {
-            val sub1 =
-                SubscriptionModel(
-                    subscriptionId = SUB_1_ID,
-                    isOpportunistic = false,
-                    carrierName = "Carrier 1",
-                    profileClass = PROFILE_CLASS_UNSET,
-                )
-            val sub2 =
-                SubscriptionModel(
-                    subscriptionId = SUB_2_ID,
-                    isOpportunistic = false,
-                    carrierName = "Carrier 2",
-                    profileClass = PROFILE_CLASS_PROVISIONING,
-                )
+    fun filteredSubscriptions_filtersOutProvisioningSubs() = runTest {
+        val sub1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                isOpportunistic = false,
+                carrierName = "Carrier 1",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        val sub2 =
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                isOpportunistic = false,
+                carrierName = "Carrier 2",
+                profileClass = PROFILE_CLASS_PROVISIONING,
+            )
 
-            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1, sub2))
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf(sub1))
-        }
+        assertThat(latest).isEqualTo(listOf(sub1))
+    }
 
     /** Note: I'm not sure if this will ever be the case, but we can test it at least */
     @Test
-    fun filteredSubscriptions_filtersOutProvisioningSubsBeforeOpportunistic() =
-        kosmos.runTest {
-            // This is a contrived test case, where the active subId is the one that would
-            // also be filtered by opportunistic filtering.
+    fun filteredSubscriptions_filtersOutProvisioningSubsBeforeOpportunistic() = runTest {
+        // This is a contrived test case, where the active subId is the one that would
+        // also be filtered by opportunistic filtering.
 
-            // GIVEN grouped, opportunistic subscriptions
-            val groupUuid = ParcelUuid(UUID.randomUUID())
-            val sub1 =
-                SubscriptionModel(
-                    subscriptionId = 1,
-                    isOpportunistic = true,
-                    groupUuid = groupUuid,
-                    carrierName = "Carrier 1",
-                    profileClass = PROFILE_CLASS_PROVISIONING,
-                )
+        // GIVEN grouped, opportunistic subscriptions
+        val groupUuid = ParcelUuid(UUID.randomUUID())
+        val sub1 =
+            SubscriptionModel(
+                subscriptionId = 1,
+                isOpportunistic = true,
+                groupUuid = groupUuid,
+                carrierName = "Carrier 1",
+                profileClass = PROFILE_CLASS_PROVISIONING,
+            )
 
-            val sub2 =
-                SubscriptionModel(
-                    subscriptionId = 2,
-                    isOpportunistic = true,
-                    groupUuid = groupUuid,
-                    carrierName = "Carrier 2",
-                    profileClass = PROFILE_CLASS_UNSET,
-                )
+        val sub2 =
+            SubscriptionModel(
+                subscriptionId = 2,
+                isOpportunistic = true,
+                groupUuid = groupUuid,
+                carrierName = "Carrier 2",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
 
-            // GIVEN active subId is 1
-            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
-            connectionsRepository.setActiveMobileDataSubscriptionId(1)
+        // GIVEN active subId is 1
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1, sub2))
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(1)
 
-            // THEN filtering of provisioning subs takes place first, and we result in sub2
+        // THEN filtering of provisioning subs takes place first, and we result in sub2
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        val latest by underTest.filteredSubscriptions.collectLastValue()
 
-            assertThat(latest).isEqualTo(listOf(sub2))
-        }
+        assertThat(latest).isEqualTo(listOf(sub2))
+    }
 
     @Test
     fun filteredSubscriptions_groupedPairAndNonProvisioned_groupedFilteringStillHappens() =
-        kosmos.runTest {
+        runTest {
             // Grouped filtering only happens when the list of subs is length 2. In this case
             // we'll show that filtering of provisioning subs happens before, and thus grouped
             // filtering happens even though the unfiltered list is length 3
@@ -384,87 +357,88 @@
                     profileClass = PROFILE_CLASS_PROVISIONING,
                 )
 
-            connectionsRepository.setSubscriptions(listOf(sub1, sub2, sub3))
-            connectionsRepository.setActiveMobileDataSubscriptionId(1)
+            mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(sub1, sub2, sub3))
+            mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(1)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+            val latest by underTest.filteredSubscriptions.collectLastValue()
 
             assertThat(latest).isEqualTo(listOf(sub1))
         }
 
     @Test
-    fun filteredSubscriptions_subNotExclusivelyNonTerrestrial_hasSub() =
-        kosmos.runTest {
-            val notExclusivelyNonTerrestrialSub =
-                SubscriptionModel(
-                    isExclusivelyNonTerrestrial = false,
-                    subscriptionId = 5,
-                    carrierName = "Carrier 5",
-                    profileClass = PROFILE_CLASS_UNSET,
-                )
-
-            connectionsRepository.setSubscriptions(listOf(notExclusivelyNonTerrestrialSub))
-
-            val latest by collectLastValue(underTest.filteredSubscriptions)
-
-            assertThat(latest).isEqualTo(listOf(notExclusivelyNonTerrestrialSub))
-        }
-
-    @Test
-    fun filteredSubscriptions_subExclusivelyNonTerrestrial_doesNotHaveSub() =
-        kosmos.runTest {
-            val exclusivelyNonTerrestrialSub =
-                SubscriptionModel(
-                    isExclusivelyNonTerrestrial = true,
-                    subscriptionId = 5,
-                    carrierName = "Carrier 5",
-                    profileClass = PROFILE_CLASS_UNSET,
-                )
-
-            connectionsRepository.setSubscriptions(listOf(exclusivelyNonTerrestrialSub))
-
-            val latest by collectLastValue(underTest.filteredSubscriptions)
-
-            assertThat(latest).isEmpty()
-        }
-
-    @Test
-    fun filteredSubscription_mixOfExclusivelyNonTerrestrialAndOther_hasOtherSubsOnly() =
-        kosmos.runTest {
-            val exclusivelyNonTerrestrialSub =
-                SubscriptionModel(
-                    isExclusivelyNonTerrestrial = true,
-                    subscriptionId = 5,
-                    carrierName = "Carrier 5",
-                    profileClass = PROFILE_CLASS_UNSET,
-                )
-            val otherSub1 =
-                SubscriptionModel(
-                    isExclusivelyNonTerrestrial = false,
-                    subscriptionId = 1,
-                    carrierName = "Carrier 1",
-                    profileClass = PROFILE_CLASS_UNSET,
-                )
-            val otherSub2 =
-                SubscriptionModel(
-                    isExclusivelyNonTerrestrial = false,
-                    subscriptionId = 2,
-                    carrierName = "Carrier 2",
-                    profileClass = PROFILE_CLASS_UNSET,
-                )
-
-            connectionsRepository.setSubscriptions(
-                listOf(otherSub1, exclusivelyNonTerrestrialSub, otherSub2)
+    fun filteredSubscriptions_subNotExclusivelyNonTerrestrial_hasSub() = runTest {
+        val notExclusivelyNonTerrestrialSub =
+            SubscriptionModel(
+                isExclusivelyNonTerrestrial = false,
+                subscriptionId = 5,
+                carrierName = "Carrier 5",
+                profileClass = PROFILE_CLASS_UNSET,
             )
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(
+            listOf(notExclusivelyNonTerrestrialSub)
+        )
 
-            assertThat(latest).isEqualTo(listOf(otherSub1, otherSub2))
-        }
+        val latest by underTest.filteredSubscriptions.collectLastValue()
+
+        assertThat(latest).isEqualTo(listOf(notExclusivelyNonTerrestrialSub))
+    }
+
+    @Test
+    fun filteredSubscriptions_subExclusivelyNonTerrestrial_doesNotHaveSub() = runTest {
+        val exclusivelyNonTerrestrialSub =
+            SubscriptionModel(
+                isExclusivelyNonTerrestrial = true,
+                subscriptionId = 5,
+                carrierName = "Carrier 5",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(
+            listOf(exclusivelyNonTerrestrialSub)
+        )
+
+        val latest by underTest.filteredSubscriptions.collectLastValue()
+
+        assertThat(latest).isEmpty()
+    }
+
+    @Test
+    fun filteredSubscription_mixOfExclusivelyNonTerrestrialAndOther_hasOtherSubsOnly() = runTest {
+        val exclusivelyNonTerrestrialSub =
+            SubscriptionModel(
+                isExclusivelyNonTerrestrial = true,
+                subscriptionId = 5,
+                carrierName = "Carrier 5",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        val otherSub1 =
+            SubscriptionModel(
+                isExclusivelyNonTerrestrial = false,
+                subscriptionId = 1,
+                carrierName = "Carrier 1",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        val otherSub2 =
+            SubscriptionModel(
+                isExclusivelyNonTerrestrial = false,
+                subscriptionId = 2,
+                carrierName = "Carrier 2",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(
+            listOf(otherSub1, exclusivelyNonTerrestrialSub, otherSub2)
+        )
+
+        val latest by underTest.filteredSubscriptions.collectLastValue()
+
+        assertThat(latest).isEqualTo(listOf(otherSub1, otherSub2))
+    }
 
     @Test
     fun filteredSubscriptions_exclusivelyNonTerrestrialSub_andOpportunistic_bothFiltersHappen() =
-        kosmos.runTest {
+        runTest {
             // Exclusively non-terrestrial sub
             val exclusivelyNonTerrestrialSub =
                 SubscriptionModel(
@@ -483,10 +457,12 @@
                 )
 
             // WHEN both an exclusively non-terrestrial sub and opportunistic sub pair is included
-            connectionsRepository.setSubscriptions(listOf(sub3, sub4, exclusivelyNonTerrestrialSub))
-            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+            mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(
+                listOf(sub3, sub4, exclusivelyNonTerrestrialSub)
+            )
+            mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(SUB_3_ID)
 
-            val latest by collectLastValue(underTest.filteredSubscriptions)
+            val latest by underTest.filteredSubscriptions.collectLastValue()
 
             // THEN both the only-non-terrestrial sub and the non-active sub are filtered out,
             // leaving only sub3.
@@ -494,484 +470,427 @@
         }
 
     @Test
-    fun activeDataConnection_turnedOn() =
-        kosmos.runTest {
-            (fakeMobileConnectionsRepository.getRepoForSubId(SUB_1_ID)
-                    as FakeMobileConnectionRepository)
-                .dataEnabled
-                .value = true
+    fun activeDataConnection_turnedOn() = runTest {
+        val connection1 =
+            mobileConnectionsRepositoryKairos.fake.mobileConnectionsBySubId.sample()[SUB_1_ID]!!
 
-            val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
+        connection1.dataEnabled.setValue(true)
 
-            assertThat(latest).isTrue()
-        }
+        val latest by underTest.activeDataConnectionHasDataEnabled.collectLastValue()
+
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun activeDataConnection_turnedOff() =
-        kosmos.runTest {
-            (fakeMobileConnectionsRepository.getRepoForSubId(SUB_1_ID)
-                    as FakeMobileConnectionRepository)
-                .dataEnabled
-                .value = true
+    fun activeDataConnection_turnedOff() = runTest {
+        val connection1 =
+            mobileConnectionsRepositoryKairos.fake.mobileConnectionsBySubId.sample()[SUB_1_ID]!!
 
-            val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
+        connection1.dataEnabled.setValue(true)
+        val latest by underTest.activeDataConnectionHasDataEnabled.collectLastValue()
 
-            (fakeMobileConnectionsRepository.getRepoForSubId(SUB_1_ID)
-                    as FakeMobileConnectionRepository)
-                .dataEnabled
-                .value = false
+        connection1.dataEnabled.setValue(false)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun activeDataConnection_invalidSubId() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
+    fun activeDataConnection_invalidSubId() = runTest {
+        val latest by underTest.activeDataConnectionHasDataEnabled.collectLastValue()
 
-            connectionsRepository.setActiveMobileDataSubscriptionId(INVALID_SUBSCRIPTION_ID)
+        mobileConnectionsRepositoryKairos.fake.setActiveMobileDataSubscriptionId(
+            INVALID_SUBSCRIPTION_ID
+        )
 
-            // An invalid active subId should tell us that data is off
-            assertThat(latest).isFalse()
-        }
+        // An invalid active subId should tell us that data is off
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun failedConnection_default_validated_notFailed() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun failedConnection_default_validated_notFailed() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = true
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(true)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun failedConnection_notDefault_notValidated_notFailed() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun failedConnection_notDefault_notValidated_notFailed() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = false
-            connectionsRepository.defaultConnectionIsValidated.value = false
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(false)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun failedConnection_default_notValidated_failed() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun failedConnection_default_notValidated_failed() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = false
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun failedConnection_carrierMergedDefault_notValidated_failed() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun failedConnection_carrierMergedDefault_notValidated_failed() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            connectionsRepository.hasCarrierMergedConnection.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = false
+        mobileConnectionsRepositoryKairos.fake.hasCarrierMergedConnection.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     /** Regression test for b/275076959. */
     @Test
-    fun failedConnection_dataSwitchInSameGroup_notFailed() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun failedConnection_dataSwitchInSameGroup_notFailed() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = true
-            runCurrent()
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(true)
+        runCurrent()
 
-            // WHEN there's a data change in the same subscription group
-            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
-            connectionsRepository.defaultConnectionIsValidated.value = false
-            runCurrent()
+        // WHEN there's a data change in the same subscription group
+        mobileConnectionsRepositoryKairos.fake.activeSubChangedInGroupEvent.emit(Unit)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
+        runCurrent()
 
-            // THEN the default connection is *not* marked as failed because of forced validation
-            assertThat(latest).isFalse()
-        }
+        // THEN the default connection is *not* marked as failed because of forced validation
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun failedConnection_dataSwitchNotInSameGroup_isFailed() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun failedConnection_dataSwitchNotInSameGroup_isFailed() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = true
-            runCurrent()
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(true)
+        runCurrent()
 
-            // WHEN the connection is invalidated without a activeSubChangedInGroupEvent
-            connectionsRepository.defaultConnectionIsValidated.value = false
+        // WHEN the connection is invalidated without a activeSubChangedInGroupEvent
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
 
-            // THEN the connection is immediately marked as failed
-            assertThat(latest).isTrue()
-        }
+        // THEN the connection is immediately marked as failed
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun alwaysShowDataRatIcon_configHasTrue() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.alwaysShowDataRatIcon)
+    fun alwaysShowDataRatIcon_configHasTrue() = runTest {
+        val latest by underTest.alwaysShowDataRatIcon.collectLastValue()
 
-            val config = MobileMappings.Config()
-            config.alwaysShowDataRatIcon = true
-            connectionsRepository.defaultDataSubRatConfig.value = config
+        val config = MobileMappings.Config()
+        config.alwaysShowDataRatIcon = true
+        mobileConnectionsRepositoryKairos.fake.defaultDataSubRatConfig.setValue(config)
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun alwaysShowDataRatIcon_configHasFalse() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.alwaysShowDataRatIcon)
+    fun alwaysShowDataRatIcon_configHasFalse() = runTest {
+        val latest by underTest.alwaysShowDataRatIcon.collectLastValue()
 
-            val config = MobileMappings.Config()
-            config.alwaysShowDataRatIcon = false
-            connectionsRepository.defaultDataSubRatConfig.value = config
+        val config = MobileMappings.Config()
+        config.alwaysShowDataRatIcon = false
+        mobileConnectionsRepositoryKairos.fake.defaultDataSubRatConfig.setValue(config)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun alwaysUseCdmaLevel_configHasTrue() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.alwaysUseCdmaLevel)
+    fun alwaysUseCdmaLevel_configHasTrue() = runTest {
+        val latest by underTest.alwaysUseCdmaLevel.collectLastValue()
 
-            val config = MobileMappings.Config()
-            config.alwaysShowCdmaRssi = true
-            connectionsRepository.defaultDataSubRatConfig.value = config
+        val config = MobileMappings.Config()
+        config.alwaysShowCdmaRssi = true
+        mobileConnectionsRepositoryKairos.fake.defaultDataSubRatConfig.setValue(config)
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun alwaysUseCdmaLevel_configHasFalse() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.alwaysUseCdmaLevel)
+    fun alwaysUseCdmaLevel_configHasFalse() = runTest {
+        val latest by underTest.alwaysUseCdmaLevel.collectLastValue()
 
-            val config = MobileMappings.Config()
-            config.alwaysShowCdmaRssi = false
-            connectionsRepository.defaultDataSubRatConfig.value = config
+        val config = MobileMappings.Config()
+        config.alwaysShowCdmaRssi = false
+        mobileConnectionsRepositoryKairos.fake.defaultDataSubRatConfig.setValue(config)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun isSingleCarrier_zeroSubscriptions_false() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isSingleCarrier)
+    fun isSingleCarrier_zeroSubscriptions_false() = runTest {
+        val latest by underTest.isSingleCarrier.collectLastValue()
 
-            connectionsRepository.setSubscriptions(emptyList())
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(emptyList())
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun isSingleCarrier_oneSubscription_true() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isSingleCarrier)
+    fun isSingleCarrier_oneSubscription_true() = runTest {
+        val latest by underTest.isSingleCarrier.collectLastValue()
 
-            connectionsRepository.setSubscriptions(listOf(SUB_1))
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1))
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun isSingleCarrier_twoSubscriptions_false() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isSingleCarrier)
+    fun isSingleCarrier_twoSubscriptions_false() = runTest {
+        val latest by underTest.isSingleCarrier.collectLastValue()
 
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1, SUB_2))
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun isSingleCarrier_updates() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isSingleCarrier)
+    fun isSingleCarrier_updates() = runTest {
+        val latest by underTest.isSingleCarrier.collectLastValue()
 
-            connectionsRepository.setSubscriptions(listOf(SUB_1))
-            assertThat(latest).isTrue()
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1))
+        assertThat(latest).isTrue()
 
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
-            assertThat(latest).isFalse()
-        }
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1, SUB_2))
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.mobileIsDefault)
+    fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() = runTest {
+        val latest by underTest.mobileIsDefault.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = false
-            connectionsRepository.hasCarrierMergedConnection.value = false
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(false)
+        mobileConnectionsRepositoryKairos.fake.hasCarrierMergedConnection.setValue(false)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun mobileIsDefault_mobileTrueAndCarrierMergedFalse_true() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.mobileIsDefault)
+    fun mobileIsDefault_mobileTrueAndCarrierMergedFalse_true() = runTest {
+        val latest by underTest.mobileIsDefault.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.hasCarrierMergedConnection.value = false
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.hasCarrierMergedConnection.setValue(false)
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     /** Regression test for b/272586234. */
     @Test
-    fun mobileIsDefault_mobileFalseAndCarrierMergedTrue_true() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.mobileIsDefault)
+    fun mobileIsDefault_mobileFalseAndCarrierMergedTrue_true() = runTest {
+        val latest by underTest.mobileIsDefault.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = false
-            connectionsRepository.hasCarrierMergedConnection.value = true
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(false)
+        mobileConnectionsRepositoryKairos.fake.hasCarrierMergedConnection.setValue(true)
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun mobileIsDefault_updatesWhenRepoUpdates() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.mobileIsDefault)
+    fun mobileIsDefault_updatesWhenRepoUpdates() = runTest {
+        val latest by underTest.mobileIsDefault.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = true
-            assertThat(latest).isTrue()
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        assertThat(latest).isTrue()
 
-            connectionsRepository.mobileIsDefault.value = false
-            assertThat(latest).isFalse()
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(false)
+        assertThat(latest).isFalse()
 
-            connectionsRepository.hasCarrierMergedConnection.value = true
-            assertThat(latest).isTrue()
-        }
+        mobileConnectionsRepositoryKairos.fake.hasCarrierMergedConnection.setValue(true)
+        assertThat(latest).isTrue()
+    }
 
     // The data switch tests are mostly testing the [forcingCellularValidation] flow, but that flow
     // is private and can only be tested by looking at [isDefaultConnectionFailed].
 
     @Test
-    fun dataSwitch_inSameGroup_validatedMatchesPreviousValue_expiresAfter2s() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun dataSwitch_inSameGroup_validatedMatchesPreviousValue_expiresAfter2s() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = true
-            runCurrent()
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(true)
+        runCurrent()
 
-            // Trigger a data change in the same subscription group that's not yet validated
-            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
-            connectionsRepository.defaultConnectionIsValidated.value = false
-            runCurrent()
+        // Trigger a data change in the same subscription group that's not yet validated
+        mobileConnectionsRepositoryKairos.fake.activeSubChangedInGroupEvent.emit(Unit)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
+        runCurrent()
 
-            // After 1s, the force validation bit is still present, so the connection is not marked
-            // as failed
-            testScope.advanceTimeBy(1000)
-            assertThat(latest).isFalse()
+        // After 1s, the force validation bit is still present, so the connection is not marked
+        // as failed
+        testScope.advanceTimeBy(1000)
+        assertThat(latest).isFalse()
 
-            // After 2s, the force validation expires so the connection updates to failed
-            testScope.advanceTimeBy(1001)
-            assertThat(latest).isTrue()
-        }
+        // After 2s, the force validation expires so the connection updates to failed
+        testScope.advanceTimeBy(1001)
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun dataSwitch_inSameGroup_notValidated_immediatelyMarkedAsFailed() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun dataSwitch_inSameGroup_notValidated_immediatelyMarkedAsFailed() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = false
-            runCurrent()
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
+        runCurrent()
 
-            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+        mobileConnectionsRepositoryKairos.fake.activeSubChangedInGroupEvent.emit(Unit)
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun dataSwitch_loseValidation_thenSwitchHappens_clearsForcedBit() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+    fun dataSwitch_loseValidation_thenSwitchHappens_clearsForcedBit() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
 
-            // GIVEN the network starts validated
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = true
-            runCurrent()
+        // GIVEN the network starts validated
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(true)
+        runCurrent()
 
-            // WHEN a data change happens in the same group
-            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+        // WHEN a data change happens in the same group
+        mobileConnectionsRepositoryKairos.fake.activeSubChangedInGroupEvent.emit(Unit)
 
-            // WHEN the validation bit is lost
-            connectionsRepository.defaultConnectionIsValidated.value = false
-            runCurrent()
+        // WHEN the validation bit is lost
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
+        runCurrent()
 
-            // WHEN another data change happens in the same group
-            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+        // WHEN another data change happens in the same group
+        mobileConnectionsRepositoryKairos.fake.activeSubChangedInGroupEvent.emit(Unit)
 
-            // THEN the forced validation bit is still used...
-            assertThat(latest).isFalse()
+        // THEN the forced validation bit is still used...
+        assertThat(latest).isFalse()
 
-            testScope.advanceTimeBy(1000)
-            assertThat(latest).isFalse()
+        testScope.advanceTimeBy(1000)
+        assertThat(latest).isFalse()
 
-            // ... but expires after 2s
-            testScope.advanceTimeBy(1001)
-            assertThat(latest).isTrue()
-        }
+        // ... but expires after 2s
+        testScope.advanceTimeBy(1001)
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun dataSwitch_whileAlreadyForcingValidation_resetsClock() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
-            connectionsRepository.mobileIsDefault.value = true
-            connectionsRepository.defaultConnectionIsValidated.value = true
-            runCurrent()
+    fun dataSwitch_whileAlreadyForcingValidation_resetsClock() = runTest {
+        val latest by underTest.isDefaultConnectionFailed.collectLastValue()
+        mobileConnectionsRepositoryKairos.fake.mobileIsDefault.setValue(true)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(true)
+        runCurrent()
 
-            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+        mobileConnectionsRepositoryKairos.fake.activeSubChangedInGroupEvent.emit(Unit)
 
-            testScope.advanceTimeBy(1000)
+        testScope.advanceTimeBy(1000)
 
-            // WHEN another change in same group event happens
-            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
-            connectionsRepository.defaultConnectionIsValidated.value = false
-            runCurrent()
+        // WHEN another change in same group event happens
+        mobileConnectionsRepositoryKairos.fake.activeSubChangedInGroupEvent.emit(Unit)
+        mobileConnectionsRepositoryKairos.fake.defaultConnectionIsValidated.setValue(false)
+        runCurrent()
 
-            // THEN the forced validation remains for exactly 2 more seconds from now
+        // THEN the forced validation remains for exactly 2 more seconds from now
 
-            // 1.500s from second event
-            testScope.advanceTimeBy(1500)
-            assertThat(latest).isFalse()
+        // 1.500s from second event
+        testScope.advanceTimeBy(1500)
+        assertThat(latest).isFalse()
 
-            // 2.001s from the second event
-            testScope.advanceTimeBy(501)
-            assertThat(latest).isTrue()
-        }
+        // 2.001s from the second event
+        testScope.advanceTimeBy(501)
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun isForceHidden_repoHasMobileHidden_true() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isForceHidden)
+    fun isForceHidden_repoHasMobileHidden_true() = runTest {
+        val latest by underTest.isForceHidden.collectLastValue()
 
-            kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
+        kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
 
-            assertThat(latest).isTrue()
-        }
+        assertThat(latest).isTrue()
+    }
 
     @Test
-    fun isForceHidden_repoDoesNotHaveMobileHidden_false() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isForceHidden)
+    fun isForceHidden_repoDoesNotHaveMobileHidden_false() = runTest {
+        val latest by underTest.isForceHidden.collectLastValue()
 
-            kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+        kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
-    fun iconInteractor_cachedPerSubId() =
-        kosmos.runTest {
-            val interactor1 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
-            val interactor2 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
+    fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() = runTest {
+        val latest by underTest.isDeviceInEmergencyCallsOnlyMode.collectLastValue()
 
-            assertThat(interactor1).isNotNull()
-            assertThat(interactor1).isSameInstanceAs(interactor2)
-        }
+        mobileConnectionsRepositoryKairos.fake.isDeviceEmergencyCallCapable.setValue(true)
 
-    @Test
-    fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode)
+        assertThat(latest).isTrue()
 
-            connectionsRepository.isDeviceEmergencyCallCapable.value = true
+        mobileConnectionsRepositoryKairos.fake.isDeviceEmergencyCallCapable.setValue(false)
 
-            assertThat(latest).isTrue()
-
-            connectionsRepository.isDeviceEmergencyCallCapable.value = false
-
-            assertThat(latest).isFalse()
-        }
-
-    @Test
-    fun defaultDataSubId_tracksRepo() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.defaultDataSubId)
-
-            connectionsRepository.defaultDataSubId.value = 1
-
-            assertThat(latest).isEqualTo(1)
-
-            connectionsRepository.defaultDataSubId.value = 2
-
-            assertThat(latest).isEqualTo(2)
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
     @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
-    fun isStackable_tracksNumberOfSubscriptions() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isStackable)
+    fun isStackable_tracksNumberOfSubscriptions() = runTest {
+        val latest by underTest.isStackable.collectLastValue()
 
-            connectionsRepository.setSubscriptions(listOf(SUB_1))
-            assertThat(latest).isFalse()
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1))
+        assertThat(latest).isFalse()
 
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
-            assertThat(latest).isTrue()
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1, SUB_2))
+        assertThat(latest).isTrue()
 
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2, SUB_3_OPP))
-            assertThat(latest).isFalse()
-        }
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(
+            listOf(SUB_1, SUB_2, SUB_3_OPP)
+        )
+        assertThat(latest).isFalse()
+    }
 
     @Test
     @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
-    fun isStackable_checksForTerrestrialConnections() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isStackable)
+    fun isStackable_checksForTerrestrialConnections() = runTest {
+        val latest by underTest.isStackable.collectLastValue()
 
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
-            setNumberOfLevelsForSubId(SUB_1_ID, 5)
-            setNumberOfLevelsForSubId(SUB_2_ID, 5)
-            assertThat(latest).isTrue()
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1, SUB_2))
+        setNumberOfLevelsForSubId(SUB_1_ID, 5)
+        setNumberOfLevelsForSubId(SUB_2_ID, 5)
+        assertThat(latest).isTrue()
 
-            (fakeMobileConnectionsRepository.getRepoForSubId(SUB_1_ID)
-                    as FakeMobileConnectionRepository)
-                .isNonTerrestrial
-                .value = true
+        mobileConnectionsRepositoryKairos.fake.mobileConnectionsBySubId
+            .sample()[SUB_1_ID]!!
+            .isNonTerrestrial
+            .setValue(true)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
     @Test
     @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
-    fun isStackable_checksForNumberOfBars() =
-        kosmos.runTest {
-            val latest by collectLastValue(underTest.isStackable)
+    fun isStackable_checksForNumberOfBars() = runTest {
+        val latest by underTest.isStackable.collectLastValue()
 
-            // Number of levels is the same for both
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
-            setNumberOfLevelsForSubId(SUB_1_ID, 5)
-            setNumberOfLevelsForSubId(SUB_2_ID, 5)
+        // Number of levels is the same for both
+        mobileConnectionsRepositoryKairos.fake.subscriptions.setValue(listOf(SUB_1, SUB_2))
+        setNumberOfLevelsForSubId(SUB_1_ID, 5)
+        setNumberOfLevelsForSubId(SUB_2_ID, 5)
 
-            assertThat(latest).isTrue()
+        assertThat(latest).isTrue()
 
-            // Change the number of levels to be different than SUB_2
-            setNumberOfLevelsForSubId(SUB_1_ID, 6)
+        // Change the number of levels to be different than SUB_2
+        setNumberOfLevelsForSubId(SUB_1_ID, 6)
 
-            assertThat(latest).isFalse()
-        }
+        assertThat(latest).isFalse()
+    }
 
-    private fun setNumberOfLevelsForSubId(subId: Int, numberOfLevels: Int) {
-        with(kosmos) {
-            (fakeMobileConnectionsRepository.getRepoForSubId(subId)
-                    as FakeMobileConnectionRepository)
-                .numberOfLevels
-                .value = numberOfLevels
-        }
+    private suspend fun KairosTestScope.setNumberOfLevelsForSubId(subId: Int, numberOfLevels: Int) {
+        mobileConnectionsRepositoryKairos.fake.mobileConnectionsBySubId
+            .sample()[subId]!!
+            .numberOfLevels
+            .setValue(numberOfLevels)
     }
 
     /**
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelKairosTest.kt
new file mode 100644
index 0000000..57e63a5
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelKairosTest.kt
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.connectivity.MobileIconCarrierIdOverridesFake
+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.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.mockito.mock
+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.UnconfinedTestDispatcher
+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
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LocationBasedMobileIconViewModelKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private lateinit var commonImpl: MobileIconViewModelCommonKairos
+    private lateinit var homeIcon: HomeMobileIconViewModelKairos
+    private lateinit var qsIcon: QsMobileIconViewModelKairos
+    private lateinit var keyguardIcon: KeyguardMobileIconViewModelKairos
+    private lateinit var iconsInteractor: MobileIconsInteractor
+    private lateinit var interactor: MobileIconInteractor
+    private val connectionsRepository = kosmos.fakeMobileConnectionsRepository
+    private lateinit var repository: FakeMobileConnectionRepository
+    private lateinit var airplaneModeInteractor: AirplaneModeInteractor
+
+    private val connectivityRepository = FakeConnectivityRepository()
+    private val flags =
+        FakeFeatureFlagsClassic().also {
+            it.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+        }
+
+    @Mock private lateinit var constants: ConnectivityConstants
+    private val tableLogBuffer =
+        logcatTableLogBuffer(kosmos, "LocationBasedMobileIconViewModelTest")
+    @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        airplaneModeInteractor =
+            AirplaneModeInteractor(
+                FakeAirplaneModeRepository(),
+                FakeConnectivityRepository(),
+                connectionsRepository,
+            )
+        repository =
+            FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer).apply {
+                isInService.value = true
+                cdmaLevel.value = 1
+                primaryLevel.value = 1
+                isEmergencyOnly.value = false
+                numberOfLevels.value = 4
+                resolvedNetworkType.value = ResolvedNetworkType.DefaultNetworkType(lookupKey = "3G")
+                dataConnectionState.value = DataConnectionState.Connected
+            }
+
+        connectionsRepository.activeMobileDataRepository.value = repository
+
+        connectivityRepository.apply { setMobileConnected() }
+
+        iconsInteractor =
+            MobileIconsInteractorImpl(
+                connectionsRepository,
+                carrierConfigTracker,
+                tableLogBuffer,
+                connectivityRepository,
+                FakeUserSetupRepository(),
+                testScope.backgroundScope,
+                context,
+                flags,
+            )
+
+        interactor =
+            MobileIconInteractorImpl(
+                testScope.backgroundScope,
+                iconsInteractor.activeDataConnectionHasDataEnabled,
+                iconsInteractor.alwaysShowDataRatIcon,
+                iconsInteractor.alwaysUseCdmaLevel,
+                iconsInteractor.isSingleCarrier,
+                iconsInteractor.mobileIsDefault,
+                iconsInteractor.defaultMobileIconMapping,
+                iconsInteractor.defaultMobileIconGroup,
+                iconsInteractor.isDefaultConnectionFailed,
+                iconsInteractor.isForceHidden,
+                repository,
+                context,
+                MobileIconCarrierIdOverridesFake(),
+            )
+
+        commonImpl =
+            MobileIconViewModelKairos(
+                SUB_1_ID,
+                interactor,
+                airplaneModeInteractor,
+                constants,
+                testScope.backgroundScope,
+            )
+
+        homeIcon = HomeMobileIconViewModelKairos(commonImpl, mock())
+        qsIcon = QsMobileIconViewModelKairos(commonImpl)
+        keyguardIcon = KeyguardMobileIconViewModelKairos(commonImpl)
+    }
+
+    @Test
+    fun locationBasedViewModelsReceiveSameIconIdWhenCommonImplUpdates() =
+        testScope.runTest {
+            var latestHome: SignalIconModel? = null
+            val homeJob = homeIcon.icon.onEach { latestHome = it }.launchIn(this)
+
+            var latestQs: SignalIconModel? = null
+            val qsJob = qsIcon.icon.onEach { latestQs = it }.launchIn(this)
+
+            var latestKeyguard: SignalIconModel? = null
+            val keyguardJob = keyguardIcon.icon.onEach { latestKeyguard = it }.launchIn(this)
+
+            var expected = defaultSignal(level = 1)
+
+            assertThat(latestHome).isEqualTo(expected)
+            assertThat(latestQs).isEqualTo(expected)
+            assertThat(latestKeyguard).isEqualTo(expected)
+
+            repository.setAllLevels(2)
+            expected = defaultSignal(level = 2)
+
+            assertThat(latestHome).isEqualTo(expected)
+            assertThat(latestQs).isEqualTo(expected)
+            assertThat(latestKeyguard).isEqualTo(expected)
+
+            homeJob.cancel()
+            qsJob.cancel()
+            keyguardJob.cancel()
+        }
+
+    companion object {
+        private const val SUB_1_ID = 1
+        private const val NUM_LEVELS = 4
+
+        /** Convenience constructor for these tests */
+        fun defaultSignal(level: Int = 1): SignalIconModel {
+            return SignalIconModel.Cellular(
+                level,
+                NUM_LEVELS,
+                showExclamationMark = false,
+                carrierNetworkChange = false,
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelKairosTest.kt
new file mode 100644
index 0000000..6b114a8
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelKairosTest.kt
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.TelephonyIcons.G
+import com.android.settingslib.mobile.TelephonyIcons.THREE_G
+import com.android.settingslib.mobile.TelephonyIcons.UNKNOWN
+import com.android.systemui.Flags.FLAG_STATUS_BAR_STATIC_INOUT_INDICATORS
+import com.android.systemui.SysuiTestCase
+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.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.connectivity.MobileIconCarrierIdOverridesFake
+import com.android.systemui.statusbar.core.NewStatusBarIcons
+import com.android.systemui.statusbar.core.StatusBarRootModernization
+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.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository.Companion.DEFAULT_NETWORK_NAME
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.model.MobileContentDescription
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.yield
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileIconViewModelKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private var connectivityRepository = FakeConnectivityRepository()
+
+    private lateinit var underTest: MobileIconViewModelKairos
+    private lateinit var interactor: MobileIconInteractorImpl
+    private lateinit var iconsInteractor: MobileIconsInteractorImpl
+    private lateinit var repository: FakeMobileConnectionRepository
+    private lateinit var connectionsRepository: FakeMobileConnectionsRepository
+    private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
+    private lateinit var airplaneModeInteractor: AirplaneModeInteractor
+    @Mock private lateinit var constants: ConnectivityConstants
+    private val tableLogBuffer = logcatTableLogBuffer(kosmos, "MobileIconViewModelTest")
+    @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
+
+    private val flags =
+        FakeFeatureFlagsClassic().also {
+            it.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+        }
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(constants.hasDataCapabilities).thenReturn(true)
+
+        connectionsRepository =
+            FakeMobileConnectionsRepository(FakeMobileMappingsProxy(), tableLogBuffer)
+
+        repository =
+            FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer).apply {
+                setNetworkTypeKey(connectionsRepository.GSM_KEY)
+                isInService.value = true
+                dataConnectionState.value = DataConnectionState.Connected
+                dataEnabled.value = true
+            }
+        connectionsRepository.activeMobileDataRepository.value = repository
+        connectionsRepository.mobileIsDefault.value = true
+
+        airplaneModeRepository = FakeAirplaneModeRepository()
+        airplaneModeInteractor =
+            AirplaneModeInteractor(
+                airplaneModeRepository,
+                connectivityRepository,
+                kosmos.fakeMobileConnectionsRepository,
+            )
+
+        iconsInteractor =
+            MobileIconsInteractorImpl(
+                connectionsRepository,
+                carrierConfigTracker,
+                tableLogBuffer,
+                connectivityRepository,
+                FakeUserSetupRepository(),
+                testScope.backgroundScope,
+                context,
+                flags,
+            )
+
+        interactor =
+            MobileIconInteractorImpl(
+                testScope.backgroundScope,
+                iconsInteractor.activeDataConnectionHasDataEnabled,
+                iconsInteractor.alwaysShowDataRatIcon,
+                iconsInteractor.alwaysUseCdmaLevel,
+                iconsInteractor.isSingleCarrier,
+                iconsInteractor.mobileIsDefault,
+                iconsInteractor.defaultMobileIconMapping,
+                iconsInteractor.defaultMobileIconGroup,
+                iconsInteractor.isDefaultConnectionFailed,
+                iconsInteractor.isForceHidden,
+                repository,
+                context,
+                MobileIconCarrierIdOverridesFake(),
+            )
+        createAndSetViewModel()
+    }
+
+    @Test
+    fun isVisible_notDataCapable_alwaysFalse() =
+        testScope.runTest {
+            // Create a new view model here so the constants are properly read
+            whenever(constants.hasDataCapabilities).thenReturn(false)
+            createAndSetViewModel()
+
+            var latest: Boolean? = null
+            val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isVisible_notAirplane_notForceHidden_true() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
+
+            airplaneModeRepository.setIsAirplaneMode(false)
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isVisible_airplaneAndNotAllowed_false() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
+
+            airplaneModeRepository.setIsAirplaneMode(true)
+            repository.isAllowedDuringAirplaneMode.value = false
+            connectivityRepository.setForceHiddenIcons(setOf())
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    /** Regression test for b/291993542. */
+    @Test
+    fun isVisible_airplaneButAllowed_true() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
+
+            airplaneModeRepository.setIsAirplaneMode(true)
+            repository.isAllowedDuringAirplaneMode.value = true
+            connectivityRepository.setForceHiddenIcons(setOf())
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isVisible_forceHidden_false() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
+
+            airplaneModeRepository.setIsAirplaneMode(false)
+            connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isVisible_respondsToUpdates() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
+
+            airplaneModeRepository.setIsAirplaneMode(false)
+            connectivityRepository.setForceHiddenIcons(setOf())
+
+            assertThat(latest).isTrue()
+
+            airplaneModeRepository.setIsAirplaneMode(true)
+            assertThat(latest).isFalse()
+
+            repository.isAllowedDuringAirplaneMode.value = true
+            assertThat(latest).isTrue()
+
+            connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isVisible_satellite_respectsAirplaneMode() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isVisible)
+
+            repository.isNonTerrestrial.value = true
+            airplaneModeInteractor.setIsAirplaneMode(false)
+
+            assertThat(latest).isTrue()
+
+            airplaneModeInteractor.setIsAirplaneMode(true)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun contentDescription_notInService_usesNoPhone() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+
+            repository.isInService.value = false
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL))
+        }
+
+    @Test
+    fun contentDescription_includesNetworkName() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+
+            repository.isInService.value = true
+            repository.networkName.value = NetworkNameModel.SubscriptionDerived("Test Network Name")
+            repository.numberOfLevels.value = 5
+            repository.setAllLevels(3)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular("Test Network Name", THREE_BARS))
+        }
+
+    @Test
+    fun contentDescription_inService_usesLevel() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+
+            repository.setAllLevels(2)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, TWO_BARS))
+
+            repository.setAllLevels(0)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL))
+        }
+
+    @Test
+    fun contentDescription_nonInflated_invalidLevelUsesNoSignalText() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+
+            repository.inflateSignalStrength.value = false
+            repository.setAllLevels(-1)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL))
+
+            repository.setAllLevels(100)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL))
+        }
+
+    @Test
+    fun contentDescription_nonInflated_levelStrings() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+
+            repository.inflateSignalStrength.value = false
+            repository.setAllLevels(0)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL))
+
+            repository.setAllLevels(1)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, ONE_BAR))
+
+            repository.setAllLevels(2)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, TWO_BARS))
+
+            repository.setAllLevels(3)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, THREE_BARS))
+
+            repository.setAllLevels(4)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, FULL_BARS))
+        }
+
+    @Test
+    fun contentDescription_inflated_invalidLevelUsesNoSignalText() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+
+            repository.inflateSignalStrength.value = true
+            repository.numberOfLevels.value = 6
+
+            repository.setAllLevels(-2)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL))
+
+            repository.setAllLevels(100)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL))
+        }
+
+    @Test
+    fun contentDescription_inflated_levelStrings() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+
+            repository.inflateSignalStrength.value = true
+            repository.numberOfLevels.value = 6
+
+            // Note that the _repo_ level is 1 lower than the reported level through the interactor
+
+            repository.setAllLevels(0)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, ONE_BAR))
+
+            repository.setAllLevels(1)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, TWO_BARS))
+
+            repository.setAllLevels(2)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, THREE_BARS))
+
+            repository.setAllLevels(3)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, FOUR_BARS))
+
+            repository.setAllLevels(4)
+
+            assertThat(latest as MobileContentDescription.Cellular)
+                .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, FULL_BARS))
+        }
+
+    @Test
+    fun contentDescription_nonInflated_testABunchOfLevelsForNull() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+
+            repository.inflateSignalStrength.value = false
+            repository.numberOfLevels.value = 5
+
+            // -1 and 5 are out of the bounds for non-inflated content descriptions
+            for (i in -1..5) {
+                repository.setAllLevels(i)
+                when (i) {
+                    -1,
+                    5 ->
+                        assertWithMessage("Level $i is expected to be 'no signal'")
+                            .that((latest as MobileContentDescription.Cellular).levelDescriptionRes)
+                            .isEqualTo(NO_SIGNAL)
+                    else ->
+                        assertWithMessage("Level $i is expected not to be null")
+                            .that(latest)
+                            .isNotNull()
+                }
+            }
+        }
+
+    @Test
+    fun contentDescription_inflated_testABunchOfLevelsForNull() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.contentDescription)
+            repository.inflateSignalStrength.value = true
+            repository.numberOfLevels.value = 6
+            // -1 and 6 are out of the bounds for inflated content descriptions
+            // Note that the interactor adds 1 to the reported level, hence the -2 to 5 range
+            for (i in -2..5) {
+                repository.setAllLevels(i)
+                when (i) {
+                    -2,
+                    5 ->
+                        assertWithMessage("Level $i is expected to be 'no signal'")
+                            .that((latest as MobileContentDescription.Cellular).levelDescriptionRes)
+                            .isEqualTo(NO_SIGNAL)
+                    else ->
+                        assertWithMessage("Level $i is not expected to be null")
+                            .that(latest)
+                            .isNotNull()
+                }
+            }
+        }
+
+    @Test
+    fun networkType_dataEnabled_groupIsRepresented() =
+        testScope.runTest {
+            val expected =
+                Icon.Resource(
+                    THREE_G.dataType,
+                    ContentDescription.Resource(THREE_G.dataContentDescription),
+                )
+            connectionsRepository.mobileIsDefault.value = true
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_null_whenDisabled() =
+        testScope.runTest {
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.setDataEnabled(false)
+            connectionsRepository.mobileIsDefault.value = true
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isNull()
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_null_whenCarrierNetworkChangeActive() =
+        testScope.runTest {
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.carrierNetworkChangeActive.value = true
+            connectionsRepository.mobileIsDefault.value = true
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isNull()
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkTypeIcon_notNull_whenEnabled() =
+        testScope.runTest {
+            val expected =
+                Icon.Resource(
+                    THREE_G.dataType,
+                    ContentDescription.Resource(THREE_G.dataContentDescription),
+                )
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.setDataEnabled(true)
+            repository.dataConnectionState.value = DataConnectionState.Connected
+            connectionsRepository.mobileIsDefault.value = true
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_nullWhenDataDisconnects() =
+        testScope.runTest {
+            val initial =
+                Icon.Resource(
+                    THREE_G.dataType,
+                    ContentDescription.Resource(THREE_G.dataContentDescription),
+                )
+
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(initial)
+
+            repository.dataConnectionState.value = DataConnectionState.Disconnected
+
+            assertThat(latest).isNull()
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_null_changeToDisabled() =
+        testScope.runTest {
+            val expected =
+                Icon.Resource(
+                    THREE_G.dataType,
+                    ContentDescription.Resource(THREE_G.dataContentDescription),
+                )
+            repository.dataEnabled.value = true
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(expected)
+
+            repository.dataEnabled.value = false
+
+            assertThat(latest).isNull()
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_alwaysShow_shownEvenWhenDisabled() =
+        testScope.runTest {
+            repository.dataEnabled.value = false
+
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
+
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            val expected =
+                Icon.Resource(
+                    THREE_G.dataType,
+                    ContentDescription.Resource(THREE_G.dataContentDescription),
+                )
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_alwaysShow_shownEvenWhenDisconnected() =
+        testScope.runTest {
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.dataConnectionState.value = DataConnectionState.Disconnected
+
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
+
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            val expected =
+                Icon.Resource(
+                    THREE_G.dataType,
+                    ContentDescription.Resource(THREE_G.dataContentDescription),
+                )
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_alwaysShow_shownEvenWhenFailedConnection() =
+        testScope.runTest {
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
+
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            val expected =
+                Icon.Resource(
+                    THREE_G.dataType,
+                    ContentDescription.Resource(THREE_G.dataContentDescription),
+                )
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_alwaysShow_usesDefaultIconWhenInvalid() =
+        testScope.runTest {
+            // The UNKNOWN icon group doesn't have a valid data type icon ID, and the logic from the
+            // old pipeline was to use the default icon group if the map doesn't exist
+            repository.setNetworkTypeKey(UNKNOWN.name)
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
+
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            val expected =
+                Icon.Resource(
+                    connectionsRepository.defaultMobileIconGroup.value.dataType,
+                    ContentDescription.Resource(G.dataContentDescription),
+                )
+
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_alwaysShow_shownWhenNotDefault() =
+        testScope.runTest {
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            connectionsRepository.mobileIsDefault.value = false
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
+
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            val expected =
+                Icon.Resource(
+                    THREE_G.dataType,
+                    ContentDescription.Resource(THREE_G.dataContentDescription),
+                )
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_notShownWhenNotDefault() =
+        testScope.runTest {
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.dataConnectionState.value = DataConnectionState.Connected
+            connectionsRepository.mobileIsDefault.value = false
+
+            var latest: Icon? = null
+            val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isNull()
+
+            job.cancel()
+        }
+
+    @Test
+    fun roaming() =
+        testScope.runTest {
+            repository.setAllRoaming(true)
+
+            var latest: Boolean? = null
+            val job = underTest.roaming.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isTrue()
+
+            repository.setAllRoaming(false)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataActivity_nullWhenConfigIsOff() =
+        testScope.runTest {
+            // Create a new view model here so the constants are properly read
+            whenever(constants.shouldShowActivityConfig).thenReturn(false)
+            createAndSetViewModel()
+
+            var inVisible: Boolean? = null
+            val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
+
+            var outVisible: Boolean? = null
+            val outJob = underTest.activityInVisible.onEach { outVisible = it }.launchIn(this)
+
+            var containerVisible: Boolean? = null
+            val containerJob =
+                underTest.activityInVisible.onEach { containerVisible = it }.launchIn(this)
+
+            repository.dataActivityDirection.value =
+                DataActivityModel(hasActivityIn = true, hasActivityOut = true)
+
+            assertThat(inVisible).isFalse()
+            assertThat(outVisible).isFalse()
+            assertThat(containerVisible).isFalse()
+
+            inJob.cancel()
+            outJob.cancel()
+            containerJob.cancel()
+        }
+
+    @Test
+    @DisableFlags(FLAG_STATUS_BAR_STATIC_INOUT_INDICATORS)
+    fun dataActivity_configOn_testIndicators_staticFlagOff() =
+        testScope.runTest {
+            // Create a new view model here so the constants are properly read
+            whenever(constants.shouldShowActivityConfig).thenReturn(true)
+            createAndSetViewModel()
+
+            var inVisible: Boolean? = null
+            val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
+
+            var outVisible: Boolean? = null
+            val outJob = underTest.activityOutVisible.onEach { outVisible = it }.launchIn(this)
+
+            var containerVisible: Boolean? = null
+            val containerJob =
+                underTest.activityContainerVisible.onEach { containerVisible = it }.launchIn(this)
+
+            repository.dataActivityDirection.value =
+                DataActivityModel(hasActivityIn = true, hasActivityOut = false)
+
+            yield()
+
+            assertThat(inVisible).isTrue()
+            assertThat(outVisible).isFalse()
+            assertThat(containerVisible).isTrue()
+
+            repository.dataActivityDirection.value =
+                DataActivityModel(hasActivityIn = false, hasActivityOut = true)
+
+            assertThat(inVisible).isFalse()
+            assertThat(outVisible).isTrue()
+            assertThat(containerVisible).isTrue()
+
+            repository.dataActivityDirection.value =
+                DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+
+            assertThat(inVisible).isFalse()
+            assertThat(outVisible).isFalse()
+            assertThat(containerVisible).isFalse()
+
+            inJob.cancel()
+            outJob.cancel()
+            containerJob.cancel()
+        }
+
+    @Test
+    @EnableFlags(FLAG_STATUS_BAR_STATIC_INOUT_INDICATORS)
+    fun dataActivity_configOn_testIndicators_staticFlagOn() =
+        testScope.runTest {
+            // Create a new view model here so the constants are properly read
+            whenever(constants.shouldShowActivityConfig).thenReturn(true)
+            createAndSetViewModel()
+
+            var inVisible: Boolean? = null
+            val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
+
+            var outVisible: Boolean? = null
+            val outJob = underTest.activityOutVisible.onEach { outVisible = it }.launchIn(this)
+
+            var containerVisible: Boolean? = null
+            val containerJob =
+                underTest.activityContainerVisible.onEach { containerVisible = it }.launchIn(this)
+
+            repository.dataActivityDirection.value =
+                DataActivityModel(hasActivityIn = true, hasActivityOut = false)
+
+            yield()
+
+            assertThat(inVisible).isTrue()
+            assertThat(outVisible).isFalse()
+            assertThat(containerVisible).isTrue()
+
+            repository.dataActivityDirection.value =
+                DataActivityModel(hasActivityIn = false, hasActivityOut = true)
+
+            assertThat(inVisible).isFalse()
+            assertThat(outVisible).isTrue()
+            assertThat(containerVisible).isTrue()
+
+            repository.dataActivityDirection.value =
+                DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+
+            assertThat(inVisible).isFalse()
+            assertThat(outVisible).isFalse()
+            assertThat(containerVisible).isTrue()
+
+            inJob.cancel()
+            outJob.cancel()
+            containerJob.cancel()
+        }
+
+    @Test
+    fun netTypeBackground_nullWhenNoPrioritizedCapabilities() =
+        testScope.runTest {
+            createAndSetViewModel()
+
+            val latest by collectLastValue(underTest.networkTypeBackground)
+
+            repository.hasPrioritizedNetworkCapabilities.value = false
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+    fun netTypeBackground_sliceUiEnabled_notNullWhenPrioritizedCapabilities_newIcons() =
+        testScope.runTest {
+            createAndSetViewModel()
+
+            val latest by collectLastValue(underTest.networkTypeBackground)
+
+            repository.hasPrioritizedNetworkCapabilities.value = true
+
+            assertThat(latest)
+                .isEqualTo(Icon.Resource(R.drawable.mobile_network_type_background_updated, null))
+        }
+
+    @Test
+    @DisableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+    fun netTypeBackground_sliceUiDisabled_notNullWhenPrioritizedCapabilities_oldIcons() =
+        testScope.runTest {
+            createAndSetViewModel()
+
+            val latest by collectLastValue(underTest.networkTypeBackground)
+
+            repository.hasPrioritizedNetworkCapabilities.value = true
+
+            assertThat(latest)
+                .isEqualTo(Icon.Resource(R.drawable.mobile_network_type_background, null))
+        }
+
+    @Test
+    fun nonTerrestrial_defaultProperties() =
+        testScope.runTest {
+            repository.isNonTerrestrial.value = true
+
+            val roaming by collectLastValue(underTest.roaming)
+            val networkTypeIcon by collectLastValue(underTest.networkTypeIcon)
+            val networkTypeBackground by collectLastValue(underTest.networkTypeBackground)
+            val activityInVisible by collectLastValue(underTest.activityInVisible)
+            val activityOutVisible by collectLastValue(underTest.activityOutVisible)
+            val activityContainerVisible by collectLastValue(underTest.activityContainerVisible)
+
+            assertThat(roaming).isFalse()
+            assertThat(networkTypeIcon).isNull()
+            assertThat(networkTypeBackground).isNull()
+            assertThat(activityInVisible).isFalse()
+            assertThat(activityOutVisible).isFalse()
+            assertThat(activityContainerVisible).isFalse()
+        }
+
+    @Test
+    fun nonTerrestrial_ignoresDefaultProperties() =
+        testScope.runTest {
+            repository.isNonTerrestrial.value = true
+
+            val roaming by collectLastValue(underTest.roaming)
+            val networkTypeIcon by collectLastValue(underTest.networkTypeIcon)
+            val networkTypeBackground by collectLastValue(underTest.networkTypeBackground)
+            val activityInVisible by collectLastValue(underTest.activityInVisible)
+            val activityOutVisible by collectLastValue(underTest.activityOutVisible)
+            val activityContainerVisible by collectLastValue(underTest.activityContainerVisible)
+
+            repository.setAllRoaming(true)
+            repository.setNetworkTypeKey(connectionsRepository.LTE_KEY)
+            // sets the background on cellular
+            repository.hasPrioritizedNetworkCapabilities.value = true
+            repository.dataActivityDirection.value =
+                DataActivityModel(hasActivityIn = true, hasActivityOut = true)
+
+            assertThat(roaming).isFalse()
+            assertThat(networkTypeIcon).isNull()
+            assertThat(networkTypeBackground).isNull()
+            assertThat(activityInVisible).isFalse()
+            assertThat(activityOutVisible).isFalse()
+            assertThat(activityContainerVisible).isFalse()
+        }
+
+    @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    fun nonTerrestrial_usesSatelliteIcon_flagOff() =
+        testScope.runTest {
+            repository.isNonTerrestrial.value = true
+            repository.setAllLevels(0)
+            repository.satelliteLevel.value = 0
+
+            val latest by
+                collectLastValue(underTest.icon.filterIsInstance(SignalIconModel.Satellite::class))
+
+            // Level 0 -> no connection
+            assertThat(latest).isNotNull()
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_0)
+
+            // 1-2 -> 1 bar
+            repository.setAllLevels(1)
+            repository.satelliteLevel.value = 1
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+            repository.setAllLevels(2)
+            repository.satelliteLevel.value = 2
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+            // 3-4 -> 2 bars
+            repository.setAllLevels(3)
+            repository.satelliteLevel.value = 3
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+
+            repository.setAllLevels(4)
+            repository.satelliteLevel.value = 4
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+        }
+
+    @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    fun nonTerrestrial_usesSatelliteIcon_flagOn() =
+        testScope.runTest {
+            repository.isNonTerrestrial.value = true
+            repository.satelliteLevel.value = 0
+
+            val latest by
+                collectLastValue(underTest.icon.filterIsInstance(SignalIconModel.Satellite::class))
+
+            // Level 0 -> no connection
+            assertThat(latest).isNotNull()
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_0)
+
+            // 1-2 -> 1 bar
+            repository.satelliteLevel.value = 1
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+            repository.satelliteLevel.value = 2
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+            // 3-4 -> 2 bars
+            repository.satelliteLevel.value = 3
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+
+            repository.satelliteLevel.value = 4
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+        }
+
+    @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    fun satelliteIcon_ignoresInflateSignalStrength_flagOff() =
+        testScope.runTest {
+            // Note that this is the exact same test as above, but with inflateSignalStrength set to
+            // true we note that the level is unaffected by inflation
+            repository.inflateSignalStrength.value = true
+            repository.isNonTerrestrial.value = true
+            repository.setAllLevels(0)
+            repository.satelliteLevel.value = 0
+
+            val latest by
+                collectLastValue(underTest.icon.filterIsInstance(SignalIconModel.Satellite::class))
+
+            // Level 0 -> no connection
+            assertThat(latest).isNotNull()
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_0)
+
+            // 1-2 -> 1 bar
+            repository.setAllLevels(1)
+            repository.satelliteLevel.value = 1
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+            repository.setAllLevels(2)
+            repository.satelliteLevel.value = 2
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+            // 3-4 -> 2 bars
+            repository.setAllLevels(3)
+            repository.satelliteLevel.value = 3
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+
+            repository.setAllLevels(4)
+            repository.satelliteLevel.value = 4
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+        }
+
+    @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    fun satelliteIcon_ignoresInflateSignalStrength_flagOn() =
+        testScope.runTest {
+            // Note that this is the exact same test as above, but with inflateSignalStrength set to
+            // true we note that the level is unaffected by inflation
+            repository.inflateSignalStrength.value = true
+            repository.isNonTerrestrial.value = true
+            repository.satelliteLevel.value = 0
+
+            val latest by
+                collectLastValue(underTest.icon.filterIsInstance(SignalIconModel.Satellite::class))
+
+            // Level 0 -> no connection
+            assertThat(latest).isNotNull()
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_0)
+
+            // 1-2 -> 1 bar
+            repository.satelliteLevel.value = 1
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+            repository.satelliteLevel.value = 2
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+            // 3-4 -> 2 bars
+            repository.satelliteLevel.value = 3
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+
+            repository.satelliteLevel.value = 4
+            assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+        }
+
+    private fun createAndSetViewModel() {
+        underTest =
+            MobileIconViewModelKairos(
+                SUB_1_ID,
+                interactor,
+                airplaneModeInteractor,
+                constants,
+                testScope.backgroundScope,
+            )
+    }
+
+    companion object {
+        private const val SUB_1_ID = 1
+
+        // For convenience, just define these as constants
+        private val NO_SIGNAL = R.string.accessibility_no_signal
+        private val ONE_BAR = R.string.accessibility_one_bar
+        private val TWO_BARS = R.string.accessibility_two_bars
+        private val THREE_BARS = R.string.accessibility_three_bars
+        private val FOUR_BARS = R.string.accessibility_four_bars
+        private val FULL_BARS = R.string.accessibility_signal_full
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelKairosTest.kt
new file mode 100644
index 0000000..e921430
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelKairosTest.kt
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.statusbar.phone.StatusBarLocation
+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
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+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
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileIconsViewModelKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private lateinit var underTest: MobileIconsViewModelKairos
+    private val interactor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+    private val flags = FakeFeatureFlagsClassic()
+
+    private lateinit var airplaneModeInteractor: AirplaneModeInteractor
+    @Mock private lateinit var constants: ConnectivityConstants
+    @Mock private lateinit var logger: MobileViewLogger
+    @Mock private lateinit var verboseLogger: VerboseMobileViewLogger
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        airplaneModeInteractor =
+            AirplaneModeInteractor(
+                FakeAirplaneModeRepository(),
+                FakeConnectivityRepository(),
+                kosmos.fakeMobileConnectionsRepository,
+            )
+
+        underTest =
+            MobileIconsViewModelKairos(
+                logger,
+                verboseLogger,
+                interactor,
+                airplaneModeInteractor,
+                constants,
+                testScope.backgroundScope,
+            )
+
+        interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+    }
+
+    @Test
+    fun subscriptionIdsFlow_matchesInteractor() =
+        testScope.runTest {
+            var latest: List<Int>? = null
+            val job = underTest.subscriptionIdsFlow.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value =
+                listOf(
+                    SubscriptionModel(
+                        subscriptionId = 1,
+                        isOpportunistic = false,
+                        carrierName = "Carrier 1",
+                        profileClass = PROFILE_CLASS_UNSET,
+                    )
+                )
+            assertThat(latest).isEqualTo(listOf(1))
+
+            interactor.filteredSubscriptions.value =
+                listOf(
+                    SubscriptionModel(
+                        subscriptionId = 2,
+                        isOpportunistic = false,
+                        carrierName = "Carrier 2",
+                        profileClass = PROFILE_CLASS_UNSET,
+                    ),
+                    SubscriptionModel(
+                        subscriptionId = 5,
+                        isOpportunistic = true,
+                        carrierName = "Carrier 5",
+                        profileClass = PROFILE_CLASS_UNSET,
+                    ),
+                    SubscriptionModel(
+                        subscriptionId = 7,
+                        isOpportunistic = true,
+                        carrierName = "Carrier 7",
+                        profileClass = PROFILE_CLASS_UNSET,
+                    ),
+                )
+            assertThat(latest).isEqualTo(listOf(2, 5, 7))
+
+            interactor.filteredSubscriptions.value = emptyList()
+            assertThat(latest).isEmpty()
+
+            job.cancel()
+        }
+
+    @Test
+    fun caching_mobileIconViewModelIsReusedForSameSubId() =
+        testScope.runTest {
+            val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME)
+            val model2 = underTest.viewModelForSub(1, StatusBarLocation.QS)
+
+            assertThat(model1.commonImpl).isSameInstanceAs(model2.commonImpl)
+        }
+
+    @Test
+    fun caching_invalidViewModelsAreRemovedFromCacheWhenSubDisappears() =
+        testScope.runTest {
+            // Retrieve models to trigger caching
+            val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME)
+            val model2 = underTest.viewModelForSub(2, StatusBarLocation.QS)
+
+            // Both impls are cached
+            assertThat(underTest.reuseCache.keys).containsExactly(1, 2)
+
+            // SUB_1 is removed from the list...
+            interactor.filteredSubscriptions.value = listOf(SUB_2)
+
+            // ... and dropped from the cache
+            assertThat(underTest.reuseCache.keys).containsExactly(2)
+        }
+
+    @Test
+    fun caching_invalidatedViewModelsAreCanceled() =
+        testScope.runTest {
+            // Retrieve models to trigger caching
+            val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME)
+            val model2 = underTest.viewModelForSub(2, StatusBarLocation.QS)
+
+            var scope1 = underTest.reuseCache[1]?.second
+            var scope2 = underTest.reuseCache[2]?.second
+
+            // Scopes are not canceled
+            assertTrue(scope1!!.isActive)
+            assertTrue(scope2!!.isActive)
+
+            // SUB_1 is removed from the list...
+            interactor.filteredSubscriptions.value = listOf(SUB_2)
+
+            // scope1 is canceled
+            assertFalse(scope1!!.isActive)
+            assertTrue(scope2!!.isActive)
+        }
+
+    @Test
+    fun firstMobileSubShowingNetworkTypeIcon_noSubs_false() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job =
+                underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value = emptyList()
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun firstMobileSubShowingNetworkTypeIcon_oneSub_notShowingRat_false() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job =
+                underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value = listOf(SUB_1)
+            // The unknown icon group doesn't show a RAT
+            interactor.getInteractorForSubId(1)!!.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun firstMobileSubShowingNetworkTypeIcon_oneSub_showingRat_true() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job =
+                underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value = listOf(SUB_1)
+            // The 3G icon group will show a RAT
+            interactor.getInteractorForSubId(1)!!.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun firstMobileSubShowingNetworkTypeIcon_updatesAsSubUpdates() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job =
+                underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value = listOf(SUB_1)
+            val sub1Interactor = interactor.getInteractorForSubId(1)!!
+
+            sub1Interactor.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+            assertThat(latest).isTrue()
+
+            sub1Interactor.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+            assertThat(latest).isFalse()
+
+            sub1Interactor.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.LTE)
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun firstMobileSubShowingNetworkTypeIcon_multipleSubs_lastSubNotShowingRat_false() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job =
+                underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+            interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+            interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun firstMobileSubShowingNetworkTypeIcon_multipleSubs_lastSubShowingRat_true() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job =
+                underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+            interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+            interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+
+            assertThat(latest).isTrue()
+            job.cancel()
+        }
+
+    @Test
+    fun firstMobileSubShowingNetworkTypeIcon_subListUpdates_valAlsoUpdates() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job =
+                underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+            interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+            interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+
+            assertThat(latest).isTrue()
+
+            // WHEN the sub list gets new subscriptions where the last subscription is not showing
+            // the network type icon
+            interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2, SUB_3)
+            interactor.getInteractorForSubId(3)!!.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+
+            // THEN the flow updates
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun firstMobileSubShowingNetworkTypeIcon_subListReorders_valAlsoUpdates() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job =
+                underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+            interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+            // Immediately switch the order so that we've created both interactors
+            interactor.filteredSubscriptions.value = listOf(SUB_2, SUB_1)
+            val sub1Interactor = interactor.getInteractorForSubId(1)!!
+            val sub2Interactor = interactor.getInteractorForSubId(2)!!
+
+            interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+            sub1Interactor.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+            sub2Interactor.networkTypeIconGroup.value =
+                NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+            assertThat(latest).isTrue()
+
+            // WHEN sub1 becomes last and sub1 has no network type icon
+            interactor.filteredSubscriptions.value = listOf(SUB_2, SUB_1)
+
+            // THEN the flow updates
+            assertThat(latest).isFalse()
+
+            // WHEN sub2 becomes last and sub2 has a network type icon
+            interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+
+            // THEN the flow updates
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    companion object {
+        private val SUB_1 =
+            SubscriptionModel(
+                subscriptionId = 1,
+                isOpportunistic = false,
+                carrierName = "Carrier 1",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        private val SUB_2 =
+            SubscriptionModel(
+                subscriptionId = 2,
+                isOpportunistic = false,
+                carrierName = "Carrier 2",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        private val SUB_3 =
+            SubscriptionModel(
+                subscriptionId = 3,
+                isOpportunistic = false,
+                carrierName = "Carrier 3",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairosTest.kt
new file mode 100644
index 0000000..ce35d9d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairosTest.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.pipeline.mobile.ui.viewmodel
+
+import android.platform.test.annotations.EnableFlags
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.statusbar.core.NewStatusBarIcons
+import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class StackedMobileIconViewModelKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val testScope = kosmos.testScope
+
+    private val Kosmos.underTest: StackedMobileIconViewModelKairos by Fixture {
+        stackedMobileIconViewModelKairos
+    }
+
+    @Before
+    fun setUp() {
+        kosmos.underTest.activateIn(testScope)
+    }
+
+    @Test
+    @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+    fun dualSim_filtersOutNonDualConnections() =
+        kosmos.runTest {
+            fakeMobileIconsInteractor.filteredSubscriptions.value = listOf()
+            assertThat(underTest.dualSim).isNull()
+
+            fakeMobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1)
+            assertThat(underTest.dualSim).isNull()
+
+            fakeMobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1, SUB_2, SUB_3)
+            assertThat(underTest.dualSim).isNull()
+
+            fakeMobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+            assertThat(underTest.dualSim).isNotNull()
+        }
+
+    @Test
+    @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+    fun dualSim_filtersOutNonCellularIcons() =
+        kosmos.runTest {
+            fakeMobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1)
+            assertThat(underTest.dualSim).isNull()
+
+            fakeMobileIconsInteractor
+                .getInteractorForSubId(SUB_1.subscriptionId)!!
+                .signalLevelIcon
+                .value =
+                SignalIconModel.Satellite(
+                    level = 0,
+                    icon = Icon.Resource(res = 0, contentDescription = null),
+                )
+            fakeMobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+            assertThat(underTest.dualSim).isNull()
+        }
+
+    @Test
+    @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+    fun dualSim_tracksActiveSubId() =
+        kosmos.runTest {
+            // Active sub id is null, order is unchanged
+            fakeMobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+            setIconLevel(SUB_1.subscriptionId, 1)
+            setIconLevel(SUB_2.subscriptionId, 2)
+
+            assertThat(underTest.dualSim!!.primary.level).isEqualTo(1)
+            assertThat(underTest.dualSim!!.secondary.level).isEqualTo(2)
+
+            // Active sub is 2, order is swapped
+            fakeMobileIconsInteractor.activeMobileDataSubscriptionId.value = SUB_2.subscriptionId
+
+            assertThat(underTest.dualSim!!.primary.level).isEqualTo(2)
+            assertThat(underTest.dualSim!!.secondary.level).isEqualTo(1)
+        }
+
+    private fun setIconLevel(subId: Int, level: Int) {
+        with(kosmos.fakeMobileIconsInteractor.getInteractorForSubId(subId)!!) {
+            signalLevelIcon.value =
+                (signalLevelIcon.value as SignalIconModel.Cellular).copy(level = level)
+        }
+    }
+
+    companion object {
+        private val SUB_1 =
+            SubscriptionModel(
+                subscriptionId = 1,
+                isOpportunistic = false,
+                carrierName = "Carrier 1",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        private val SUB_2 =
+            SubscriptionModel(
+                subscriptionId = 2,
+                isOpportunistic = false,
+                carrierName = "Carrier 2",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        private val SUB_3 =
+            SubscriptionModel(
+                subscriptionId = 3,
+                isOpportunistic = false,
+                carrierName = "Carrier 3",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
index a083e59..91b3896 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
@@ -66,7 +66,7 @@
     override val mediaProjectionStopDialogDueToCallEndedState =
         MutableStateFlow(MediaProjectionStopDialogModel.Hidden)
 
-    override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)
+    override val isHomeStatusBarAllowed = MutableStateFlow(false)
 
     override val canShowOngoingActivityChips: Flow<Boolean> = MutableStateFlow(false)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
index 27aa4ba..12cf3b6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
@@ -30,6 +30,7 @@
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.display.data.repository.fake
@@ -57,6 +58,7 @@
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.screenrecord.data.model.ScreenRecordModel
 import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
 import com.android.systemui.shade.shadeTestUtil
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
@@ -97,7 +99,6 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.runCurrent
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -502,9 +503,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneLockscreen_notOccluded_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneLockscreen_notOccluded_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
             kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, taskInfo = null)
@@ -513,9 +515,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneLockscreen_occluded_true() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneLockscreen_occluded_true() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
             kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, taskInfo = null)
@@ -524,9 +527,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_overlayBouncer_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_overlayBouncer_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
             kosmos.sceneContainerRepository.showOverlay(Overlays.Bouncer)
@@ -535,9 +539,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneCommunal_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneCommunal_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Communal)
 
@@ -545,9 +550,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneShade_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneShade_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Shade)
 
@@ -555,9 +561,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneGone_true() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneGone_true() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
 
@@ -565,9 +572,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneGoneWithNotificationsShadeOverlay_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneGoneWithNotificationsShadeOverlay_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
             kosmos.sceneContainerRepository.showOverlay(Overlays.NotificationsShade)
@@ -577,12 +585,102 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneGoneWithQuickSettingsShadeOverlay_false() =
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_QsVisibleButInExternalDisplay_defaultStatusBarVisible() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
             kosmos.sceneContainerRepository.showOverlay(Overlays.QuickSettingsShade)
+            kosmos.fakeShadeDisplaysRepository.setDisplayId(EXTERNAL_DISPLAY)
+            runCurrent()
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_QsVisibleButInExternalDisplay_withFlagOff_defaultStatusBarInvisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+            kosmos.sceneContainerRepository.showOverlay(Overlays.QuickSettingsShade)
+            kosmos.fakeShadeDisplaysRepository.setDisplayId(EXTERNAL_DISPLAY)
+            runCurrent()
+
+            // Shade position is ignored.
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_qsVisibleInThisDisplay_thisStatusBarInvisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+            kosmos.sceneContainerRepository.showOverlay(Overlays.QuickSettingsShade)
+            kosmos.fakeShadeDisplaysRepository.setDisplayId(DEFAULT_DISPLAY)
+            runCurrent()
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_qsExpandedOnDefaultDisplay_statusBarInAnotherDisplay_visible() =
+        kosmos.runTest {
+            val underTest = homeStatusBarViewModelFactory(EXTERNAL_DISPLAY)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+            kosmos.sceneContainerRepository.showOverlay(Overlays.QuickSettingsShade)
+            runCurrent()
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_onDefaultDisplayLockscreen_invisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+            runCurrent()
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableSceneContainer
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    fun isHomeStatusBarAllowed_onExternalDispalyWithLocksceren_invisible() =
+        kosmos.runTest {
+            val underTest = homeStatusBarViewModelFactory(EXTERNAL_DISPLAY)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+            runCurrent()
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @DisableSceneContainer
+    fun isHomeStatusBarAllowed_legacy_onDefaultDisplayLockscreen_invisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.fakeKeyguardTransitionRepository.transitionTo(
+                KeyguardState.GONE,
+                KeyguardState.LOCKSCREEN,
+            )
+
             runCurrent()
 
             assertThat(latest).isFalse()
@@ -920,7 +1018,7 @@
             addOngoingCallState(key = "call")
 
             assertIsScreenRecordChip(latest!!.chips.active[0])
-            assertIsCallChip(latest!!.chips.active[1], "call")
+            assertIsCallChip(latest!!.chips.active[1], "call", context)
         }
 
     @Test
@@ -1560,4 +1658,8 @@
             testScope = testScope,
         )
     }
+
+    private companion object {
+        const val EXTERNAL_DISPLAY = 1
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt
index fdfcdc4..9a58365 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt
@@ -16,14 +16,13 @@
 
 package com.android.systemui.util.wakelock
 
-import android.os.Build
 import android.os.PowerManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.assertLogsWtf
 import org.junit.After
 import org.junit.Assert
-import org.junit.Assume
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -82,12 +81,11 @@
 
     @Test
     fun wakeLock_releasedTooManyTimes_stillReleased_noThrow() {
-        Assume.assumeFalse(Build.IS_ENG)
         mWakeLock.acquire(WHY)
         mWakeLock.acquire(WHY_2)
         mWakeLock.release(WHY)
         mWakeLock.release(WHY_2)
-        mWakeLock.release(WHY)
+        assertLogsWtf { mWakeLock.release(WHY) }
         Assert.assertFalse(mInner.isHeld)
     }
 
@@ -104,9 +102,8 @@
 
     @Test
     fun prodBuild_wakeLock_releaseWithoutAcquire_noThrow() {
-        Assume.assumeFalse(Build.IS_ENG)
         // shouldn't throw an exception on production builds
-        mWakeLock.release(WHY)
+        assertLogsWtf { mWakeLock.release(WHY) }
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/WakeLockTest.java
index 90aecfb..3951670 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/WakeLockTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/WakeLockTest.java
@@ -19,16 +19,15 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.os.Build;
 import android.os.PowerManager;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.log.LogAssertKt;
 
 import org.junit.After;
-import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -93,8 +92,7 @@
 
     @Test
     public void prodBuild_wakeLock_releaseWithoutAcquire_noThrow() {
-        Assume.assumeFalse(Build.IS_ENG);
         // shouldn't throw an exception on production builds
-        mWakeLock.release(WHY);
+        LogAssertKt.assertRunnableLogsWtf(() -> mWakeLock.release(WHY));
     }
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
index 4c1f645..b52db83 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
@@ -42,9 +42,13 @@
         isDarkTheme: Boolean,
         dozeFraction: Float,
         foldFraction: Float,
-        onBoundsChanged: (RectF) -> Unit,
+        clockListener: ClockEventListener?,
     )
 
     /** Optional method for dumping debug information */
     fun dump(pw: PrintWriter)
 }
+
+interface ClockEventListener {
+    fun onBoundsChanged(bounds: RectF)
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt
index 029e546..20ee6c1 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceEvents.kt
@@ -13,6 +13,7 @@
  */
 package com.android.systemui.plugins.clocks
 
+import android.content.Context
 import android.graphics.Rect
 import com.android.systemui.plugins.annotations.ProtectedInterface
 
@@ -60,4 +61,12 @@
      * value denotes that we should use the seed color for the current system theme.
      */
     val seedColor: Int?,
-)
+) {
+    fun getDefaultColor(context: Context): Int {
+        return when {
+            seedColor != null -> seedColor!!
+            isDarkTheme -> context.resources.getColor(android.R.color.system_accent1_100)
+            else -> context.resources.getColor(android.R.color.system_accent2_600)
+        }
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/WeatherData.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/WeatherData.kt
index f920b18..f59dda0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/WeatherData.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/WeatherData.kt
@@ -24,6 +24,8 @@
         @VisibleForTesting const val TEMPERATURE_KEY = "temperature"
         private const val INVALID_WEATHER_ICON_STATE = -1
 
+        @JvmStatic
+        @JvmOverloads
         fun fromBundle(extras: Bundle, touchAction: WeatherTouchAction? = null): WeatherData? {
             val description = extras.getString(DESCRIPTION_KEY)
             val state =
@@ -46,7 +48,7 @@
                         state = state,
                         useCelsius = extras.getBoolean(USE_CELSIUS_KEY),
                         temperature = temperature,
-                        touchAction = touchAction
+                        touchAction = touchAction,
                     )
                 if (DEBUG) {
                     Log.i(TAG, "Weather data parsed $result from $extras")
@@ -87,53 +89,53 @@
     }
 
     // Values for WeatherStateIcon must stay in sync with go/g3-WeatherStateIcon
-    enum class WeatherStateIcon(val id: Int) {
-        UNKNOWN_ICON(0),
+    enum class WeatherStateIcon(val id: Int, val icon: String) {
+        UNKNOWN_ICON(0, ""),
 
         // Clear, day & night.
-        SUNNY(1),
-        CLEAR_NIGHT(2),
+        SUNNY(1, "a"),
+        CLEAR_NIGHT(2, "f"),
 
         // Mostly clear, day & night.
-        MOSTLY_SUNNY(3),
-        MOSTLY_CLEAR_NIGHT(4),
+        MOSTLY_SUNNY(3, "b"),
+        MOSTLY_CLEAR_NIGHT(4, "n"),
 
         // Partly cloudy, day & night.
-        PARTLY_CLOUDY(5),
-        PARTLY_CLOUDY_NIGHT(6),
+        PARTLY_CLOUDY(5, "b"),
+        PARTLY_CLOUDY_NIGHT(6, "n"),
 
         // Mostly cloudy, day & night.
-        MOSTLY_CLOUDY_DAY(7),
-        MOSTLY_CLOUDY_NIGHT(8),
-        CLOUDY(9),
-        HAZE_FOG_DUST_SMOKE(10),
-        DRIZZLE(11),
-        HEAVY_RAIN(12),
-        SHOWERS_RAIN(13),
+        MOSTLY_CLOUDY_DAY(7, "e"),
+        MOSTLY_CLOUDY_NIGHT(8, "e"),
+        CLOUDY(9, "e"),
+        HAZE_FOG_DUST_SMOKE(10, "d"),
+        DRIZZLE(11, "c"),
+        HEAVY_RAIN(12, "c"),
+        SHOWERS_RAIN(13, "c"),
 
         // Scattered showers, day & night.
-        SCATTERED_SHOWERS_DAY(14),
-        SCATTERED_SHOWERS_NIGHT(15),
+        SCATTERED_SHOWERS_DAY(14, "c"),
+        SCATTERED_SHOWERS_NIGHT(15, "c"),
 
         // Isolated scattered thunderstorms, day & night.
-        ISOLATED_SCATTERED_TSTORMS_DAY(16),
-        ISOLATED_SCATTERED_TSTORMS_NIGHT(17),
-        STRONG_TSTORMS(18),
-        BLIZZARD(19),
-        BLOWING_SNOW(20),
-        FLURRIES(21),
-        HEAVY_SNOW(22),
+        ISOLATED_SCATTERED_TSTORMS_DAY(16, "i"),
+        ISOLATED_SCATTERED_TSTORMS_NIGHT(17, "i"),
+        STRONG_TSTORMS(18, "i"),
+        BLIZZARD(19, "j"),
+        BLOWING_SNOW(20, "j"),
+        FLURRIES(21, "h"),
+        HEAVY_SNOW(22, "j"),
 
         // Scattered snow showers, day & night.
-        SCATTERED_SNOW_SHOWERS_DAY(23),
-        SCATTERED_SNOW_SHOWERS_NIGHT(24),
-        SNOW_SHOWERS_SNOW(25),
-        MIXED_RAIN_HAIL_RAIN_SLEET(26),
-        SLEET_HAIL(27),
-        TORNADO(28),
-        TROPICAL_STORM_HURRICANE(29),
-        WINDY_BREEZY(30),
-        WINTRY_MIX_RAIN_SNOW(31);
+        SCATTERED_SNOW_SHOWERS_DAY(23, "h"),
+        SCATTERED_SNOW_SHOWERS_NIGHT(24, "h"),
+        SNOW_SHOWERS_SNOW(25, "g"),
+        MIXED_RAIN_HAIL_RAIN_SLEET(26, "h"),
+        SLEET_HAIL(27, "h"),
+        TORNADO(28, "l"),
+        TROPICAL_STORM_HURRICANE(29, "m"),
+        WINDY_BREEZY(30, "k"),
+        WINTRY_MIX_RAIN_SNOW(31, "h");
 
         companion object {
             fun fromInt(value: Int) = values().firstOrNull { it.id == value }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
similarity index 87%
rename from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
rename to packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
index 3e39ae9..0c46e07 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
+++ b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
@@ -18,4 +18,7 @@
 import javax.inject.Qualifier
 
 /** Annotates a class that is display specific. */
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class DisplaySpecific
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+public annotation class DisplaySpecific
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Main.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Main.java
similarity index 100%
rename from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Main.java
rename to packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Main.java
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/UiBackground.java
similarity index 100%
rename from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java
rename to packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/UiBackground.java
diff --git a/packages/SystemUI/res/layout/magic_action_button.xml b/packages/SystemUI/res/layout/magic_action_button.xml
index 381d6b1..63fc1e4 100644
--- a/packages/SystemUI/res/layout/magic_action_button.xml
+++ b/packages/SystemUI/res/layout/magic_action_button.xml
@@ -6,7 +6,7 @@
     android:background="@drawable/magic_action_button_background"
     android:drawablePadding="@dimen/magic_action_button_drawable_padding"
     android:ellipsize="none"
-    android:fontFamily="google-sans-flex"
+    android:fontFamily="google-sans-flex-medium"
     android:gravity="center"
     android:minWidth="0dp"
     android:paddingHorizontal="@dimen/magic_action_button_padding_horizontal"
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 6f8b4cd..9b629ac 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -15,8 +15,8 @@
   ~ limitations under the License.
   -->
 
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/media_output_dialog"
     android:layout_width="@dimen/large_dialog_width"
     android:layout_height="wrap_content"
@@ -35,24 +35,25 @@
         android:orientation="horizontal">
         <ImageView
             android:id="@+id/header_icon"
-            android:layout_width="72dp"
-            android:layout_height="72dp"
+            android:layout_width="@dimen/media_output_dialog_header_album_icon_size"
+            android:layout_height="@dimen/media_output_dialog_header_album_icon_size"
+            android:layout_marginEnd="@dimen/media_output_dialog_header_icon_padding"
             android:importantForAccessibility="no"/>
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingStart="12dp"
             android:orientation="vertical">
             <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:gravity="center_vertical"
+                android:gravity="top"
                 android:orientation="horizontal">
                 <ImageView
                     android:id="@+id/app_source_icon"
                     android:layout_width="20dp"
                     android:layout_height="20dp"
+                    android:layout_marginBottom="7dp"
                     android:gravity="center_vertical"
                     android:importantForAccessibility="no"/>
 
@@ -103,12 +104,11 @@
         android:layout_height="wrap_content" >
     </ViewStub>
 
-    <LinearLayout
+    <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/device_list"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:orientation="vertical">
+        android:layout_height="0dp"
+        android:layout_weight="1">
 
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/list_result"
@@ -116,8 +116,11 @@
             android:paddingTop="8dp"
             android:clipToPadding="false"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-    </LinearLayout>
+            android:layout_height="wrap_content"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintHeight_max="@dimen/media_output_dialog_list_max_height"/>
+    </androidx.constraintlayout.widget.ConstraintLayout>
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/notif_half_shelf.xml b/packages/SystemUI/res/layout/notif_half_shelf.xml
index 9a66ca9..603cc00 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf.xml
@@ -71,15 +71,18 @@
                     android:textSize="16sp"
                 />
 
-                <Switch
-                    android:id="@+id/toggle"
+                <com.google.android.material.materialswitch.MaterialSwitch
+                    android:theme="@style/Theme.Material3.DynamicColors.DayNight"
+                    android:id="@+id/material_toggle"
+                    android:filterTouchesWhenObscured="false"
+                    android:clickable="true"
+                    android:focusable="true"
+                    android:padding="8dp"
                     android:layout_height="48dp"
                     android:layout_width="wrap_content"
                     android:layout_gravity="center_vertical"
-                    android:padding="8dp"
-                    android:track="@drawable/settingslib_track_selector"
-                    android:thumb="@drawable/settingslib_thumb_selector"
-                    android:theme="@style/MainSwitch.Settingslib"/>
+                    style="@style/SettingslibSwitchStyle.Expressive"/>
+
             </com.android.systemui.statusbar.notification.row.AppControlView>
 
             <ScrollView
diff --git a/packages/SystemUI/res/layout/notif_half_shelf_row.xml b/packages/SystemUI/res/layout/notif_half_shelf_row.xml
index b2eaa6c..4bc37f8 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf_row.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf_row.xml
@@ -80,15 +80,16 @@
             />
         </RelativeLayout>
 
-        <Switch
-            android:id="@+id/toggle"
+        <com.google.android.material.materialswitch.MaterialSwitch
+            android:theme="@style/Theme.Material3.DynamicColors.DayNight"
+            android:id="@+id/material_toggle"
+            android:filterTouchesWhenObscured="false"
+            android:clickable="true"
+            android:focusable="true"
+            android:padding="8dp"
             android:layout_height="48dp"
             android:layout_width="wrap_content"
             android:layout_gravity="center_vertical"
-            android:padding="8dp"
-            android:track="@drawable/settingslib_track_selector"
-            android:thumb="@drawable/settingslib_thumb_selector"
-            android:theme="@style/MainSwitch.Settingslib"
-        />
+            style="@style/SettingslibSwitchStyle.Expressive"/>
     </LinearLayout>
 </com.android.systemui.statusbar.notification.row.ChannelRow>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index f41eaec..a1fa54c 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -40,7 +40,7 @@
         android:layout_marginBottom="@dimen/volume_dialog_components_spacing"
         android:clipChildren="false"
         app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container"
-        app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintEnd_toEndOf="@id/volume_dialog_background"
         app:layout_constraintHeight_default="spread"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
@@ -70,9 +70,9 @@
         android:layout_marginTop="@dimen/volume_dialog_components_spacing"
         android:clipChildren="false"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintEnd_toEndOf="@id/volume_dialog_background"
         app:layout_constraintHeight_default="wrap"
-        app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintStart_toStartOf="@id/volume_dialog_background"
         app:layout_constraintTop_toBottomOf="@id/volume_dialog_main_slider_container"
         app:layout_constraintVertical_bias="0"
         app:layout_constraintWidth_default="wrap">
diff --git a/packages/SystemUI/res/layout/volume_dialog_top_section.xml b/packages/SystemUI/res/layout/volume_dialog_top_section.xml
index 29f5248..b745547 100644
--- a/packages/SystemUI/res/layout/volume_dialog_top_section.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_top_section.xml
@@ -22,7 +22,7 @@
     android:clipChildren="false"
     android:clipToPadding="false"
     android:gravity="center"
-    android:paddingEnd="@dimen/volume_dialog_ringer_drawer_diff_end_margin"
+    android:paddingEnd="@dimen/volume_dialog_buttons_margin"
     app:layoutDescription="@xml/volume_dialog_ringer_drawer_motion_scene">
 
     <View
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 4179d8a..cbec8c2 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Gekoppel aan <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Gekoppel aan <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Vou groep uit."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Voeg toestel by groep."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Verwyder toestel uit groep."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Maak app oop."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nie gekoppel nie."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Swerwing"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Gehoortoestelle"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Skakel tans aan …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Kan nie helderheid verstel nie omdat dit deur die boonste app beheer word"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Outodraai"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Outodraai skerm"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ligging"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Voeg by posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisie is ongeldig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Teël is bygevoeg"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Teël is verwyder"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kitsinstellingswysiger."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Onbekend"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Stel alle teëls terug?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle Kitsinstellingsteëls sal na die toestel se oorspronklike instellings teruggestel word"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index a92a141..655f060 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ከ<xliff:g id="BLUETOOTH">%s</xliff:g> ጋር ተገናኝቷል።"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"ከ<xliff:g id="CAST">%s</xliff:g> ጋር ተገናኝቷል።"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ቡድንን ዘርጋ።"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"መሣሪያን ወደ ቡድን አክል።"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"መሣሪያን ከቡድን ላይ አስወግድ።"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"መተግበሪያ ክፈት።"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"አልተገናኘም።"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"በማዛወር ላይ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ግቤት"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"መስሚያ አጋዥ መሣሪያዎች"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"በማብራት ላይ..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ከላይ ባለው መተግበሪያ ቁጥጥር እየተደረገበት ስለሆነ ብሩህነትን ማስተካከል አልተቻለም"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"በራስ ሰር አሽከርክር"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ማያ ገጽን በራስ-አሽከርክር"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"አካባቢ"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ወደ <xliff:g id="POSITION">%1$d</xliff:g> ቦታ አክል"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"አቀማመጡ ተቀባይነት የለውም።"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"የ<xliff:g id="POSITION">%1$d</xliff:g> አቀማመጥ"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ሰቅ ታክሏል"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ሰቅ ተወግዷል"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"የፈጣን ቅንብሮች አርታዒ።"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ያልታወቀ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ሁሉም ሰቆች ዳግም ይጀምሩ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ሁሉም የፈጣን ቅንብሮች ሰቆች ወደ የመሣሪያው የመጀመሪያ ቅንብሮች ዳግም ይጀምራሉ"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>፣ <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 13f3fd8..b2d71da 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"متصل بـ <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"تم الاتصال بـ <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"سيتم توسيع المجموعة."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"إضافة الجهاز إلى المجموعة"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"إزالة الجهاز من المجموعة"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"سيتم فتح التطبيق."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"غير متصل."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"التجوال"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"الإدخال"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سماعات الأذن الطبية"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"جارٍ التفعيل…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"لا يمكن ضبط مستوى السطوع لأنّ التطبيق العلوي يتحكّم فيه"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"التدوير التلقائي"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"التدوير التلقائي للشاشة"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"الإضافة إلى الموضع <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"الموضِع غير صالح."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"الموضع: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"تمت إضافة البطاقة."</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"تمت إزالة البطاقة."</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"برنامج تعديل الإعدادات السريعة."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 067649c..6aa9d66 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>ৰ লগত সংযোগ কৰা হ’ল।"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>ত সংযোগ হ’ল।"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"গোট বিস্তাৰ কৰক।"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"গোটত ডিভাইচ যোগ দিয়ক।"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"গোটৰ পৰা ডিভাইচ আঁতৰাওক।"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"এপ্লিকেশ্বনটো খোলক।"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"সংযোগ হৈ থকা নাই।"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ৰ\'মিং"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"শ্ৰৱণ যন্ত্ৰ"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"অন কৰি থকা হৈছে…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"উজ্জ্বলতা মিলাব নোৱাৰি কাৰণ সেয়া শীৰ্ষৰ এপটোৱে নিয়ন্ত্ৰণ কৰি আছে"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"স্বয়ং-ঘূৰ্ণন"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"অৱস্থান"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থানত যোগ দিয়ক"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"স্থান অমান্য।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থান"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"টাইল যোগ দিয়া হৈছে"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"টাইল আঁতৰোৱা হৈছে"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ক্ষিপ্ৰ ছেটিঙৰ সম্পাদক।"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"অজ্ঞাত"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"আটাইবোৰ টাইল ৰিছেট কৰিবনে?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"আটাইবোৰ ক্ষিপ্ৰ ছেটিঙৰ টাইল ডিভাইচৰ মূল ছেটিংছলৈ ৰিছেট হ’ব"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 9df9923..b87432f 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> üzərindən qoşuldu."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> cihazına qoşulub."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Qrupu genişləndirin."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Qrupa cihaz əlavə edin."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Cihazı qrupdan silin."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Tətbiqi açın."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Qoşulu deyil."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Rouminq"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Eşitmə aparatları"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiv edilir..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Yuxarıdakı tətbiq tərəfindən idarə olunduğu üçün parlaqlığı tənzimləmək mümkün deyil"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avtodönüş"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranın avtomatik dönməsi"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Məkan"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyinə əlavə edin"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Mövqe yanlışdır."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Mozaik əlavə edilib"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Mozaik silinib"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sürətli ayarlar redaktoru."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Naməlum"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Bütün mozaiklər sıfırlansın?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Bütün Sürətli Ayarlar mozaiki cihazın orijinal ayarlarına sıfırlanacaq"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 6ab7bf1..a875e73 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajte na <xliff:g id="POSITION">%1$d</xliff:g>. poziciju"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozicija je nevažeća."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Pločica je dodata"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Pločica je uklonjena"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivač za Brza podešavanja."</string>
@@ -1571,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite da resetujete sve pločice?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve pločice Brzih podešavanja će se resetovati na prvobitna podešavanja uređaja"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 94f9507..75d0a44 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Падлучаны да <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ёсць падключэнне да <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Разгарнуць групу."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Дадаць прыладу ў групу."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Выдаліць прыладу з групы."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Адкрыць праграму."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Няма падключэння."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роўмінг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Увод"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слыхавыя апараты"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Уключэнне…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Не ўдаецца адрэгуляваць яркасць, бо яна кантралюецца верхняй праграмай"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аўтапаварот"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аўтаматычны паварот экрана"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Месцазнаходжанне"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Дадаць на пазіцыю <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Няправільнае месца."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Пазіцыя <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Плітка дададзена"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Плітка выдалена"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Рэдактар хуткіх налад."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 4615e60..4f3d641 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Има връзка с <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Установена е връзка с/ъс <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Разгъване на групата."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Добавяне на устройството към групата."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Премахване на устройството от групата."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Отваряне на приложението."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Няма връзка."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Вход"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слухови апарати"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Включва се..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Яркостта не може да се коригира, защото се контролира от приложението на екрана"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авт. ориентация"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично завъртане на екрана"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Местоположение"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавяне към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Невалидна позиция."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Панелът е добавен"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Панелът е премахнат"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор за бързи настройки."</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 6247bf1..3fd699db 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>এ সংযুক্ত হয়ে আছে।"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> এর সাথে সংযুক্ত৷"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"গ্রুপ বড় করুন।"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"গ্রুপে ডিভাইস যোগ করুন।"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"গ্রুপ থেকে ডিভাইস সরিয়ে দিন।"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"অ্যাপ্লিকেশন খুলুন।"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"সংযুক্ত নয়৷"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"রোমিং"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"হিয়ারিং এড"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"চালু করা হচ্ছে…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"উজ্জ্বলতা অ্যাডজাস্ট করা যাচ্ছে না কারণ এটি সেরা অ্যাপের মাধ্যমে কন্ট্রোল করা হচ্ছে"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"নিজে থেকে ঘুরবে"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"অটো-রোটেট স্ক্রিন"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"লোকেশন"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"অবস্থান <xliff:g id="POSITION">%1$d</xliff:g>-এ যোগ করুন"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"পজিশন সঠিক নয়।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"অবস্থান <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"টাইল যোগ করা হয়েছে"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"টাইল সরানো হয়েছে"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"দ্রুত সেটিংস সম্পাদক৷"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"অজানা"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"সব টাইল রিসেট করবেন?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"সব কুইক সেটিংস টাইল, ডিভাইসের আসল সেটিংসে রিসেট হয়ে যাবে"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 75f3f08..0b5af17 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Povezan na <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Proširivanje grupe."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodavanje uređaja u grupu."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Uklanjanje uređaja iz grupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otvaranje aplikacije."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nije povezano."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ulaz"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nije moguće podesiti osvijetljenost jer njome upravlja gornja aplikacija"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko rotiranje"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje u položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nevažeći položaj."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartica je dodana"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartica je uklonjena"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivanje brzih postavki"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vratiti sve kartice na zadano?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve kartice Brze postavke će se vratiti na originalne postavke uređaja"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 19b299f..0225d2b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"S\'ha connectat a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Està connectat amb <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Desplega el grup."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Afegeix el dispositiu al grup."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Suprimeix el dispositiu del grup."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Obre l\'aplicació."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Sense connexió."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Itinerància"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audiòfons"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"S\'està activant…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"No es pot ajustar la brillantor perquè està controlada per l\'aplicació superior"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Gira automàticament"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Gira la pantalla automàticament"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicació"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Afegeix a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"La posició no és vàlida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"El mosaic s\'ha afegit"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"El mosaic s\'ha suprimit"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configuració ràpida."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconegut"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vols restablir totes les icones?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Totes les icones de configuració ràpida es restabliran a les opcions originals del dispositiu"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 51dfa2e..8a6980e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Připojeno k zařízení <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Jste připojeni k zařízení <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Rozbalit skupinu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Přidat zařízení do skupiny."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Odstranit zařízení ze skupiny."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otevřít aplikaci."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nepřipojeno."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Naslouchátka"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapínání…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Jas nelze upravit, protože ho řídí hlavní aplikace"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. otáčení"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčení obrazovky"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Přidat dlaždici na pozici <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozice není platná."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Dlaždice byla přidána"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Dlaždice byla odstraněna"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor rychlého nastavení"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznámé"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Resetovat všechny dlaždice?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Všechny dlaždice Rychlého nastavení se resetují do původní konfigurace zařízení"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ad6633e..60c5c1c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Forbundet med <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Forbundet til <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Udvid gruppe."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Føj enhed til gruppe."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Fjern enhed fra gruppe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Åbn app."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ikke tilsluttet."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Høreapparater"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverer…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Lysstyrken kan ikke justeres, fordi den styres af den øverste app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Roter automatisk"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Roter skærmen automatisk"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokation"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Føj til lokation <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positionen er ugyldig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Lokation <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Feltet blev tilføjet"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Feltet blev fjernet"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsværktøj til Kvikmenu."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ukendt"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vil du nulstille alle handlingsfelter?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle handlingsfelter i kvikmenuen nulstilles til enhedens oprindelige indstillinger"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 8bc3815..66b60b1 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Mit <xliff:g id="BLUETOOTH">%s</xliff:g> verbunden"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Verbunden mit <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Gruppe erweitern."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Gerät zu Gruppe hinzufügen."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Gerät aus Gruppe entfernen."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Anwendung öffnen."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nicht verbunden"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Eingabe"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hörgerät"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Wird aktiviert…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Die Helligkeit kann nicht angepasst werden, weil sie von der obersten App gesteuert wird"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. drehen"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Bildschirm automatisch drehen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Standort"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Zur Position <xliff:g id="POSITION">%1$d</xliff:g> hinzufügen"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position ist ungültig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ansicht hinzugefügt"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ansicht entfernt"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor für Schnelleinstellungen."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unbekannt"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Alle Kacheln zurücksetzen?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle Schnelleinstellungen-Kacheln werden auf die Standardeinstellungen des Geräts zurückgesetzt"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index dade080..639aee2 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Συνδέθηκε στο <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Συνδέθηκε σε <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Αναπτύξτε την ομάδα."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Προσθήκη συσκευής στην ομάδα."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Κατάργηση συσκευής από την ομάδα."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ανοίξτε την εφαρμογή."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Μη συνδεδεμένο"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Περιαγωγή"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Είσοδος"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Βοηθήματα ακοής"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ενεργοποίηση…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Δεν είναι δυνατή η προσαρμογή της φωτεινότητας, επειδή ελέγχεται από την εφαρμογή στην κορυφή"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Αυτόματη περιστροφή"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Αυτόματη περιστροφή οθόνης"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Τοποθεσία"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Προσθήκη στη θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Μη έγκυρη θέση."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Το πλακίδιο προστέθηκε"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Το πλακίδιο καταργήθηκε"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Επεξεργασία γρήγορων ρυθμίσεων."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index fb251dd..62441c8 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Add device to group."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remove device from group."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Can\'t adjust brightness because it\'s being controlled by the top app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 54ef0cc..69aca1f 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -423,12 +423,9 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Right"</string>
-    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
-    <skip />
-    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
-    <skip />
-    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
-    <skip />
+    <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Surroundings"</string>
+    <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Left surroundings"</string>
+    <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Right surroundings"</string>
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expand to left and right separated controls"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Collapse to unified control"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mute surroundings"</string>
@@ -1003,6 +1000,7 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Tile already added"</string>
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index fb251dd..62441c8 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Add device to group."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remove device from group."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Can\'t adjust brightness because it\'s being controlled by the top app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index fb251dd..62441c8 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Add device to group."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remove device from group."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Can\'t adjust brightness because it\'s being controlled by the top app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 371638b3..840afd4 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expandir grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Agregar el dispositivo al grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Quitar el dispositivo del grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicación."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"No conectado"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audífonos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"La app superior controla el brillo, por lo que no se puede ajustar"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar la pantalla automáticamente"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Agregar a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición no válida"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Se agregó la tarjeta"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Se quitó la tarjeta"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de Configuración rápida"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b02ab30..177f298 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Mostrar grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Añade un dispositivo al grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Quita un dispositivo del grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicación."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"No conectado."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audífonos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"No se puede ajustar el brillo porque la aplicación superior lo está controlando"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar pantalla automáticamente"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Añadir a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición no válida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Recuadro añadido"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Recuadro quitado"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de ajustes rápidos."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconocido"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"¿Borrar todos los recuadros?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos los recuadros de ajustes rápidos se restablecerán a los ajustes originales del dispositivo"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 578ca4d..be021fc 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ühendatud: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ühendatud ülekandega <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Grupi laiendamine."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Seadme lisamine gruppi."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Seadme eemaldamine grupist."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Rakenduse avamine."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ühendus puudub."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Rändlus"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sisend"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Kuuldeaparaadid"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Sisselülitamine …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Heledust ei saa reguleerida, kuna seda juhib ülemine rakendus"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. pööramine"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Kuva automaatne pööramine"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Asukoht"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisamine asendisse <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Sobimatu asukoht."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Asend <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Paan on lisatud"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Paan on eemaldatud"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kiirseadete redigeerija."</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index c6b8f56..edcc172 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> gailura konektatuta."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Hona konektatuta: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Zabaldu taldea."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Gehitu gailua taldera"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Kendu gailua taldetik."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ireki aplikazioa."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Konektatu gabe."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Ibiltaritza"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sarrera"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audifonoak"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktibatzen…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ezin da argitasuna doitu goiko aplikazioak kontrolatzen duelako"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Biratze automatikoa"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Biratu pantaila automatikoki"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Kokapena"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Gehitu <xliff:g id="POSITION">%1$d</xliff:g>garren lekuan"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Kokapenak ez du balio."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>garren lekua"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Gehitu da lauza"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kendu da lauza"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ezarpen bizkorren editorea."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 6f4d1bc..f1f6a14 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"به <xliff:g id="BLUETOOTH">%s</xliff:g> متصل شد."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"به <xliff:g id="CAST">%s</xliff:g> متصل شد."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"گروه را از هم باز می‌کند."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"افزودن دستگاه به گروه."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"حذف دستگاه از گروه."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"برنامه را باز می‌کند."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"متصل نیست."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"فراگردی"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ورودی"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سمعک"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"روشن کردن…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"نمی‌توان روشنایی را تنظیم کرد زیرا برنامه بالایی آن را کنترل می‌کند"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"چرخش خودکار"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"چرخش خودکار صفحه‌نمایش"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"مکان"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"افزودن به موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"موقعیت نامعتبر است."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"کاشی اضافه شد"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"کاشی حذف شد"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ویرایشگر تنظیمات سریع."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"نامشخص"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"همه کاشی‌ها بازنشانی شود؟"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"همه کاشی‌های «تنظیمات فوری» به تنظیمات اصلی دستگاه بازنشانی خواهد شد"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>، <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 527a292..7476599 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -254,10 +254,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Yhteys: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Yhdistetty kohteeseen <xliff:g id="CAST">%s</xliff:g>"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Laajenna ryhmä."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Lisää laite ryhmään."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Poista laite ryhmästä."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Avaa sovellus."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ei yhteyttä."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -335,8 +333,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Syöttölaite"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Kuulolaitteet"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Otetaan käyttöön…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Kirkkautta ei voi säätää, koska ensisijainen sovellus ohjaa sitä"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automaattinen kääntö"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Käännä näyttöä automaattisesti."</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Sijainti"</string>
@@ -1008,6 +1005,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisää paikkaan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Virheellinen sijainti."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kiekko lisätty"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kiekko poistettu"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Pika-asetusten muokkausnäkymä"</string>
@@ -1576,6 +1575,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tuntematon"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Nollataanko kaikki laatat?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Kaikki pika-asetuslaatat palautetaan laitteen alkuperäisiin asetuksiin"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 6a2d7c8..e22f306 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connecté à <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Développer le groupe."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Ajouter un appareil au groupe."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Retirer l\'appareil du groupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ouvrir l\'appli."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Non connecté"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Itinérance"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Prothèses auditives"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation en cours…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Impossible de régler la luminosité, car elle est contrôlée par l\'appli principale"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation auto"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position incorrecte."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tuile ajoutée"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tuile retirée"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur de paramètres rapides."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Inconnu"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Réinitialiser toutes les tuiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Toutes les tuiles des paramètres rapides seront réinitialisées aux paramètres par défaut de l\'appareil."</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index e9d3c48..487c566 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -68,7 +68,7 @@
   </string-array>
   <string-array name="tile_states_bt">
     <item msgid="5330252067413512277">"Non disponible"</item>
-    <item msgid="5315121904534729843">"Désactivée"</item>
+    <item msgid="5315121904534729843">"Désactivé"</item>
     <item msgid="503679232285959074">"Activé"</item>
   </string-array>
   <string-array name="tile_states_airplane">
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 62916e8..cceab1c 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connecté à <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Développer le groupe."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Ajouter l\'appareil au groupe."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Supprimer l\'appareil du groupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ouvrir l\'application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Non connecté"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Itinérance"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Appareils auditifs"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Impossible d\'ajuster la luminosité, car celle-ci est contrôlée par l\'appli principale"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation auto"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Emplacement non valide."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloc ajouté"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloc supprimé"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur Réglages rapides"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Inconnu"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Réinitialiser tous les blocs ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Tous les blocs \"Réglages rapides\" seront réinitialisés aux paramètres d\'origine de l\'appareil"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 87980c8..f54a634 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Dispositivo conectado: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Despregar o grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Engadir o dispositivo ao grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Quitar o dispositivo do grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir a aplicación."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Non conectada"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Itinerancia"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audiófonos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Non se pode axustar o brillo porque o controla a aplicación principal"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Xirar automaticamente"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Xirar pantalla automaticamente"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localización"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engadir á posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición non válida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Engadiuse a tarxeta"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Quitouse a tarxeta"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configuración rápida."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Categoría descoñecida"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Queres restablecer todos os atallos?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Restablecerase a configuración orixinal do dispositivo para todos os atallos de Configuración rápida"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e61d4e1..1830b34 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1006,6 +1006,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"જગ્યા પર <xliff:g id="POSITION">%1$d</xliff:g> ઉમેરો"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"સ્થિતિ અમાન્ય છે."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"જગ્યા <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ટાઇલ ઉમેરી"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ટાઇલ કાઢી નાખી"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ઝડપી સેટિંગ એડિટર."</string>
@@ -1574,6 +1576,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"અજાણ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"તમામ ટાઇલ રીસેટ કરીએ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"તમામ ઝડપી સેટિંગ ટાઇલને ડિવાઇસના ઑરિજિનલ સેટિંગ પર રીસેટ કરવામાં આવશે"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0dfbb4c..6449800 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> से कनेक्ट किया गया."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> से कनेक्ट है."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ग्रुप को बड़ा करें."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"डिवाइस को ग्रुप में जोड़ें."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"डिवाइस को ग्रुप से हटाएं."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ऐप्लिकेशन खोलें."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"कनेक्ट नहीं है."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"रोमिंग"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"कान की मशीनें"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ब्लूटूथ चालू हो रहा है…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"स्क्रीन की रोशनी को अडजस्ट नहीं किया जा सकता, क्योंकि इसे टॉप ऐप्लिकेशन कंट्रोल कर रहा है"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रीन का अपने-आप दिशा बदलना (ऑटो-रोटेट)"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"जगह की जानकारी"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"टाइल को <xliff:g id="POSITION">%1$d</xliff:g> पोज़िशन पर जोड़ें"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"मौजूदा जगह अमान्य है."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"टाइल की पोज़िशन <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"टाइल जोड़ी गई"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"टाइल हटाई गई"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"त्वरित सेटिंग संपादक."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 4dba930..7db95fe 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Spojen na <xliff:g id="BLUETOOTH">%s</xliff:g> ."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Povezani ste sa sljedećim uređajem: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Proširite grupu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodajte uređaj u grupu."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Uklonite uređaj iz grupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otvorite aplikaciju."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nije povezano."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Unos"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušna pomagala"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Svjetlina se ne može prilagoditi jer njome upravlja aplikacija pri vrhu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko zakretanje"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko zakretanje zaslona"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Položaj nije važeći."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartica je dodana"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartica je uklonjena"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivač brzih postavki."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite li poništiti sve pločice?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve pločice Brze postavke vratit će se na izvorne postavke uređaja"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 891cf28..906ce54 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Csatlakoztatva a következőhöz: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Csatlakozva a következőhöz: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Csoport kibontása."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Eszköz hozzáadása csoporthoz."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Eszköz eltávolítása csoportból."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Alkalmazás megnyitása."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nincs csatlakozva."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Bevitel"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hallókészülék"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Bekapcsolás…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nem lehet módosítani a fényerőt, mert a felső alkalmazás vezérli"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Hozzáadás a következő pozícióhoz: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Érvénytelen pozíció."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. hely"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kártya hozzáadva"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kártya eltávolítva"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Gyorsbeállítások szerkesztője"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index f231822..57a822e 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Միացված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Միացված է <xliff:g id="CAST">%s</xliff:g>-ին:"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Ծավալել խումբը։"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Սարքը ավելացնել խմբին։"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Հեռացնել սարքը խմբից։"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Բացել հավելվածը։"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Միացված չէ:"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Ռոումինգ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Մուտքագրում"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Լսողական սարք"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Միացում…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Հնարավոր չէ կարգավորել պայծառությունը, քանի որ այն կառավարվում է գլխավոր հավելվածի կողմից"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ինքնապտտում"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ավտոմատ պտտել էկրանը"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Տեղորոշում"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ավելացնել դիրք <xliff:g id="POSITION">%1$d</xliff:g>-ում"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Դիրքն անվավեր է։"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Սալիկն ավելացվեց"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Սալիկը հեռացվեց"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Արագ կարգավորումների խմբագրիչ:"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Անհայտ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Զրոյացնե՞լ բոլոր սալիկները"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Արագ կարգավորումների բոլոր սալիկները կզրոյացվեն սարքի սկզբնական կարգավորումների համաձայն։"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index e0e69a9..2d38c8f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Terhubung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Terhubung ke <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Luaskan grup."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Tambahkan perangkat ke grup."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Hapus perangkat dari grup."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Buka aplikasi."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Tidak terhubung."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Alat bantu dengar"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Mengaktifkan…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Tidak dapat menyesuaikan kecerahan karena sedang dikontrol oleh aplikasi atas"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Putar Otomatis"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Putar layar otomatis"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan ke posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisi tidak valid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartu ditambahkan"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartu dihapus"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor setelan cepat."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tidak diketahui"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset semua kartu?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Semua kartu Setelan Cepat akan direset ke setelan asli perangkat"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index faff4c5..5c37bdb 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tengt við <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Tengt við <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Stækka hóp."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Bæta tæki við hóp."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Fjarlægja tæki úr hóp."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Opna forrit."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Engin tenging."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Reiki"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Inntak"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Heyrnartæki"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Kveikir…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ekki er hægt að breyta birtustiginu vegna þess að efsta forritið stjórnar því"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Sjálfvirkur snúningur"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Snúa skjá sjálfkrafa"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Staðsetning"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bæta við í stöðu <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Staða ógild."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Staða <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Reit bætt við"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Reitur fjarlægður"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Flýtistillingaritill."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Óþekkt"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Endurstilla alla reiti?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Allir flýtistillingareitir munu endurstillast á upprunalegar stillingar tækisins"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index e6f5dee..a21b6db 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Aggiungi alla posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posizione non valida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Riquadro aggiunto"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Riquadro rimosso"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor di impostazioni rapide."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 8e2df32..936b10e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1006,6 +1006,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"הוספה למיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"המיקום לא תקין."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"הלחצן נוסף"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"הלחצן הוסר"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"עורך הגדרות מהירות."</string>
@@ -1574,6 +1576,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"לא ידוע"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"לאפס את כל הלחצנים?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"כל הלחצנים ב\'הגדרות מהירות\' יאופסו להגדרות המקוריות של המכשיר"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"‫<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 5daa645e..d5ecfe5 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> に追加"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置が無効です。"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"タイルを追加しました"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"タイルを削除しました"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"クイック設定エディタ"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 68f48b0..2e3dc98 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"დაკავშირებულია <xliff:g id="BLUETOOTH">%s</xliff:g>-თან."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"დაკავშირებულია მოწყობილობასთან: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ჯგუფის გაფართოება."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"მოწყობილობის ჯგუფში დამატება."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"მოწყობილობის ჯგუფიდან ამოშლა."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"აპლიკაციის გახსნა."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"არ არის დაკავშირებული."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"როუმინგი"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"შეყვანა"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"სმენის მოწყობილობები"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ირთვება…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"სიკაშკაშის კორექტირება ვერ ხერხდება, რადგან ის იმართება გახსნილი აპის მიერ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ავტოროტაცია"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ეკრანის ავტომატური შეტრიალება"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"მდებარეობა"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"დამატება პოზიციაზე <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"პოზიცია არასწორია."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"მოზაიკის ფილა დაემატა"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"მოზაიკის ფილა ამოიშალა"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"სწრაფი პარამეტრების რედაქტორი."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"უცნობი"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"გსურთ ყველა ფილის გადაყენება?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"სწრაფი პარამეტრების ყველა ფილა გადაყენდება მოწყობილობის ორიგინალ პარამეტრებზე"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 1ecc743..1c4d31a 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> қосылған."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> трансляциясына қосылды."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Топты жайыңыз."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Құрылғыны топқа қосады."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Құрылғыны топтан өшіреді."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Қолданбаны ашыңыз."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Жалғанбаған."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Кіріс"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Есту аппараттары"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Қосылып жатыр…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Жарықтықты реттеу мүмкін емес, себебі ол жетекші қолданба арқылы басқарылады."</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматты түрде бұру"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматты айналатын экран"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Локация"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> орнына қосу"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Орын жарамсыз."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> орны"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Бөлшек қосылды."</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Бөлшек өшірілді."</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Жылдам параметрлер өңдегіші."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгісіз"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Барлық бөлшекті бастапқы күйге қайтару керек пе?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Барлық \"Жылдам параметрлер\" бөлшегі құрылғының бастапқы параметрлеріне қайтарылады."</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 8c5ea90..8b3bfcc 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"បាន​ភ្ជាប់​ទៅ <xliff:g id="BLUETOOTH">%s</xliff:g> ។"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"បានភ្ជាប់ទៅ <xliff:g id="CAST">%s</xliff:g>"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ពង្រីកក្រុម។"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"បញ្ចូលឧបករណ៍ទៅក្រុម។"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ដកឧបករណ៍ចេញពីក្រុម។"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"បើកកម្មវិធី។"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"មិន​បាន​តភ្ជាប់​។"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"រ៉ូ​មីង"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"បញ្ចូល"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"កំពុង​បើក..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"មិនអាចកែតម្រូវកម្រិតពន្លឺបានទេ ដោយសារវាកំពុងស្ថិតក្រោមការគ្រប់គ្រងរបស់កម្មវិធីខាងលើគេ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"បង្វិល​ស្វ័យ​ប្រវត្តិ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ទី​តាំង​"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"បញ្ចូលទៅ​ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ទីតាំងគ្មានសុពលភាព។"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"បានបញ្ចូលប្រអប់"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"បាន​ផ្លាស់ទី​ប្រអប់"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"កម្មវិធីកែការកំណត់រហ័ស"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7c785d9..50f8c60 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ಗುಂಪು ವಿಸ್ತರಿಸಿ."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"ಸಾಧನವನ್ನು ಗುಂಪಿಗೆ ಸೇರಿಸಿ."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ಸಾಧನವನ್ನು ಗುಂಪಿನಿಂದ ತೆಗೆದುಹಾಕಿ."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಿರಿ."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ರೋಮಿಂಗ್"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ಇನ್‌ಪುಟ್"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ಆನ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ಬ್ರೈಟ್‌ನೆಸ್ ಅನ್ನು ಹೊಂದಾಣಿಕೆ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ, ಏಕೆಂದರೆ ಅದನ್ನು ಟಾಪ್ ಆ್ಯಪ್ ನಿಯಂತ್ರಿಸುತ್ತಿದೆ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ಸ್ವಯಂ-ತಿರುಗುವಿಕೆ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ಸ್ಥಳ"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸೇರಿಸಿ"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ಸ್ಥಾನವು ಅಮಾನ್ಯವಾಗಿದೆ."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ಟೈಲ್ ಸೇರಿಸಲಾಗಿದೆ"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ಟೈಲ್ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳ ಎಡಿಟರ್."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ಅಪರಿಚಿತ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ಎಲ್ಲಾ ಟೈಲ್‌ಗಳನ್ನು ರೀಸೆಟ್ ಮಾಡಬೇಕೆ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ಎಲ್ಲಾ ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಟೈಲ್‌ಗಳನ್ನು ಸಾಧನದ ಮೂಲ ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ರೀಸೆಟ್ ಮಾಡಲಾಗುತ್ತದೆ"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index b3c21b1..7342f32 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>에 연결되었습니다."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>에 연결됨"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"그룹을 펼칩니다."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"기기를 그룹에 추가합니다."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"그룹에서 기기를 삭제합니다."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"애플리케이션을 엽니다."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"연결되지 않았습니다."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"로밍"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"입력"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"보청기"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"켜는 중..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"상위 앱에서 밝기를 제어하고 있으므로 밝기를 조절할 수 없습니다."</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"자동 회전"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"화면 자동 회전"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"위치"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> 위치에 추가"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"위치가 잘못되었습니다."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> 위치"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"타일 추가됨"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"타일 삭제됨"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"빠른 설정 편집기"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"알 수 없음"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"모든 타일을 재설정하시겠습니까?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"모든 빠른 설정 타일이 기기의 원래 설정으로 재설정됩니다."</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 9aedbb5..f21ee1a 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> менен туташты."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Топту жайып көрсөтүү."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Түзмөктү топко кошуңуз."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Түзмөктү топтон алып салыңыз."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Колдонмону ачуу."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Интернет жок."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Киргизүү"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Угуу аппараттары"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Күйгүзүлүүдө…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Жарыктыкты тууралоого болбойт, анткени аны жогорку колдонмо көзөмөлдөйт"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авто буруу"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Экранды авто буруу"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Жайгашкан жер"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>-позицияга кошуу"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Абал жараксыз."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>-позиция"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Карта кошулду"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Карта өчүрүлдү"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ыкчам параметрлер түзөткүчү."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгисиз"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Бардык параметрлерди кайра коесузбу?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Бардык ыкчам параметрлер түзмөктүн баштапкы маанилерине кайтарылат"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 47b3235..4c778d1 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ເຊື່ອມ​ຕໍ່​ຫາ <xliff:g id="BLUETOOTH">%s</xliff:g> ແລ້ວ."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"ເຊື່ອມຕໍ່ຫາ <xliff:g id="CAST">%s</xliff:g> ແລ້ວ."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ຂະຫຍາຍກຸ່ມ."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"ເພີ່ມອຸປະກອນໃສ່ໃນກຸ່ມ."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ລຶບອຸປະກອນອອກຈາກກຸ່ມ."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ເປີດແອັບພລິເຄຊັນ."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"ບໍ່ໄດ້ເຊື່ອມຕໍ່."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ໂຣມມິງ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ການປ້ອນຂໍ້ມູນ"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ເຄື່ອງຊ່ວຍຟັງ"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ກຳລັງເປີດ..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ບໍ່ສາມາດປັບຄວາມສະຫວ່າງໄດ້ເນື່ອງຈາກຄວບຄຸມໂດຍແອັບທາງເທິງ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ໝຸນ​ອັດ​ຕະ​ໂນ​ມັດ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ສະຖານທີ່"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ເພີ່ມໃສ່ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ຕຳແໜ່ງບໍ່ຖືກຕ້ອງ."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ເພີ່ມແຜ່ນແລ້ວ"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ລຶບແຜ່ນແລ້ວ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ຕົວແກ້ໄຂການຕັ້ງຄ່າດ່ວນ"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ບໍ່ຮູ້ຈັກ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ຣີເຊັດແຜ່ນທັງໝົດບໍ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ແຜ່ນການຕັ້ງຄ່າດ່ວນທັງໝົດຈະຣີເຊັດເປັນການຕັ້ງຄ່າແບບເກົ່າຂອງອຸປະກອນ"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5971e73..f387a4e 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Prisijungta prie „<xliff:g id="BLUETOOTH">%s</xliff:g>“."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Prisijungta prie <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Išskleisti grupę."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Pridėti įrenginį prie grupės."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Pašalinti įrenginį iš grupės."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Atidaryti programą."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Neprijungta."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Tarptinklinis ryšys"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Įvestis"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Klausos aparatai"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Įjungiama…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Negalima koreguoti šviesumo, nes jį valdo viršuje esanti programa"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatinis pasukimas"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatiškai sukti ekraną"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vietovė"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridėkite <xliff:g id="POSITION">%1$d</xliff:g> pozicijoje"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Padėtis netinkama."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> pozicija"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Išklotinė pridėta"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Išklotinė pašalinta"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sparčiųjų nustatymų redagavimo priemonė."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index bb8d702..fd54921 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ir izveidots savienojum ar <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Savienots ar ierīci <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Izvērst grupu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Pievienot ierīci grupai."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Noņemt ierīci no grupas."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Atvērt lietojumprogrammu."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Savienojums nav izveidots."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Viesabonēšana"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ievade"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Dzirdes aparāti"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Notiek ieslēgšana…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nevar mainīt spilgtumu, jo to kontrolē lietotne augšpusē"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automātiska pagriešana"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automātiska ekrāna pagriešana"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Atrašanās vieta"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pievienot elementu pozīcijā numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nederīga pozīcija."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozīcija numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Elements ir pievienots"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Elements ir noņemts"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ātro iestatījumu redaktors."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nezināma"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vai atiestatīt visus elementus?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Visiem ātro iestatījumu elementiem tiks atiestatīti sākotnējie iestatījumi"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 189390f..2afe93e 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Поврзано со <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Поврзано со <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Проширете ја групата."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Додај го уредот во групата."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Отстрани го уредот од групата."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Отворете ја апликацијата."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Не е поврзана"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роаминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Влез"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слушни помагала"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Се вклучува…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Не може да се приспособи осветленоста бидејќи е контролирана од горната апликација"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматско ротирање"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматско ротирање на екранот"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додавање на позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позицијата е погрешна."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Додадена е плочка"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Отстранета е плочка"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Уредник за брзи поставки."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Непознато"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Да се ресетираат сите плочки?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Сите плочки на „Брзи поставки“ ќе се ресетираат на првичните поставки на уредот"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 7e4282f..48d07cb 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> എന്ന സ്ഥാനത്തേക്ക് ചേർക്കുക"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"സ്ഥാനം അസാധുവാണ്."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ടൈൽ ചേർത്തു"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ടൈൽ നീക്കം ചെയ്‌തു"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ദ്രുത ക്രമീകരണ എഡിറ്റർ."</string>
@@ -1571,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"അജ്ഞാതം"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"എല്ലാ ടൈലുകളും റീസെറ്റ് ചെയ്യണോ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"എല്ലാ ദ്രുത ക്രമീകരണ ടൈലുകളും ഉപകരണത്തിന്റെ ഒറിജിനൽ ക്രമീകരണത്തിലേക്ക് റീസെറ്റ് ചെയ്യും"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index c6ab2c5..c7fb7da 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>-тай холбогдсон."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>-д холбогдсон."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Бүлгийг дэлгэнэ үү."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Бүлэгт төхөөрөмж нэмнэ."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Бүлгээс төхөөрөмж хасна."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Аппликейшныг нээнэ үү."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Холбогдоогүй."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Оролт"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Сонсголын төхөөрөмж"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Асааж байна…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Гэрэлтүүлгийг давуу эрхтэй аппаас хянаж байгаа тул тохируулах боломжгүй"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматаар эргэх"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Дэлгэцийг автоматаар эргүүлэх"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Байршил"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> байрлалд нэмнэ үү"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Байрлал буруу байна."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> байрлал"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Хавтан нэмсэн"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Хавтанг хассан"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Шуурхай тохиргоо засварлагч."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Тодорхойгүй"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Бүх хавтанг шинэчлэх үү?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Шуурхай тохиргооны бүх хавтан төхөөрөмжийн эх тохиргоо руу шинэчлэгдэнэ"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 9fa4051..2c5a9a8 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> शी कनेक्‍ट केले."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> शी कनेक्ट केले."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"गटाचा विस्तार करा."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"डिव्हाइस गटामध्ये जोडा."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"डिव्हाइस गटामधून काढून टाका."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"अ‍ॅप उघडा."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"कनेक्ट केले नाही."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"रोमिंग"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"श्रवणयंत्रे"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सुरू करत आहे…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ब्राइटनेस टॉप ॲपद्वारे नियंत्रित केला जात असल्यामुळे ॲडजस्ट करू शकत नाही"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ऑटो-रोटेट स्क्रीन"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> स्थानावर जोडा"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"स्थान चुकीचे आहे."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थान <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"टाइल जोडली"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"टाइल काढून टाकली"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"द्रुत सेटिंग्ज संपादक."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"अज्ञात"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"सर्व टाइल रीसेट करायच्या?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"सर्व क्विक सेटिंग्ज टाइल डिव्हाइसच्या मूळ सेटिंग्जवर रीसेट केल्या जातील"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 91e7e63..5575098 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan pada kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Kedudukan tidak sah."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Jubin ditambah"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Jubin dialih keluar"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor tetapan pantas."</string>
@@ -1571,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tidak diketahui"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Tetapkan semula semua jubin?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Semua jubin Tetapan Pantas akan ditetapkan semula kepada tetapan asal peranti"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 703562e..b428422 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>သို့ ချိတ်ဆက်ထား"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> သို့ချိတ်ဆက်ထားပါသည်။"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"အုပ်စုကို ပိုပြသည်။"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"အဖွဲ့သို့ စက်ပစ္စည်းထည့်ရန်။"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"အဖွဲ့မှ စက်ပစ္စည်းကို ဖယ်ရှားရန်။"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"အပလီကေးရှင်းကို ဖွင့်သည်။"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"ချိတ်ဆက်မထားပါ"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ပြင်ပကွန်ရက်သုံးခြင်း"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"အဝင်"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"နားကြားကိရိယာ"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ဖွင့်နေသည်…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"အပေါ်အက်ပ်မှ ထိန်းချုပ်ထားသောကြောင့် တောက်ပမှုကို ချိန်ညှိ၍ မရပါ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"အော်တို-လည်"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"မျက်နှာပြင်အား အလိုအလျောက်လှည့်ခြင်း"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"တည်နေရာ"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထားသို့ ပေါင်းထည့်ရန်"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"နေရာ မမှန်ပါ။"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထား"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"အကွက်ငယ်ကို ထည့်ပြီးပါပြီ"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"အကွက်ငယ်ကို ဖယ်ရှားပြီးပါပြီ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"မြန်ဆန်သည့် ဆက်တင်တည်းဖြတ်စနစ်"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"အမျိုးအမည်မသိ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"အကွက်ငယ်အားလုံးကို ပြင်ဆင်သတ်မှတ်မလား။"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"အမြန်ဆက်တင်များ အကွက်ငယ်အားလုံးကို စက်ပစ္စည်း၏ မူရင်းဆက်တင်များသို့ ပြင်ဆင်သတ်မှတ်ပါမည်"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>၊ <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index b75f644..9574075 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Koblet til <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Koblet til <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Utvid gruppen."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Legg til enheten i gruppen."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Fjern enheten fra gruppen."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Åpne appen."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ikke tilkoblet."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Innenhet"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Høreapparater"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Slår på …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Kan ikke justere lysstyrken, fordi den kontrolleres av den øvre appen"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotér automatisk"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotér skjermen automatisk"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Sted"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Legg til posisjonen <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisjonen er ugyldig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisjon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"En infobrikke er lagt til"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"En infobrikke er fjernet"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsvindu for hurtiginnstillinger."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ukjent"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vil du tilbakestille alle brikkene?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle brikker for hurtiginnstillinger tilbakestilles til enhetens opprinnelige innstillinger"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index cd20def..4d37f8f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> मा जडित।"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> मा कनेक्ट गरियो।"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"समूह एक्स्पान्ड गर्नुहोस्।"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"समूहमा डिभाइस हाल्नुहोस्।"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"समूहबाट डिभाइस हटाउनुहोस्।"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"एप खोल्नुहोस्।"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"जडान नगरिएको।"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"रोमिङ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"हियरिङ डिभाइसहरू"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सक्रिय गर्दै…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"सिरानको एपले चमक नियन्त्रण गरिरहेकाले चमक मिलाउन मिल्दैन"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"अटो रोटेट"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रिन स्वतःघुम्ने"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"लोकेसन"</string>
@@ -997,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"कम प्राथमिकताका सूचना आइकनहरू देखाउनुहोस्"</string>
     <string name="other" msgid="429768510980739978">"अन्य"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"टाइलको आकार टगल गर्नुहोस्"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल हटाउनुहोस्"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"अन्तिम स्थानमा टाइल हाल्नुहोस्"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल सार्नुहोस्"</string>
@@ -1007,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"टाइल यो अवस्था <xliff:g id="POSITION">%1$d</xliff:g> मा हाल्नुहोस्"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"पोजिसन अवैध छ।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"टाइल हालियो"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"टाइल हटाइयो"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"द्रुत सेटिङ सम्पादक।"</string>
@@ -1551,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"आफूले हालसालै चलाएका एपहरू हेर्न तीन वटा औँलाले टचप्याडमा माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"आफ्ना सबै एपहरू हेर्न आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"जानकारी लुकाउन सम्पादन गरिएको"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"हेर्न अनलक गर्नुहोस्"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"कोड हेर्न अनलक गर्नुहोस्"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"सान्दर्भिक शिक्षा"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"पछाडि जान आफ्नो टचप्याड प्रयोग गर्नुहोस्"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"तीन वटा औँला प्रयोग गरी बायाँ वा दायाँतिर स्वाइप गर्नुहोस्। थप जेस्चर प्रयोग गर्ने तरिका सिक्न ट्याप गर्नुहोस्।"</string>
@@ -1577,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"अज्ञात"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"सबै टाइलहरू रिसेट गर्ने हो?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"द्रुत सेटिङका सबै टाइलहरू रिसेट गरी डिभाइसका मूल सेटिङ लागू गरिने छन्"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 1df27df..26d8752 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Verbonden met <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Verbonden met <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Groep uitvouwen."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Voeg het apparaat aan de groep toe."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Verwijder het apparaat uit de groep."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"App openen."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Niet verbonden."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hoortoestellen"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aanzetten…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Kan de helderheid niet aanpassen omdat deze wordt beheerd door de bovenste app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Scherm automatisch draaien"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Locatie"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Toevoegen aan positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positie ongeldig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tegel toegevoegd"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tegel verwijderd"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor voor \'Snelle instellingen\'."</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index ddb9157..a0e360c 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ଅବସ୍ଥିତିରେ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ଅବସ୍ଥିତି ଅବୈଧ ଅଟେ।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ଅବସ୍ଥିତି <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ଟାଇଲ୍ ଯୋଗ କରାଯାଇଛି"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ଟାଇଲ୍ କାଢ଼ି ଦିଆଯାଇଛି"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଏଡିଟର୍।"</string>
@@ -1571,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ଅଜଣା"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ସମସ୍ତ ଟାଇଲକୁ ରିସେଟ କରିବେ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ସମସ୍ତ କୁଇକ ସେଟିଂସ ଟାଇଲ ଡିଭାଇସର ମୂଳ ସେଟିଂସରେ ରିସେଟ ହୋଇଯିବ"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 39c02d2..f2a6612 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ਸਥਾਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ਮੌਜੂਦਾ ਥਾਂ ਅਵੈਧ ਹੈ।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ਸਥਾਨ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ਟਾਇਲ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ਟਾਇਲ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਗਿਆ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਸੰਪਾਦਕ।"</string>
@@ -1571,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ਅਗਿਆਤ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ਕੀ ਸਾਰੀਆਂ ਟਾਇਲਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ਸਾਰੀਆਂ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਟਾਇਲਾਂ ਡੀਵਾਈਸ ਦੀਆਂ ਮੂਲ ਸੈਟਿੰਗਾਂ \'ਤੇ ਰੀਸੈੱਟ ਹੋ ਜਾਣਗੀਆਂ"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b93bf30..99e99e1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Połączono z <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Połączono z urządzeniem <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Rozwiń grupę."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodaj urządzenie do grupy."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Usuń urządzenie z grupy."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otwórz aplikację."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nie połączono."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Wejście"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparaty słuchowe"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Włączam…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nie można dostosować jasności, ponieważ reguluje ją aplikacja na pierwszym planie"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoobracanie"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoobracanie ekranu"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokalizacja"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodaj w pozycji <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nieprawidłowa pozycja."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozycja <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Dodano kartę"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Usunięto kartę"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Edytor szybkich ustawień."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nieznane"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Zresetować wszystkie kafelki?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Wszystkie kafelki Szybkich ustawień zostaną zresetowane do oryginalnych ustawień urządzenia"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 7c9028b..4663dba 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expandir grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Adicionar dispositivo ao grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remover dispositivo do grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicativo."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Sem conexão."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Não é possível ajustar o brilho, porque ele está sendo controlado pelo app principal"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloco adicionado"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloco removido"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configurações rápidas."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecidos"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Redefinir todos os blocos?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos os blocos \"Configurações rápidas\" serão redefinidos para as configurações originais do dispositivo"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a8e0f05..7a0e4f6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ligado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ligado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expanda o grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Adicionar dispositivo ao grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remover dispositivo do grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abra a aplicação."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Sem ligação."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"A ativar..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Não é possível ajustar o brilho porque está a ser controlado pela app principal"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotação auto."</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rodar o ecrã automaticamente"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicione à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Cartão adicionado"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Cartão removido"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de definições rápidas."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 7c9028b..4663dba 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expandir grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Adicionar dispositivo ao grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remover dispositivo do grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicativo."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Sem conexão."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Não é possível ajustar o brilho, porque ele está sendo controlado pelo app principal"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloco adicionado"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloco removido"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configurações rápidas."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecidos"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Redefinir todos os blocos?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos os blocos \"Configurações rápidas\" serão redefinidos para as configurações originais do dispositivo"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 23270ea..e8b826b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectat la <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"S-a stabilit conexiunea la <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Extinde grupul."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Adaugă dispozitivul în grup."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Elimină dispozitivul din grup."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Deschide aplicația."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Neconectat."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Intrare"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparate auditive"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Se activează..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nu se poate ajusta luminozitatea deoarece este controlată de aplicația de sus"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotire automată"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotirea automată a ecranului"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Locație"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adaugă pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Poziție nevalidă."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Cardul a fost adăugat"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Cardul a fost eliminat"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editorul pentru setări rapide."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Necunoscută"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Resetezi toate cardurile?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Toate cardurile Setări rapide se vor reseta la setările inițiale ale dispozitivului"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index e4c1d45..52458eb 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>: подключено."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Подключено к: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Развернуть группу."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Добавить устройство в группу."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Удалить устройство из группы."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Открыть приложение."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Не подключено"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Устройство ввода"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слуховые аппараты"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Включение…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Невозможно изменить яркость, поскольку ею управляет приложение сверху"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоповорот"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоповорот экрана"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Геолокация"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавить на позицию <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Недопустимое расположение."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Панель добавлена"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Панель удалена"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор быстрых настроек."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Неизвестно"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Сбросить все параметры?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Для всех параметров быстрых настроек будут восстановлены значения по умолчанию."</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 437a35b..84a981f 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> වෙත සම්බන්ධ කරන ලදි."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> වෙත සම්බන්ධ විය."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"සමූහය දිගහැරීම"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"සමූහයට උපාංගය එක් කරන්න."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"උපාංගය සමූහයෙන් ඉවත් කරන්න."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"යෙදුම විවෘත කරන්න."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"සම්බන්ධ වී නැත."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"රෝමිං"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ආදානය"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ශ්‍රවණාධාරක"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ක්‍රියාත්මක කරමින්…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ඉහළ යෙදුම මඟින් එය පාලනය වන නිසා දීප්තිය ගැළපුම් කළ නොහැක"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ස්වයංක්‍රීය කරකැවීම"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ස්වයංක්‍රීයව-භ්‍රමණය වන තිරය"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ස්ථානය"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ස්ථානයට එක් කරන්න"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ස්ථානය අවලංගුයි."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ටයිල් එක එක් කරන ලදි"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ටයිල් ඉවත් කරන ලදි"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ඉක්මන් සැකසුම් සංස්කාරකය."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"නොදනී"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"සියලු ටයිල් නැවත සකසන්න ද?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"සියලු ඉක්මන් සැකසීම් ටයිල් උපාංගයේ මුල් සැකසීම් වෙත නැවත සකසනු ඇත"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 859c976..78a332a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Pripojené k zariadeniu <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Pripojené k zariadeniu <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Rozbaliť skupinu"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Pridať zariadenie do skupiny"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Odstrániť zariadenie zo skupiny"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otvoriť aplikáciu"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nepripojené."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Načúvadlá"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapína sa…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Jas sa nedá upraviť, pretože ho ovláda horná aplikácia"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčanie"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčanie obrazovky"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridať na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozícia je neplatná."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozícia"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Karta bola pridaná"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Karta bola odstránená"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor rýchlych nastavení"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznáme"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Chcete resetovať všetky karty?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Všetky karty rýchlych nastavení sa resetujú na pôvodné nastavenia zariadenia"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 2a1ed469..93649f5 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezava vzpostavljena z: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Vzpostavljena povezava: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Razširitev skupine."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodajte napravo v skupino."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Odstranite napravo iz skupine."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Odpiranje aplikacije."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ni povezan."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Gostovanje"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vhodna naprava"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Vklapljanje …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Svetlosti ni mogoče prilagoditi, ker jo nadzoruje aplikacija na vrhu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Samodejno sukanje"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Samodejno sukanje zaslona"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Položaj je neveljaven."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ploščica je bila dodana"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ploščica je bila odstranjena"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Urejevalnik hitrih nastavitev."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznano"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite ponastaviti vse ploščice?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Vse ploščice v hitrih nastavitvah bodo ponastavljene na prvotne nastavitve naprave."</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 916595f..5e69808 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Lidhur me <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Është lidhur me <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Zgjero grupin."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Shto pajisjen te grupi."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Hiq pajisjen nga grupi."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Hap aplikacionin."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nuk është i lidhur."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Hyrja"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparatet e dëgjimit"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Po aktivizohet…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ndriçimi nuk mund të rregullohet pasi po kontrollohet nga aplikacioni lart"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rrotullim automatik"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rrotullimi automatik i ekranit"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vendndodhja"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Shto te pozicioni <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozicion i pavlefshëm."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Pllakëza u shtua"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Pllakëza u hoq"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redaktori i cilësimeve të shpejta."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nuk njihet"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Të rivendosen të gjitha pllakëzat?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Të gjitha pllakëzat e \"Cilësimeve të shpejta\" do të rivendosen te cilësimet origjinale të pajisjes"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 6bf3a69..1b645a8 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додајте на <xliff:g id="POSITION">%1$d</xliff:g>. позицију"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позиција је неважећа."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Плочица је додата"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Плочица је уклоњена"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Уређивач за Брза подешавања."</string>
@@ -1571,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Непознато"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Желите да ресетујете све плочице?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Све плочице Брзих подешавања ће се ресетовати на првобитна подешавања уређаја"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index aa9f4a4..a4129e0 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ansluten till <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ansluten till <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Utöka gruppen."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Lägg till enheten i gruppen."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Ta bort enheten från gruppen."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Öppna appen."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Inte ansluten."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingång"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hörapparater"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverar …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Det går inte att ändra ljusstyrkan eftersom den styrs av den översta appen"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotera automatiskt"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotera skärmen automatiskt"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Plats"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lägg till på position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positionen är ogiltig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kortet har lagts till"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kortet har tagits bort"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigerare för snabbinställningar."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Okänt"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vill du återställa alla rutor?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alla Snabbinställningsrutor återställs till enhetens ursprungliga inställningar"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 72bfb83..cb82aff 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Imeunganishwa kwenye <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Imeunganishwa kwenye <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Panua kikundi."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Weka kifaa kwenye kikundi."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Ondoa kifaa kwenye kikundi."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Fungua programu."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Haijaunganishwa."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Mitandao ya ng\'ambo"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vifaa vya kuingiza sauti"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Visaidizi vya kusikia"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Inawasha..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Imeshindwa kurekebisha mwangaza kwa sababu inadhibitiwa na programu iliyo juu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Zungusha kiotomatiki"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Skrini ijizungushe kiotomatiki"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Mahali"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ongeza kwenye nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nafasi si sahihi."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kigae kimewekwa"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kigae kimeondolewa"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kihariri cha Mipangilio ya haraka."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Visivyojulikana"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Ungependa kubadilisha vigae vyote?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Vigae vyote vya Mipangilio ya Haraka vitabadilishwa kuwa katika mipangilio halisi ya kifaa"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 31ab515..77be6ea 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>க்கு இணைக்கப்பட்டது."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> உடன் இணைக்கப்பட்டுள்ளது."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"குழுவை விரிவாக்கும்."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"குழுவில் சாதனத்தைச் சேர்க்கும்."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"குழுவிலிருந்து சாதனத்தை அகற்றும்."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ஆப்ஸைத் திறக்கும்."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"இணைக்கப்படவில்லை."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ரோமிங்"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"உள்ளீடு"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"செவித்துணைக் கருவி"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ஆன் செய்கிறது…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ஒளிர்வை மேலுள்ள ஆப்ஸ் கட்டுப்படுத்துவதால் அதை மாற்ற முடியவில்லை"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"தானாகச் சுழற்று"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"திரையைத் தானாகச் சுழற்று"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"இருப்பிடம்"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>ல் சேர்க்கும்"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"நிலை தவறானது."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"இடம்: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"கட்டம் சேர்க்கப்பட்டது"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"கட்டம் அகற்றப்பட்டது"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"விரைவு அமைப்புகள் திருத்தி."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"தெரியவில்லை"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"அனைத்துக் கட்டங்களையும் மீட்டமைக்கவா?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"விரைவு அமைப்புகளின் கட்டங்கள் அனைத்தும் சாதனத்தின் அசல் அமைப்புகளுக்கு மீட்டமைக்கப்படும்"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index d26bfac..b466519 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"గ్రూప్‌ను విస్తరించండి."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"గ్రూప్‌కి పరికరాన్ని జోడించండి."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"గ్రూప్ నుండి పరికరాన్ని తీసివేయండి."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"యాప్‌ను తెరవండి."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"కనెక్ట్ చేయబడలేదు."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"రోమింగ్"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ఇన్‌పుట్"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"వినికిడి పరికరాలు"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ఆన్ చేస్తోంది…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"దీనిని టాప్ యాప్ కంట్రోల్ చేస్తోంది కనుక బ్రైట్‌నెస్‌ను సర్దుబాటు చేయడం సాధ్యం కాదు"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ఆటో-రొటేట్‌"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"స్క్రీన్ ఆటో-రొటేట్‌"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"లొకేషన్"</string>
@@ -1007,6 +1004,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> స్థానానికి జోడించండి"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ప్రస్తుత పొజిషన్ చెల్లదు."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"టైల్ జోడించబడింది"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"టైల్ తీసివేయబడింది"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"శీఘ్ర సెట్టింగ్‌ల ఎడిటర్."</string>
@@ -1577,6 +1576,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"తెలియదు"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"టైల్స్ అన్ని రీసెట్ చేయాలా?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"అన్ని క్విక్ సెట్టింగ్‌ల టైల్స్, పరికరం తాలూకు ఒరిజినల్ సెట్టింగ్‌లకు రీసెట్ చేయబడతాయి"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 9196f95..e816c04 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1003,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"เพิ่มไปยังตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ตำแหน่งไม่ถูกต้อง"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"เพิ่มชิ้นส่วนแล้ว"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"นำชิ้นส่วนออกแล้ว"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ตัวแก้ไขการตั้งค่าด่วน"</string>
@@ -1571,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ไม่ทราบ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"รีเซ็ตการ์ดทั้งหมดใช่ไหม"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"การ์ดการตั้งค่าด่วนทั้งหมดจะรีเซ็ตเป็นการตั้งค่าเดิมของอุปกรณ์"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a6b0d6a..d996218 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Nakakonekta sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Nakakonekta sa <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"I-expand ang grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Idagdag ang device sa grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Alisin ang device sa grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Buksan ang application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Hindi nakakonekta."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Mga hearing aid"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ino-on…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Hindi ma-adjust ang liwanag dahil kinokontrol ito ng nangingibabaw na app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"I-auto rotate"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Awtomatikong i-rotate ang screen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasyon"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Idagdag sa posisyong <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Invalid ang posisyon."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Idinagdag ang tile"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Inalis ang tile"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor ng Mga mabilisang setting."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 13d6cd7..9d78941 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ile bağlı."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> bağlantısı kuruldu."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Grubu genişlet."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Cihazı gruba ekle."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Cihazı gruptan kaldır."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Uygulama aç."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Bağlanmadı."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Dolaşım"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"İşitme cihazları"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Açılıyor…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Parlaklık ayarlanamıyor, çünkü bu özellik en üstteki uygulama tarafından kontrol ediliyor"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Otomatik döndür"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranı otomatik döndür"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Konum"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> konumuna ekle"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Konum geçersiz."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Konum: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kutu eklendi"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kutu kaldırıldı"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Hızlı ayar düzenleyicisi."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Bilinmiyor"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Tüm ayar kutuları sıfırlansın mı?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Tüm Hızlı Ayarlar kutuları cihazın özgün ayarlarına sıfırlanır"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index f0f4e38..97e5bb7 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -247,15 +247,13 @@
     <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Натисніть, щоб змінити налаштування пристрою"</string>
     <string name="accessibility_bluetooth_device_settings_gear_with_name" msgid="114373701123165491">"<xliff:g id="DEVICE_NAME">%s</xliff:g>. Змінити налаштування пристрою"</string>
     <string name="accessibility_bluetooth_device_settings_see_all" msgid="5260390270128256620">"Переглянути всі пристрої"</string>
-    <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="7988547106800504256">"Підключити новий пристрій"</string>
+    <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="7988547106800504256">"Зв’язати новий пристрій"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Підключено до <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Під’єднано до пристрою <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Розгорнути групу"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Додати пристрій у групу."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Вилучити пристрій із групи."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Відкрити додаток"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Не з’єднано."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роумінг"</string>
@@ -308,7 +306,7 @@
     <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Немає спарених пристроїв"</string>
     <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Натисніть, щоб під’єднати або від’єднати пристрій"</string>
-    <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Підключити новий пристрій"</string>
+    <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Зв’язати новий пристрій"</string>
     <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Показати всі"</string>
     <string name="turn_on_bluetooth" msgid="5681370462180289071">"Увімкнути Bluetooth"</string>
     <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Підключено"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Джерело сигналу"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слухові апарати"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Увімкнення…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Не вдається змінити яскравість, оскільки нею керує основний додаток"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автообертання"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично обертати екран"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Геодані"</string>
@@ -418,7 +415,7 @@
     <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Під’єднано"</string>
     <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Від’єднано"</string>
     <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухові апарати"</string>
-    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Підключити новий пристрій"</string>
+    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Зв’язати новий пристрій"</string>
     <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Натисніть, щоб підключити новий пристрій"</string>
     <string name="hearing_devices_presets_error" msgid="350363093458408536">"Не вдалось оновити набір налаштувань"</string>
     <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Набір налаштувань"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додати на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позиція недійсна."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Опцію додано"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Опцію вилучено"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор швидких налаштувань."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Невідомо"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Скинути всі панелі?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Усі панелі швидких налаштувань буде скинуто до стандартних налаштувань пристрою"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ef10b87..41ba6b2 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> سے منسلک ہیں۔"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> سے منسلک ہے۔"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"گروپ کو پھیلائیں۔"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"آلہ کو گروپ شامل کریں۔"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"آلہ کو گروپ سے ہٹائیں"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ایپلیکیشن کھولیں۔"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"مربوط نہیں ہے۔"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"رومنگ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ان پٹ"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سماعتی آلات"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"آن ہو رہا ہے…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"چمک کو ایڈجسٹ نہیں کیا جا سکتا کیونکہ اسے سرفہرست ایپ کے ذریعے کنٹرول کیا جا رہا ہے"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"خود کار طور پر گھمائیں"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"اسکرین کو خود کار طور پر گھمائیں"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"مقام"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g> میں شامل کریں"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"پوزیشن غلط ہے۔"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ٹائل کو شامل کیا گیا"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ٹائل کو ہٹا دیا گیا"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"فوری ترتیبات کا ایڈیٹر۔"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index facc51f..f713ddc 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ulangan: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Bunga ulangan: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Guruhni yoying."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Qurilmani guruhga kiritish."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Qurilmani guruhdan olib tashlash."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ilovani oching."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ulanmagan."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Rouming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Kirish"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Eshitish moslamalari"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Yoqilmoqda…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Yorqinlikni sozlash imkonsiz, chunki tepadago ilova tomonidan boshqariladi"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avto-burilish"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranning avtomatik burilishi"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bu joyga kiritish: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozitsiya yaroqsiz."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Joylashuv: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Katakcha kiritildi"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Katakcha olib tashlandi"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Tezkor sozlamalar muharriri"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Noaniq"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Barcha katakchalar asliga qaytarilsinmi?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Barcha Tezkor sozlamalar katakchalari qurilmaning asl sozlamalariga qaytariladi"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 80db132..2f266a7 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Đã kết nối với <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Đã kết nối với <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Mở rộng nhóm."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Thêm thiết bị vào nhóm."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Xoá thiết bị khỏi nhóm."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Mở ứng dụng."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Chưa được kết nối."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Chuyển vùng"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Thiết bị đầu vào"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Thiết bị trợ thính"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Đang bật…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Không điều chỉnh được độ sáng do ứng dụng ở trên cùng đang điều khiển độ sáng"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Tự động xoay"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Tự động xoay màn hình"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Thêm vào vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Vị trí không hợp lệ."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Đã thêm thẻ thông tin"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Đã xóa thẻ thông tin"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Trình chỉnh sửa cài đặt nhanh."</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Không xác định"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Đặt lại mọi ô?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Mọi ô Cài đặt nhanh sẽ được đặt lại về chế độ cài đặt ban đầu của thiết bị"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index feb3989..480debc 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已连接到<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"已连接到 <xliff:g id="CAST">%s</xliff:g>。"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"展开群组。"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"将设备添加到群组。"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"从群组中移除设备。"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"打开应用。"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"未连接。"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"漫游"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"输入"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助听器"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"正在开启…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"亮度无法调整,因为它正在被顶层应用控制"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自动屏幕旋转"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自动旋转屏幕"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"位置信息"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"添加到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置无效。"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"已添加功能块"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"已移除功能块"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快捷设置编辑器。"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"未知"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重置所有功能块吗?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有“快捷设置”功能块都将重置为设备的原始设置"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>,<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 031df00..bc9e0c5 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"已連接至 <xliff:g id="CAST">%s</xliff:g>。"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"展開群組。"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"將裝置新增至群組。"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"從群組移除裝置。"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"開啟應用程式。"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"未連線。"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"漫遊"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"輸入"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助聽器"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"正在開啟…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"無法調整亮度,因為目前是由上層應用程式控制亮度"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"位置"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"加去位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置冇效。"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"加咗圖塊"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"移除咗圖塊"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快速設定編輯工具。"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重設所有圖塊嗎?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有「快速設定」圖塊將重設為裝置的原始設定"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>,<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index df05577..02fda5a 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"已連線至 <xliff:g id="CAST">%s</xliff:g>。"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"展開群組。"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"將裝置加入群組。"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"從群組中移除裝置。"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"開啟應用程式。"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"尚未連線。"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"漫遊"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"輸入"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助聽器"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"開啟中…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"無法調整亮度,因為目前是由上層應用程式控制亮度"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"定位"</string>
@@ -1006,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"新增到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置無效。"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"已新增設定方塊"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"已移除設定方塊"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快速設定編輯器。"</string>
@@ -1574,6 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重設所有設定方塊嗎?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有快速設定方塊都會恢復裝置的原始設定"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>、<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d571f0e..886cbdf 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -254,10 +254,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Xhuma ku-<xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ixhumeke ku-<xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Nweba iqembu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Faka idivayisi eqenjini."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Susa idivayisi eqenjini."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Vula i-application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Akuxhunyiwe"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Iyazulazula"</string>
@@ -335,8 +333,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Okokufaka"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Imishini yendlebe"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Iyavula..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ayikwazi ukulungisa ukukhanya ngoba ilawulwa yi-app ephezulu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ukuphenduka okuzenzakalelayo"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Phendula iskrini ngokuzenzakalela"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Indawo"</string>
@@ -1008,6 +1005,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engeza kusikhundla se-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Indawo ayivumelekile."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Isikhundla se-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ithayela lingeziwe"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ithayela likhishiwe"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Isihleli sezilungiselelo ezisheshayo."</string>
@@ -1576,6 +1575,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Akwaziwa"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Qala kabusha onke amathayela?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Ithayela Lamasethingi Asheshayo lizosetha kabusha libuyele kumasethingi okuqala edivayisi"</string>
-    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
-    <skip />
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c8e3107..d547bd0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -283,7 +283,7 @@
     <dimen name="notification_max_height">358dp</dimen>
 
     <!-- Height of a large promoted ongoing notification in the status bar -->
-    <dimen name="notification_max_height_for_promoted_ongoing">272dp</dimen>
+    <dimen name="notification_max_height_for_promoted_ongoing">218dp</dimen>
 
     <!-- Height of a heads up notification in the status bar for legacy custom views -->
     <dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
@@ -2166,7 +2166,7 @@
     <dimen name="volume_dialog_background_top_margin">-28dp</dimen>
 
     <dimen name="volume_dialog_window_margin">14dp</dimen>
-    <dimen name="volume_dialog_components_spacing">8dp</dimen>
+    <dimen name="volume_dialog_components_spacing">10dp</dimen>
     <dimen name="volume_dialog_floating_sliders_spacing">8dp</dimen>
     <dimen name="volume_dialog_floating_sliders_vertical_padding">10dp</dimen>
     <dimen name="volume_dialog_floating_sliders_vertical_padding_negative">
@@ -2189,11 +2189,6 @@
     <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
 
     <dimen name="volume_dialog_ringer_drawer_margin">@dimen/volume_dialog_buttons_margin</dimen>
-    <!--
-     (volume_dialog_slider_width - volume_dialog_button_size) / 2
-     This centers ringer drawer against the volume slider
-    -->
-    <dimen name="volume_dialog_ringer_drawer_diff_end_margin">6dp</dimen>
     <dimen name="volume_dialog_ringer_drawer_button_size">@dimen/volume_dialog_button_size</dimen>
     <dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen>
     <dimen name="volume_dialog_ringer_selected_button_background_radius">20dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 786ac69..c06c17a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1042,6 +1042,8 @@
     <string name="hearing_devices_tools_label">Tools</string>
     <!-- QuickSettings: Tool name for hearing devices dialog related tools [CHAR LIMIT=40] [BACKUP_MESSAGE_ID=8916875614623730005]-->
     <string name="quick_settings_hearing_devices_live_caption_title">Live Caption</string>
+    <!-- QuickSettings: Label for button to go to hearing devices settings page [CHAR_LIMIT=20] -->
+    <string name="hearing_devices_settings_button">Settings</string>
 
     <!-- QuickSettings: Notes tile. The label of a quick settings tile for launching the default notes taking app. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_notes_label">Note</string>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index ae3a76e..8d7cab4 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -51,6 +51,7 @@
         ":wm_shell-shared-aidls",
     ],
     static_libs: [
+        "com.android.systemui.dagger-api",
         "BiometricsSharedLib",
         "PlatformAnimationLib",
         "PluginCoreLib",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
index a2b6e2c..f276a82 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
@@ -41,7 +41,7 @@
 constructor(
     private val scope: CoroutineScope,
     private val conditions: Collection<Condition>,
-    @Evaluator.ConditionOperand private val operand: Int
+    @Evaluator.ConditionOperand private val operand: Int,
 ) : Condition(scope, null, false) {
 
     private var job: Job? = null
@@ -54,7 +54,7 @@
 
                 lazilyEvaluate(
                         conditions = groupedConditions.getOrDefault(true, emptyList()),
-                        filterUnknown = true
+                        filterUnknown = true,
                     )
                     .distinctUntilChanged()
                     .flatMapLatest { overriddenValue ->
@@ -62,7 +62,7 @@
                         if (overriddenValue == null) {
                             lazilyEvaluate(
                                 conditions = groupedConditions.getOrDefault(false, emptyList()),
-                                filterUnknown = false
+                                filterUnknown = false,
                             )
                         } else {
                             flowOf(overriddenValue)
@@ -188,7 +188,6 @@
         return startStrategy
     }
 
-    override fun getStartStrategy(): Int {
-        return _startStrategy
-    }
+    override val startStrategy: Int
+        get() = _startStrategy
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
deleted file mode 100644
index 670feeb..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.shared.condition;
-
-import android.util.Log;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleEventObserver;
-import androidx.lifecycle.LifecycleOwner;
-
-import kotlinx.coroutines.CoroutineScope;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Base class for a condition that needs to be fulfilled in order for {@link Monitor} to inform
- * its callbacks.
- */
-public abstract class Condition {
-    private final String mTag = getClass().getSimpleName();
-
-    private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
-    private final boolean mOverriding;
-    private final CoroutineScope mScope;
-    private Boolean mIsConditionMet;
-    private boolean mStarted = false;
-
-    /**
-     * By default, conditions have an initial value of false and are not overriding.
-     */
-    public Condition(CoroutineScope scope) {
-        this(scope, false, false);
-    }
-
-    /**
-     * Constructor for specifying initial state and overriding condition attribute.
-     *
-     * @param initialConditionMet Initial state of the condition.
-     * @param overriding          Whether this condition overrides others.
-     */
-    protected Condition(CoroutineScope scope, Boolean initialConditionMet, boolean overriding) {
-        mIsConditionMet = initialConditionMet;
-        mOverriding = overriding;
-        mScope = scope;
-    }
-
-    /**
-     * Starts monitoring the condition.
-     */
-    protected abstract void start();
-
-    /**
-     * Stops monitoring the condition.
-     */
-    protected abstract void stop();
-
-    /**
-     * Condition should be started as soon as there is an active subscription.
-     */
-    public static final int START_EAGERLY = 0;
-    /**
-     * Condition should be started lazily only if needed. But once started, it will not be cancelled
-     * unless there are no more active subscriptions.
-     */
-    public static final int START_LAZILY = 1;
-    /**
-     * Condition should be started lazily only if needed, and can be stopped when not needed. This
-     * should be used for conditions which are expensive to keep running.
-     */
-    public static final int START_WHEN_NEEDED = 2;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({START_EAGERLY, START_LAZILY, START_WHEN_NEEDED})
-    @interface StartStrategy {
-    }
-
-    @StartStrategy
-    protected abstract int getStartStrategy();
-
-    /**
-     * Returns whether the current condition overrides
-     */
-    public boolean isOverridingCondition() {
-        return mOverriding;
-    }
-
-    /**
-     * Registers a callback to receive updates once started. This should be called before
-     * {@link #start()}. Also triggers the callback immediately if already started.
-     */
-    public void addCallback(@NonNull Callback callback) {
-        if (shouldLog()) Log.d(mTag, "adding callback");
-        mCallbacks.add(new WeakReference<>(callback));
-
-        if (mStarted) {
-            callback.onConditionChanged(this);
-            return;
-        }
-
-        start();
-        mStarted = true;
-    }
-
-    /**
-     * Removes the provided callback from further receiving updates.
-     */
-    public void removeCallback(@NonNull Callback callback) {
-        if (shouldLog()) Log.d(mTag, "removing callback");
-        final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
-        while (iterator.hasNext()) {
-            final Callback cb = iterator.next().get();
-            if (cb == null || cb == callback) {
-                iterator.remove();
-            }
-        }
-
-        if (!mCallbacks.isEmpty() || !mStarted) {
-            return;
-        }
-
-        stop();
-        mStarted = false;
-    }
-
-    /**
-     * Wrapper to {@link #addCallback(Callback)} when a lifecycle is in the resumed state
-     * and {@link #removeCallback(Callback)} when not resumed automatically.
-     */
-    public Callback observe(LifecycleOwner owner, Callback listener) {
-        return observe(owner.getLifecycle(), listener);
-    }
-
-    /**
-     * Wrapper to {@link #addCallback(Callback)} when a lifecycle is in the resumed state
-     * and {@link #removeCallback(Condition.Callback)} when not resumed automatically.
-     */
-    public Callback observe(Lifecycle lifecycle, Callback listener) {
-        lifecycle.addObserver((LifecycleEventObserver) (lifecycleOwner, event) -> {
-            if (event == Lifecycle.Event.ON_RESUME) {
-                addCallback(listener);
-            } else if (event == Lifecycle.Event.ON_PAUSE) {
-                removeCallback(listener);
-            }
-        });
-        return listener;
-    }
-
-    /**
-     * Updates the value for whether the condition has been fulfilled, and sends an update if the
-     * value changes and any callback is registered.
-     *
-     * @param isConditionMet True if the condition has been fulfilled. False otherwise.
-     */
-    protected void updateCondition(boolean isConditionMet) {
-        if (mIsConditionMet != null && mIsConditionMet == isConditionMet) {
-            return;
-        }
-
-        if (shouldLog()) Log.d(mTag, "updating condition to " + isConditionMet);
-        mIsConditionMet = isConditionMet;
-        sendUpdate();
-    }
-
-    /**
-     * Clears the set condition value. This is purposefully separate from
-     * {@link #updateCondition(boolean)} to avoid confusion around {@code null} values.
-     */
-    protected void clearCondition() {
-        if (mIsConditionMet == null) {
-            return;
-        }
-
-        if (shouldLog()) Log.d(mTag, "clearing condition");
-
-        mIsConditionMet = null;
-        sendUpdate();
-    }
-
-    private void sendUpdate() {
-        final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
-        while (iterator.hasNext()) {
-            final Callback cb = iterator.next().get();
-            if (cb == null) {
-                iterator.remove();
-            } else {
-                cb.onConditionChanged(this);
-            }
-        }
-    }
-
-    /**
-     * Returns whether the condition is set. This method should be consulted to understand the
-     * value of {@link #isConditionMet()}.
-     *
-     * @return {@code true} if value is present, {@code false} otherwise.
-     */
-    public boolean isConditionSet() {
-        return mIsConditionMet != null;
-    }
-
-    /**
-     * Returns whether the condition has been met. Note that this method will return {@code false}
-     * if the condition is not set as well.
-     */
-    public boolean isConditionMet() {
-        return Boolean.TRUE.equals(mIsConditionMet);
-    }
-
-    protected final boolean shouldLog() {
-        return Log.isLoggable(mTag, Log.DEBUG);
-    }
-
-    protected final String getTag() {
-        if (isOverridingCondition()) {
-            return mTag + "[OVRD]";
-        }
-
-        return mTag;
-    }
-
-    /**
-     * Returns the state of the condition.
-     * - "Invalid", condition hasn't been set / not monitored
-     * - "True", condition has been met
-     * - "False", condition has not been met
-     */
-    protected final String getState() {
-        if (!isConditionSet()) {
-            return "Invalid";
-        }
-        return isConditionMet() ? "True" : "False";
-    }
-
-    /**
-     * Creates a new condition which will only be true when both this condition and all the provided
-     * conditions are true.
-     */
-    public Condition and(@NonNull Collection<Condition> others) {
-        final List<Condition> conditions = new ArrayList<>();
-        conditions.add(this);
-        conditions.addAll(others);
-        return new CombinedCondition(mScope, conditions, Evaluator.OP_AND);
-    }
-
-    /**
-     * Creates a new condition which will only be true when both this condition and the provided
-     * condition is true.
-     */
-    public Condition and(@NonNull Condition... others) {
-        return and(Arrays.asList(others));
-    }
-
-    /**
-     * Creates a new condition which will only be true when either this condition or any of the
-     * provided conditions are true.
-     */
-    public Condition or(@NonNull Collection<Condition> others) {
-        final List<Condition> conditions = new ArrayList<>();
-        conditions.add(this);
-        conditions.addAll(others);
-        return new CombinedCondition(mScope, conditions, Evaluator.OP_OR);
-    }
-
-    /**
-     * Creates a new condition which will only be true when either this condition or the provided
-     * condition is true.
-     */
-    public Condition or(@NonNull Condition... others) {
-        return or(Arrays.asList(others));
-    }
-
-    /**
-     * Callback that receives updates about whether the condition has been fulfilled.
-     */
-    public interface Callback {
-        /**
-         * Called when the fulfillment of the condition changes.
-         *
-         * @param condition The condition in question.
-         */
-        void onConditionChanged(Condition condition);
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.kt
new file mode 100644
index 0000000..69236b4
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.kt
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.condition
+
+import android.util.Log
+import androidx.annotation.IntDef
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.LifecycleOwner
+import java.lang.ref.WeakReference
+import kotlinx.coroutines.CoroutineScope
+
+/**
+ * Base class for a condition that needs to be fulfilled in order for [Monitor] to inform its
+ * callbacks.
+ */
+abstract class Condition
+/**
+ * Constructor for specifying initial state and overriding condition attribute.
+ *
+ * @param initialConditionMet Initial state of the condition.
+ * @param overriding Whether this condition overrides others.
+ */
+@JvmOverloads
+protected constructor(
+    private val _scope: CoroutineScope,
+    private var _isConditionMet: Boolean? = false,
+    /** Returns whether the current condition overrides */
+    val isOverridingCondition: Boolean = false,
+) {
+    private val mTag: String = javaClass.simpleName
+
+    private val _callbacks = mutableListOf<WeakReference<Callback>>()
+    private var _started = false
+
+    /** Starts monitoring the condition. */
+    protected abstract fun start()
+
+    /** Stops monitoring the condition. */
+    protected abstract fun stop()
+
+    @Retention(AnnotationRetention.SOURCE)
+    @IntDef(START_EAGERLY, START_LAZILY, START_WHEN_NEEDED)
+    annotation class StartStrategy
+
+    @get:StartStrategy abstract val startStrategy: Int
+
+    /**
+     * Registers a callback to receive updates once started. This should be called before [.start].
+     * Also triggers the callback immediately if already started.
+     */
+    fun addCallback(callback: Callback) {
+        if (shouldLog()) Log.d(mTag, "adding callback")
+        _callbacks.add(WeakReference(callback))
+
+        if (_started) {
+            callback.onConditionChanged(this)
+            return
+        }
+
+        start()
+        _started = true
+    }
+
+    /** Removes the provided callback from further receiving updates. */
+    fun removeCallback(callback: Callback) {
+        if (shouldLog()) Log.d(mTag, "removing callback")
+        val iterator = _callbacks.iterator()
+        while (iterator.hasNext()) {
+            val cb = iterator.next().get()
+            if (cb == null || cb === callback) {
+                iterator.remove()
+            }
+        }
+
+        if (_callbacks.isNotEmpty() || !_started) {
+            return
+        }
+
+        stop()
+        _started = false
+    }
+
+    /**
+     * Wrapper to [.addCallback] when a lifecycle is in the resumed state and [.removeCallback] when
+     * not resumed automatically.
+     */
+    fun observe(owner: LifecycleOwner, listener: Callback): Callback {
+        return observe(owner.lifecycle, listener)
+    }
+
+    /**
+     * Wrapper to [.addCallback] when a lifecycle is in the resumed state and [.removeCallback] when
+     * not resumed automatically.
+     */
+    fun observe(lifecycle: Lifecycle, listener: Callback): Callback {
+        lifecycle.addObserver(
+            LifecycleEventObserver { lifecycleOwner: LifecycleOwner?, event: Lifecycle.Event ->
+                if (event == Lifecycle.Event.ON_RESUME) {
+                    addCallback(listener)
+                } else if (event == Lifecycle.Event.ON_PAUSE) {
+                    removeCallback(listener)
+                }
+            }
+        )
+        return listener
+    }
+
+    /**
+     * Updates the value for whether the condition has been fulfilled, and sends an update if the
+     * value changes and any callback is registered.
+     *
+     * @param isConditionMet True if the condition has been fulfilled. False otherwise.
+     */
+    protected fun updateCondition(isConditionMet: Boolean) {
+        if (_isConditionMet != null && _isConditionMet == isConditionMet) {
+            return
+        }
+
+        if (shouldLog()) Log.d(mTag, "updating condition to $isConditionMet")
+        _isConditionMet = isConditionMet
+        sendUpdate()
+    }
+
+    /**
+     * Clears the set condition value. This is purposefully separate from [.updateCondition] to
+     * avoid confusion around `null` values.
+     */
+    fun clearCondition() {
+        if (_isConditionMet == null) {
+            return
+        }
+
+        if (shouldLog()) Log.d(mTag, "clearing condition")
+
+        _isConditionMet = null
+        sendUpdate()
+    }
+
+    private fun sendUpdate() {
+        val iterator = _callbacks.iterator()
+        while (iterator.hasNext()) {
+            val cb = iterator.next().get()
+            if (cb == null) {
+                iterator.remove()
+            } else {
+                cb.onConditionChanged(this)
+            }
+        }
+    }
+
+    val isConditionSet: Boolean
+        /**
+         * Returns whether the condition is set. This method should be consulted to understand the
+         * value of [.isConditionMet].
+         *
+         * @return `true` if value is present, `false` otherwise.
+         */
+        get() = _isConditionMet != null
+
+    val isConditionMet: Boolean
+        /**
+         * Returns whether the condition has been met. Note that this method will return `false` if
+         * the condition is not set as well.
+         */
+        get() = true == _isConditionMet
+
+    protected fun shouldLog(): Boolean {
+        return Log.isLoggable(mTag, Log.DEBUG)
+    }
+
+    val tag: String
+        get() {
+            if (isOverridingCondition) {
+                return "$mTag[OVRD]"
+            }
+
+            return mTag
+        }
+
+    val state: String
+        /**
+         * Returns the state of the condition.
+         * - "Invalid", condition hasn't been set / not monitored
+         * - "True", condition has been met
+         * - "False", condition has not been met
+         */
+        get() {
+            if (!isConditionSet) {
+                return "Invalid"
+            }
+            return if (isConditionMet) "True" else "False"
+        }
+
+    /**
+     * Creates a new condition which will only be true when both this condition and all the provided
+     * conditions are true.
+     */
+    fun and(others: Collection<Condition>): Condition {
+        val conditions: List<Condition> = listOf(this, *others.toTypedArray())
+        return CombinedCondition(_scope, conditions, Evaluator.OP_AND)
+    }
+
+    /**
+     * Creates a new condition which will only be true when both this condition and the provided
+     * condition is true.
+     */
+    fun and(vararg others: Condition): Condition {
+        return and(listOf(*others))
+    }
+
+    /**
+     * Creates a new condition which will only be true when either this condition or any of the
+     * provided conditions are true.
+     */
+    fun or(others: Collection<Condition>): Condition {
+        val conditions: MutableList<Condition> = ArrayList()
+        conditions.add(this)
+        conditions.addAll(others)
+        return CombinedCondition(_scope, conditions, Evaluator.OP_OR)
+    }
+
+    /**
+     * Creates a new condition which will only be true when either this condition or the provided
+     * condition is true.
+     */
+    fun or(vararg others: Condition): Condition {
+        return or(listOf(*others))
+    }
+
+    /** Callback that receives updates about whether the condition has been fulfilled. */
+    fun interface Callback {
+        /**
+         * Called when the fulfillment of the condition changes.
+         *
+         * @param condition The condition in question.
+         */
+        fun onConditionChanged(condition: Condition)
+    }
+
+    companion object {
+        /** Condition should be started as soon as there is an active subscription. */
+        const val START_EAGERLY: Int = 0
+
+        /**
+         * Condition should be started lazily only if needed. But once started, it will not be
+         * cancelled unless there are no more active subscriptions.
+         */
+        const val START_LAZILY: Int = 1
+
+        /**
+         * Condition should be started lazily only if needed, and can be stopped when not needed.
+         * This should be used for conditions which are expensive to keep running.
+         */
+        const val START_WHEN_NEEDED: Int = 2
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
index 84edc35..0f535cd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
@@ -14,7 +14,7 @@
 fun Flow<Boolean>.toCondition(
     scope: CoroutineScope,
     @StartStrategy strategy: Int,
-    initialValue: Boolean? = null
+    initialValue: Boolean? = null,
 ): Condition {
     return object : Condition(scope, initialValue, false) {
         var job: Job? = null
@@ -28,7 +28,8 @@
             job = null
         }
 
-        override fun getStartStrategy() = strategy
+        override val startStrategy: Int
+            get() = strategy
     }
 }
 
@@ -36,13 +37,16 @@
 fun Condition.toFlow(): Flow<Boolean?> {
     return callbackFlow {
             val callback =
-                Condition.Callback { condition ->
-                    if (condition.isConditionSet) {
-                        trySend(condition.isConditionMet)
-                    } else {
-                        trySend(null)
+                object : Condition.Callback {
+                    override fun onConditionChanged(condition: Condition) {
+                        if (condition.isConditionSet) {
+                            trySend(condition.isConditionMet)
+                        } else {
+                            trySend(null)
+                        }
                     }
                 }
+
             addCallback(callback)
             callback.onConditionChanged(this@toFlow)
             awaitClose { removeCallback(callback) }
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index dcbacec..c880f05 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -203,7 +203,9 @@
             CarrierTextManagerLogger logger) {
 
         mContext = context;
-        mIsEmergencyCallCapable = telephonyManager.isVoiceCapable();
+        boolean hasTelephony = mContext.getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+        mIsEmergencyCallCapable = telephonyManager.isVoiceCapable() && hasTelephony;
 
         mShowAirplaneMode = showAirplaneMode;
         mShowMissingSim = showMissingSim;
@@ -221,9 +223,7 @@
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLogger = logger;
         mBgExecutor.execute(() -> {
-            boolean supported = mContext.getPackageManager()
-                    .hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-            if (supported && mNetworkSupported.compareAndSet(false, supported)) {
+            if (hasTelephony && mNetworkSupported.compareAndSet(false, hasTelephony)) {
                 // This will set/remove the listeners appropriately. Note that it will never double
                 // add the listeners.
                 handleSetListening(mCarrierTextCallback);
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index e827b2d..1549b69 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -56,6 +56,7 @@
 import com.android.systemui.modes.shared.ModesUi
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockEventListener
 import com.android.systemui.plugins.clocks.ClockFaceController
 import com.android.systemui.plugins.clocks.ClockMessageBuffers
 import com.android.systemui.plugins.clocks.ClockTickRate
@@ -148,7 +149,7 @@
         val clockStr = clock.toString()
         loggers.forEach { it.d({ "New Clock: $str1" }) { str1 = clockStr } }
 
-        clock.initialize(isDarkTheme(), dozeAmount.value, 0f, { onClockBoundsChanged.value = it })
+        clock.initialize(isDarkTheme(), dozeAmount.value, 0f, clockListener)
 
         if (!regionSamplingEnabled) {
             updateColors()
@@ -312,6 +313,13 @@
     private var zenData: ZenData? = null
     private var alarmData: AlarmData? = null
 
+    private val clockListener =
+        object : ClockEventListener {
+            override fun onBoundsChanged(bounds: RectF) {
+                onClockBoundsChanged.value = bounds
+            }
+        }
+
     private val configListener =
         object : ConfigurationController.ConfigurationListener {
             override fun onThemeChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 4a8e4ed..f72087e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -32,6 +32,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationModeController;
@@ -42,7 +43,6 @@
 import com.android.systemui.recents.LauncherProxyService;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
diff --git a/packages/SystemUI/src/com/android/systemui/KairosActivatable.kt b/packages/SystemUI/src/com/android/systemui/KairosActivatable.kt
index 5e29ba9..442d4ab 100644
--- a/packages/SystemUI/src/com/android/systemui/KairosActivatable.kt
+++ b/packages/SystemUI/src/com/android/systemui/KairosActivatable.kt
@@ -19,23 +19,28 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.BuildSpec
 import com.android.systemui.kairos.Events
 import com.android.systemui.kairos.EventsLoop
 import com.android.systemui.kairos.ExperimentalKairosApi
 import com.android.systemui.kairos.Incremental
 import com.android.systemui.kairos.IncrementalLoop
 import com.android.systemui.kairos.KairosNetwork
+import com.android.systemui.kairos.RootKairosNetwork
 import com.android.systemui.kairos.State
 import com.android.systemui.kairos.StateLoop
+import com.android.systemui.kairos.TransactionScope
+import com.android.systemui.kairos.activateSpec
+import com.android.systemui.kairos.effect
 import com.android.systemui.kairos.launchKairosNetwork
 import com.android.systemui.kairos.launchScope
 import dagger.Binds
 import dagger.Module
-import dagger.Provides
 import dagger.multibindings.ClassKey
 import dagger.multibindings.IntoMap
 import dagger.multibindings.Multibinds
 import javax.inject.Inject
+import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 
@@ -176,21 +181,40 @@
 @SysUISingleton
 @ExperimentalKairosApi
 class KairosCoreStartable
-@Inject
-constructor(
-    @Application private val appScope: CoroutineScope,
-    private val kairosNetwork: KairosNetwork,
+private constructor(
+    private val appScope: CoroutineScope,
     private val activatables: dagger.Lazy<Set<@JvmSuppressWildcards KairosActivatable>>,
-) : CoreStartable {
+    private val unwrappedNetwork: RootKairosNetwork,
+) : CoreStartable, KairosNetwork by unwrappedNetwork {
+
+    @Inject
+    constructor(
+        @Application appScope: CoroutineScope,
+        activatables: dagger.Lazy<Set<@JvmSuppressWildcards KairosActivatable>>,
+    ) : this(appScope, activatables, appScope.launchKairosNetwork())
+
+    private val started = CompletableDeferred<Unit>()
+
     override fun start() {
         appScope.launch {
-            kairosNetwork.activateSpec {
+            unwrappedNetwork.activateSpec {
                 for (activatable in activatables.get()) {
                     launchScope { activatable.run { activate() } }
                 }
+                effect { started.complete(Unit) }
             }
         }
     }
+
+    override suspend fun activateSpec(spec: BuildSpec<*>) {
+        started.await()
+        unwrappedNetwork.activateSpec(spec)
+    }
+
+    override suspend fun <R> transact(block: TransactionScope.() -> R): R {
+        started.await()
+        return unwrappedNetwork.transact(block)
+    }
 }
 
 @Module
@@ -203,10 +227,5 @@
 
     @Multibinds fun kairosActivatables(): Set<@JvmSuppressWildcards KairosActivatable>
 
-    companion object {
-        @Provides
-        @SysUISingleton
-        fun provideKairosNetwork(@Application scope: CoroutineScope): KairosNetwork =
-            scope.launchKairosNetwork()
-    }
+    @Binds fun bindKairosNetwork(impl: KairosCoreStartable): KairosNetwork
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java
index 2d1cd03..20290f7 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java
@@ -99,10 +99,7 @@
 
     private boolean isExclusivelyManagedBluetoothDevice(
             @NonNull CachedBluetoothDevice cachedDevice) {
-        if (com.android.settingslib.flags.Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            return BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
-                    cachedDevice.getDevice());
-        }
-        return false;
+        return BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
+                cachedDevice.getDevice());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index b730c93..fb3bc62 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -19,6 +19,8 @@
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 
+import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
+
 import static java.util.Collections.emptyList;
 
 import android.bluetooth.BluetoothHapClient;
@@ -61,7 +63,7 @@
 import com.android.systemui.animation.DialogTransitionAnimator;
 import com.android.systemui.bluetooth.qsdialog.ActiveHearingDeviceItemFactory;
 import com.android.systemui.bluetooth.qsdialog.AvailableHearingDeviceItemFactory;
-import com.android.systemui.bluetooth.qsdialog.ConnectedDeviceItemFactory;
+import com.android.systemui.bluetooth.qsdialog.ConnectedHearingDeviceItemFactory;
 import com.android.systemui.bluetooth.qsdialog.DeviceItem;
 import com.android.systemui.bluetooth.qsdialog.DeviceItemFactory;
 import com.android.systemui.bluetooth.qsdialog.DeviceItemType;
@@ -69,6 +71,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.shared.QSSettingsPackageRepository;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
@@ -109,6 +112,7 @@
     private final HearingDevicesUiEventLogger mUiEventLogger;
     private final boolean mShowPairNewDevice;
     private final int mLaunchSourceId;
+    private final QSSettingsPackageRepository mQSSettingsPackageRepository;
 
     private SystemUIDialog mDialog;
     private HearingDevicesListAdapter mDeviceListAdapter;
@@ -140,12 +144,7 @@
     private final List<DeviceItemFactory> mHearingDeviceItemFactoryList = List.of(
             new ActiveHearingDeviceItemFactory(),
             new AvailableHearingDeviceItemFactory(),
-            // TODO(b/331305850): setHearingAidInfo() for connected but not connect to profile
-            // hearing device only called from
-            // settings/bluetooth/DeviceListPreferenceFragment#handleLeScanResult, so we don't know
-            // it is connected but not yet connect to profile hearing device in systemui.
-            // Show all connected but not connect to profile bluetooth device for now.
-            new ConnectedDeviceItemFactory(),
+            new ConnectedHearingDeviceItemFactory(),
             new SavedHearingDeviceItemFactory()
     );
 
@@ -169,7 +168,8 @@
             @Main Executor mainExecutor,
             @Background Executor bgExecutor,
             AudioManager audioManager,
-            HearingDevicesUiEventLogger uiEventLogger) {
+            HearingDevicesUiEventLogger uiEventLogger,
+            QSSettingsPackageRepository qsSettingsPackageRepository) {
         mShowPairNewDevice = showPairNewDevice;
         mSystemUIDialogFactory = systemUIDialogFactory;
         mActivityStarter = activityStarter;
@@ -181,6 +181,7 @@
         mProfileManager = localBluetoothManager.getProfileManager();
         mUiEventLogger = uiEventLogger;
         mLaunchSourceId = launchSourceId;
+        mQSSettingsPackageRepository = qsSettingsPackageRepository;
     }
 
     @Override
@@ -196,11 +197,11 @@
     public void onDeviceItemGearClicked(@NonNull DeviceItem deviceItem, @NonNull View view) {
         mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_GEAR_CLICK, mLaunchSourceId);
         dismissDialogIfExists();
-        Intent intent = new Intent(ACTION_BLUETOOTH_DEVICE_DETAILS);
         Bundle bundle = new Bundle();
         bundle.putString(KEY_BLUETOOTH_ADDRESS, deviceItem.getCachedBluetoothDevice().getAddress());
-        intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        Intent intent = new Intent(ACTION_BLUETOOTH_DEVICE_DETAILS)
+                .setPackage(mQSSettingsPackageRepository.getSettingsPackageName())
+                .putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle);
         mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
                 mDialogTransitionAnimator.createActivityTransitionController(view));
     }
@@ -263,6 +264,20 @@
         dialog.setTitle(R.string.quick_settings_hearing_devices_dialog_title);
         dialog.setView(LayoutInflater.from(dialog.getContext()).inflate(
                 R.layout.hearing_devices_tile_dialog, null));
+        dialog.setNegativeButton(
+                R.string.hearing_devices_settings_button,
+                (dialogInterface, which) -> {
+                    mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_SETTINGS_CLICK,
+                            mLaunchSourceId);
+                    final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS)
+                            .putExtra(Intent.EXTRA_COMPONENT_NAME,
+                                    ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
+                    mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
+                            mDialogTransitionAnimator.createActivityTransitionController(
+                                    dialog));
+                },
+                /* dismissOnClick = */ true
+        );
         dialog.setPositiveButton(
                 R.string.quick_settings_done,
                 /* onClick = */ null,
@@ -385,8 +400,8 @@
             pairButton.setOnClickListener(v -> {
                 mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PAIR, mLaunchSourceId);
                 dismissDialogIfExists();
-                final Intent intent = new Intent(Settings.ACTION_HEARING_DEVICE_PAIRING_SETTINGS);
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                final Intent intent = new Intent(Settings.ACTION_HEARING_DEVICE_PAIRING_SETTINGS)
+                        .setPackage(mQSSettingsPackageRepository.getSettingsPackageName());
                 mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
                         mDialogTransitionAnimator.createActivityTransitionController(dialog));
             });
@@ -507,8 +522,9 @@
                     com.android.internal.R.color.materialColorOnPrimaryContainer));
         }
         text.setText(item.getToolName());
-        Intent intent = item.getToolIntent();
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        Intent intent = item.getToolIntent()
+                .setPackage(mQSSettingsPackageRepository.getSettingsPackageName());
+
         view.setOnClickListener(v -> {
             final String name = intent.getComponent() != null
                     ? intent.getComponent().flattenToString()
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt
index fe1d504..4a695d6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt
@@ -39,7 +39,9 @@
     @UiEvent(doc = "Expand the ambient volume controls")
     HEARING_DEVICES_AMBIENT_EXPAND_CONTROLS(2153),
     @UiEvent(doc = "Collapse the ambient volume controls")
-    HEARING_DEVICES_AMBIENT_COLLAPSE_CONTROLS(2154);
+    HEARING_DEVICES_AMBIENT_COLLAPSE_CONTROLS(2154),
+    @UiEvent(doc = "Click on the device settings to enter hearing devices page")
+    HEARING_DEVICES_SETTINGS_CLICK(2172);
 
     override fun getId(): Int = this.id
 }
diff --git a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
index 0b578c6..113df20 100644
--- a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
@@ -122,6 +122,10 @@
         return false
     }
 
+    fun isBackCallbackRegistered(): Boolean {
+        return isCallbackRegistered
+    }
+
     private fun registerBackCallback() {
         if (isCallbackRegistered) {
             return
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
index bfbc27d..208e498 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
@@ -21,7 +21,6 @@
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
-import com.android.settingslib.flags.Flags
 import com.android.systemui.res.R
 
 private val backgroundOn = R.drawable.settingslib_switch_bar_bg_on
@@ -215,19 +214,15 @@
     }
 }
 
-internal class ConnectedDeviceItemFactory : DeviceItemFactory() {
+internal open class ConnectedDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
         isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
-        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
-                BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, isOngoingCall)
-        } else {
+        return !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
             BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, isOngoingCall)
-        }
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -243,6 +238,19 @@
     }
 }
 
+internal class ConnectedHearingDeviceItemFactory : ConnectedDeviceItemFactory() {
+    override fun isFilterMatched(
+        context: Context,
+        cachedDevice: CachedBluetoothDevice,
+        isOngoingCall: Boolean,
+        audioSharingAvailable: Boolean,
+    ): Boolean {
+        return cachedDevice.isHearingDevice &&
+            cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
+            cachedDevice.device.isConnected
+    }
+}
+
 internal open class SavedDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
         context: Context,
@@ -250,13 +258,9 @@
         isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
-        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
-                cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
-                !cachedDevice.isConnected
-        } else {
-            cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
-        }
+        return !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
+            cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
+            !cachedDevice.isConnected
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -279,18 +283,12 @@
         isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
-        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
-                context,
-                cachedDevice.getDevice(),
-            ) &&
-                cachedDevice.isHearingAidDevice &&
-                cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
-                !cachedDevice.isConnected
-        } else {
-            cachedDevice.isHearingAidDevice &&
-                cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
-                !cachedDevice.isConnected
-        }
+        return !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
+            context,
+            cachedDevice.getDevice(),
+        ) &&
+            cachedDevice.isHearingDevice &&
+            cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
+            !cachedDevice.isConnected
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index 52204b8..6aeb35b 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.view.MotionEvent
 import androidx.annotation.VisibleForTesting
+import androidx.compose.animation.animateColorAsState
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationVector1D
 import androidx.compose.animation.core.VectorConverter
@@ -40,6 +41,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
@@ -323,7 +325,7 @@
 fun BrightnessSliderContainer(
     viewModel: BrightnessSliderViewModel,
     modifier: Modifier = Modifier,
-    containerColor: Color = colorResource(R.color.shade_scrim_background_dark),
+    containerColors: ContainerColors,
 ) {
     val gamma = viewModel.currentBrightness.value
     if (gamma == BrightnessSliderViewModel.initialValue.value) { // Ignore initial negative value.
@@ -344,6 +346,16 @@
 
     DisposableEffect(Unit) { onDispose { viewModel.setIsDragging(false) } }
 
+    var dragging by remember { mutableStateOf(false) }
+
+    // Use dragging instead of viewModel.showMirror so the color starts changing as soon as the
+    // dragging state changes. If not, we may be waiting for the background to finish fading in
+    // when stopping dragging
+    val containerColor by
+        animateColorAsState(
+            if (dragging) containerColors.mirrorColor else containerColors.idleColor
+        )
+
     Box(
         modifier =
             modifier
@@ -360,10 +372,12 @@
             onRestrictedClick = viewModel::showPolicyRestrictionDialog,
             onDrag = {
                 viewModel.setIsDragging(true)
+                dragging = true
                 coroutineScope.launch { viewModel.onDrag(Drag.Dragging(GammaBrightness(it))) }
             },
             onStop = {
                 viewModel.setIsDragging(false)
+                dragging = false
                 coroutineScope.launch { viewModel.onDrag(Drag.Stopped(GammaBrightness(it))) }
             },
             modifier =
@@ -392,6 +406,15 @@
     }
 }
 
+data class ContainerColors(val idleColor: Color, val mirrorColor: Color) {
+    companion object {
+        fun singleColor(color: Color) = ContainerColors(color, color)
+
+        val defaultContainerColor: Color
+            @Composable @ReadOnlyComposable get() = colorResource(R.color.shade_panel_fallback)
+    }
+}
+
 private object Dimensions {
     val SliderBackgroundFrameSize = DpSize(10.dp, 6.dp)
     val SliderBackgroundRoundedCorner = 24.dp
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ActionIntentCreator.kt
new file mode 100644
index 0000000..df6c1b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ActionIntentCreator.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.clipboardoverlay
+
+import android.content.ClipData
+import android.content.ClipDescription
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.text.TextUtils
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+@SysUISingleton
+class ActionIntentCreator @Inject constructor() : IntentCreator {
+    override fun getTextEditorIntent(context: Context?) =
+        Intent(context, EditTextActivity::class.java).apply {
+            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+        }
+
+    override fun getShareIntent(clipData: ClipData, context: Context?): Intent {
+        val shareIntent = Intent(Intent.ACTION_SEND)
+
+        // From the ACTION_SEND docs:
+        //   "If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the
+        //    MIME type of the data in EXTRA_STREAM"
+        val uri = clipData.getItemAt(0).uri
+        shareIntent.apply {
+            if (uri != null) {
+                // We don't use setData here because some apps interpret this as "to:".
+                setType(clipData.description.getMimeType(0))
+                // Include URI in ClipData also, so that grantPermission picks it up.
+                setClipData(
+                    ClipData(
+                        ClipDescription("content", arrayOf(clipData.description.getMimeType(0))),
+                        ClipData.Item(uri),
+                    )
+                )
+                putExtra(Intent.EXTRA_STREAM, uri)
+                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            } else {
+                putExtra(Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context).toString())
+                setType("text/plain")
+            }
+        }
+
+        return Intent.createChooser(shareIntent, null)
+            .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
+            .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+    }
+
+    override fun getImageEditIntent(uri: Uri?, context: Context): Intent {
+        val editorPackage = context.getString(R.string.config_screenshotEditor)
+        return Intent(Intent.ACTION_EDIT).apply {
+            if (!TextUtils.isEmpty(editorPackage)) {
+                setComponent(ComponentName.unflattenFromString(editorPackage))
+            }
+            setDataAndType(uri, "image/*")
+            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+            putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_CLIPBOARD)
+        }
+    }
+
+    override fun getRemoteCopyIntent(clipData: ClipData?, context: Context): Intent {
+        val remoteCopyPackage = context.getString(R.string.config_remoteCopyPackage)
+        return Intent(REMOTE_COPY_ACTION).apply {
+            if (!TextUtils.isEmpty(remoteCopyPackage)) {
+                setComponent(ComponentName.unflattenFromString(remoteCopyPackage))
+            }
+
+            setClipData(clipData)
+            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+        }
+    }
+
+    companion object {
+        private const val EXTRA_EDIT_SOURCE: String = "edit_source"
+        private const val EDIT_SOURCE_CLIPBOARD: String = "clipboard"
+        private const val REMOTE_COPY_ACTION: String = "android.intent.action.REMOTE_COPY"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index ac74784..314b6e7 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -65,7 +65,6 @@
 import com.android.systemui.broadcast.BroadcastSender;
 import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule.OverlayWindowContext;
 import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.res.R;
 import com.android.systemui.screenshot.TimeoutHandler;
 
@@ -94,13 +93,13 @@
     private final ClipboardOverlayWindow mWindow;
     private final TimeoutHandler mTimeoutHandler;
     private final ClipboardOverlayUtils mClipboardUtils;
-    private final FeatureFlags mFeatureFlags;
     private final Executor mBgExecutor;
     private final ClipboardImageLoader mClipboardImageLoader;
     private final ClipboardTransitionExecutor mTransitionExecutor;
 
     private final ClipboardOverlayView mView;
     private final ClipboardIndicationProvider mClipboardIndicationProvider;
+    private final IntentCreator mIntentCreator;
 
     private Runnable mOnSessionCompleteListener;
     private Runnable mOnRemoteCopyTapped;
@@ -189,13 +188,13 @@
             BroadcastDispatcher broadcastDispatcher,
             BroadcastSender broadcastSender,
             TimeoutHandler timeoutHandler,
-            FeatureFlags featureFlags,
             ClipboardOverlayUtils clipboardUtils,
             @Background Executor bgExecutor,
             ClipboardImageLoader clipboardImageLoader,
             ClipboardTransitionExecutor transitionExecutor,
             ClipboardIndicationProvider clipboardIndicationProvider,
-            UiEventLogger uiEventLogger) {
+            UiEventLogger uiEventLogger,
+            IntentCreator intentCreator) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
         mClipboardImageLoader = clipboardImageLoader;
@@ -203,6 +202,7 @@
         mClipboardIndicationProvider = clipboardIndicationProvider;
 
         mClipboardLogger = new ClipboardLogger(uiEventLogger);
+        mIntentCreator = intentCreator;
 
         mView = clipboardOverlayView;
         mWindow = clipboardOverlayWindow;
@@ -211,7 +211,6 @@
             hideImmediate();
         });
 
-        mFeatureFlags = featureFlags;
         mTimeoutHandler = timeoutHandler;
         mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS);
 
@@ -508,7 +507,8 @@
     }
 
     private void maybeShowRemoteCopy(ClipData clipData) {
-        Intent remoteCopyIntent = IntentCreator.getRemoteCopyIntent(clipData, mContext);
+        Intent remoteCopyIntent = mIntentCreator.getRemoteCopyIntent(clipData, mContext);
+
         // Only show remote copy if it's available.
         PackageManager packageManager = mContext.getPackageManager();
         if (packageManager.resolveActivity(
@@ -558,19 +558,19 @@
 
     private void editImage(Uri uri) {
         mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
-        mContext.startActivity(IntentCreator.getImageEditIntent(uri, mContext));
+        mContext.startActivity(mIntentCreator.getImageEditIntent(uri, mContext));
         animateOut();
     }
 
     private void editText() {
         mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
-        mContext.startActivity(IntentCreator.getTextEditorIntent(mContext));
+        mContext.startActivity(mIntentCreator.getTextEditorIntent(mContext));
         animateOut();
     }
 
     private void shareContent(ClipData clip) {
         mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SHARE_TAPPED);
-        mContext.startActivity(IntentCreator.getShareIntent(clip, mContext));
+        mContext.startActivity(mIntentCreator.getShareIntent(clip, mContext));
         animateOut();
     }
 
@@ -717,22 +717,22 @@
     public void onRemoteCopyButtonTapped() {
         if (clipboardSharedTransitions()) {
             finish(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED,
-                    IntentCreator.getRemoteCopyIntent(mClipboardModel.getClipData(), mContext));
+                    mIntentCreator.getRemoteCopyIntent(mClipboardModel.getClipData(), mContext));
         }
     }
 
     @Override
     public void onShareButtonTapped() {
         if (clipboardSharedTransitions()) {
+            Intent shareIntent =
+                    mIntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext);
             switch (mClipboardModel.getType()) {
                 case TEXT:
                 case URI:
-                    finish(CLIPBOARD_OVERLAY_SHARE_TAPPED,
-                            IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext));
+                    finish(CLIPBOARD_OVERLAY_SHARE_TAPPED, shareIntent);
                     break;
                 case IMAGE:
-                    finishWithSharedTransition(CLIPBOARD_OVERLAY_SHARE_TAPPED,
-                            IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext));
+                    finishWithSharedTransition(CLIPBOARD_OVERLAY_SHARE_TAPPED, shareIntent);
                     break;
             }
         }
@@ -744,11 +744,11 @@
             switch (mClipboardModel.getType()) {
                 case TEXT:
                     finish(CLIPBOARD_OVERLAY_EDIT_TAPPED,
-                            IntentCreator.getTextEditorIntent(mContext));
+                            mIntentCreator.getTextEditorIntent(mContext));
                     break;
                 case IMAGE:
                     finishWithSharedTransition(CLIPBOARD_OVERLAY_EDIT_TAPPED,
-                            IntentCreator.getImageEditIntent(mClipboardModel.getUri(), mContext));
+                            mIntentCreator.getImageEditIntent(mClipboardModel.getUri(), mContext));
                     break;
                 default:
                     Log.w(TAG, "Got preview tapped callback for non-editable type "
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DefaultIntentCreator.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DefaultIntentCreator.java
new file mode 100644
index 0000000..4b24536
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DefaultIntentCreator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.clipboardoverlay;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
+
+import javax.inject.Inject;
+
+@SysUISingleton
+public class DefaultIntentCreator implements IntentCreator {
+    private static final String EXTRA_EDIT_SOURCE = "edit_source";
+    private static final String EDIT_SOURCE_CLIPBOARD = "clipboard";
+    private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
+
+    @Inject
+    public DefaultIntentCreator() {}
+
+    public Intent getTextEditorIntent(Context context) {
+        Intent intent = new Intent(context, EditTextActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        return intent;
+    }
+
+    public Intent getShareIntent(ClipData clipData, Context context) {
+        Intent shareIntent = new Intent(Intent.ACTION_SEND);
+
+        // From the ACTION_SEND docs:
+        //   "If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the
+        //    MIME type of the data in EXTRA_STREAM"
+        Uri uri = clipData.getItemAt(0).getUri();
+        if (uri != null) {
+            // We don't use setData here because some apps interpret this as "to:".
+            shareIntent.setType(clipData.getDescription().getMimeType(0));
+            // Include URI in ClipData also, so that grantPermission picks it up.
+            shareIntent.setClipData(new ClipData(
+                    new ClipDescription(
+                            "content", new String[]{clipData.getDescription().getMimeType(0)}),
+                    new ClipData.Item(uri)));
+            shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
+            shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        } else {
+            shareIntent.putExtra(
+                    Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context).toString());
+            shareIntent.setType("text/plain");
+        }
+        Intent chooserIntent = Intent.createChooser(shareIntent, null)
+                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
+                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+        return chooserIntent;
+    }
+
+    public Intent getImageEditIntent(Uri uri, Context context) {
+        String editorPackage = context.getString(R.string.config_screenshotEditor);
+        Intent editIntent = new Intent(Intent.ACTION_EDIT);
+        if (!TextUtils.isEmpty(editorPackage)) {
+            editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
+        }
+        editIntent.setDataAndType(uri, "image/*");
+        editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        editIntent.putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_CLIPBOARD);
+        return editIntent;
+    }
+
+    public Intent getRemoteCopyIntent(ClipData clipData, Context context) {
+        Intent nearbyIntent = new Intent(REMOTE_COPY_ACTION);
+
+        String remoteCopyPackage = context.getString(R.string.config_remoteCopyPackage);
+        if (!TextUtils.isEmpty(remoteCopyPackage)) {
+            nearbyIntent.setComponent(ComponentName.unflattenFromString(remoteCopyPackage));
+        }
+
+        nearbyIntent.setClipData(clipData);
+        nearbyIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        return nearbyIntent;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
index a18b4c8..c8a6b05 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,79 +17,13 @@
 package com.android.systemui.clipboardoverlay;
 
 import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
-import android.text.TextUtils;
 
-import com.android.systemui.res.R;
-
-class IntentCreator {
-    private static final String EXTRA_EDIT_SOURCE = "edit_source";
-    private static final String EDIT_SOURCE_CLIPBOARD = "clipboard";
-    private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
-
-    static Intent getTextEditorIntent(Context context) {
-        Intent intent = new Intent(context, EditTextActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        return intent;
-    }
-
-    static Intent getShareIntent(ClipData clipData, Context context) {
-        Intent shareIntent = new Intent(Intent.ACTION_SEND);
-
-        // From the ACTION_SEND docs:
-        //   "If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the
-        //    MIME type of the data in EXTRA_STREAM"
-        Uri uri = clipData.getItemAt(0).getUri();
-        if (uri != null) {
-            // We don't use setData here because some apps interpret this as "to:".
-            shareIntent.setType(clipData.getDescription().getMimeType(0));
-            // Include URI in ClipData also, so that grantPermission picks it up.
-            shareIntent.setClipData(new ClipData(
-                    new ClipDescription(
-                            "content", new String[]{clipData.getDescription().getMimeType(0)}),
-                    new ClipData.Item(uri)));
-            shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
-            shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        } else {
-            shareIntent.putExtra(
-                    Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context).toString());
-            shareIntent.setType("text/plain");
-        }
-        Intent chooserIntent = Intent.createChooser(shareIntent, null)
-                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
-                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-        return chooserIntent;
-    }
-
-    static Intent getImageEditIntent(Uri uri, Context context) {
-        String editorPackage = context.getString(R.string.config_screenshotEditor);
-        Intent editIntent = new Intent(Intent.ACTION_EDIT);
-        if (!TextUtils.isEmpty(editorPackage)) {
-            editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
-        }
-        editIntent.setDataAndType(uri, "image/*");
-        editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        editIntent.putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_CLIPBOARD);
-        return editIntent;
-    }
-
-    static Intent getRemoteCopyIntent(ClipData clipData, Context context) {
-        Intent nearbyIntent = new Intent(REMOTE_COPY_ACTION);
-
-        String remoteCopyPackage = context.getString(R.string.config_remoteCopyPackage);
-        if (!TextUtils.isEmpty(remoteCopyPackage)) {
-            nearbyIntent.setComponent(ComponentName.unflattenFromString(remoteCopyPackage));
-        }
-
-        nearbyIntent.setClipData(clipData);
-        nearbyIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        return nearbyIntent;
-    }
+public interface IntentCreator {
+    Intent getTextEditorIntent(Context context);
+    Intent getShareIntent(ClipData clipData, Context context);
+    Intent getImageEditIntent(Uri uri, Context context);
+    Intent getRemoteCopyIntent(ClipData clipData, Context context);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
index 6c10eea..c86a84b 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
@@ -20,6 +20,7 @@
 
 import static com.android.systemui.Flags.clipboardOverlayMultiuser;
 import static com.android.systemui.Flags.enableViewCaptureTracing;
+import static com.android.systemui.shared.Flags.usePreferredImageEditor;
 import static com.android.systemui.util.ConvenienceExtensionsKt.toKotlinLazy;
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -32,7 +33,10 @@
 
 import com.android.app.viewcapture.ViewCapture;
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
+import com.android.systemui.clipboardoverlay.ActionIntentCreator;
 import com.android.systemui.clipboardoverlay.ClipboardOverlayView;
+import com.android.systemui.clipboardoverlay.DefaultIntentCreator;
+import com.android.systemui.clipboardoverlay.IntentCreator;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
@@ -102,6 +106,17 @@
                 /* isViewCaptureEnabled= */ enableViewCaptureTracing());
     }
 
+    @Provides
+    static IntentCreator provideIntentCreator(
+            Lazy<DefaultIntentCreator> defaultIntentCreator,
+            Lazy<ActionIntentCreator> actionIntentCreator) {
+        if (usePreferredImageEditor()) {
+            return actionIntentCreator.get();
+        } else {
+            return defaultIntentCreator.get();
+        }
+    }
+
     @Qualifier
     @Documented
     @Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
index 13f6bba..07cc136 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
@@ -147,7 +147,7 @@
          */
         fun create(
             context: Context,
-            configurationController: ConfigurationController
+            configurationController: ConfigurationController,
         ): ConfigurationStateImpl
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java b/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java
index e456310..4be9601 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java
@@ -102,7 +102,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 
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 d7859c9..62a98d7 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
@@ -367,11 +367,24 @@
     /** See [CommunalSettingsInteractor.isV2FlagEnabled] */
     fun v2FlagEnabled(): Boolean = communalSettingsInteractor.isV2FlagEnabled()
 
-    val swipeToHubEnabled: StateFlow<Boolean> by lazy {
+    val swipeToHubEnabled: Flow<Boolean> by lazy {
+        val inAllowedDeviceState =
+            if (swipeToHub) {
+                MutableStateFlow(true)
+            } else if (v2FlagEnabled()) {
+                communalInteractor.shouldShowCommunal
+            } else {
+                MutableStateFlow(false)
+            }
+
         if (v2FlagEnabled()) {
-            communalInteractor.shouldShowCommunal
+            val inAllowedKeyguardState =
+                keyguardTransitionInteractor.startedKeyguardTransitionStep.map {
+                    it.to == KeyguardState.LOCKSCREEN || it.to == KeyguardState.GLANCEABLE_HUB
+                }
+            allOf(inAllowedDeviceState, inAllowedKeyguardState)
         } else {
-            MutableStateFlow(swipeToHub)
+            inAllowedDeviceState
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index a25faa3..11b42a8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -36,6 +36,8 @@
 import com.android.systemui.dock.DockManagerImpl;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.education.dagger.ContextualEducationModule;
+import com.android.systemui.topwindoweffects.dagger.SqueezeEffectRepositoryModule;
+import com.android.systemui.topwindoweffects.dagger.TopLevelWindowEffectsModule;
 import com.android.systemui.emergency.EmergencyGestureModule;
 import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialModule;
 import com.android.systemui.keyboard.shortcut.ShortcutHelperModule;
@@ -160,12 +162,14 @@
         StatusBarPhoneModule.class,
         SystemActionsModule.class,
         ShadeModule.class,
+        SqueezeEffectRepositoryModule.class,
         StartCentralSurfacesModule.class,
         SceneContainerFrameworkModule.class,
         SysUICoroutinesModule.class,
         SysUIUnfoldStartableModule.class,
         UnfoldTransitionModule.Startables.class,
         ToastModule.class,
+        TopLevelWindowEffectsModule.class,
         TouchpadTutorialModule.class,
         VolumeModule.class,
         WallpaperModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt
index 69da67e..1e7bec2 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt
@@ -68,10 +68,4 @@
                 emptyFlow()
             }
         }
-
-    /** Triggered if a face failure occurs regardless of the mode. */
-    val faceFailure: Flow<FailedFaceAuthenticationStatus> =
-        deviceEntryFaceAuthInteractor.authenticationStatus.filterIsInstance<
-            FailedFaceAuthenticationStatus
-        >()
 }
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 38e0503..0993683 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
@@ -22,7 +22,6 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardBypassInteractor
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.util.kotlin.FlowDumperImpl
@@ -49,8 +48,6 @@
 constructor(
     biometricSettingsRepository: BiometricSettingsRepository,
     deviceEntryBiometricAuthInteractor: DeviceEntryBiometricAuthInteractor,
-    deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
-    keyguardBypassInteractor: KeyguardBypassInteractor,
     deviceEntryFingerprintAuthInteractor: DeviceEntryFingerprintAuthInteractor,
     deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
     fingerprintPropertyRepository: FingerprintPropertyRepository,
@@ -83,7 +80,12 @@
                 emit(recentPowerButtonPressThresholdMs * -1L - 1L)
             }
 
-    private val playHapticsOnDeviceEntry: Flow<Boolean> =
+    /**
+     * Indicates when success haptics should play when the device is entered. This always occurs on
+     * successful fingerprint authentications. It also occurs on successful face authentication but
+     * only if the lockscreen is bypassed.
+     */
+    val playSuccessHapticOnDeviceEntry: Flow<Unit> =
         deviceEntrySourceInteractor.deviceEntryFromBiometricSource
             .sample(
                 combine(
@@ -93,29 +95,17 @@
                     ::Triple,
                 )
             )
-            .map { (sideFpsEnrolled, powerButtonDown, lastPowerButtonWakeup) ->
+            .filter { (sideFpsEnrolled, powerButtonDown, lastPowerButtonWakeup) ->
                 val sideFpsAllowsHaptic =
                     !powerButtonDown &&
                         systemClock.uptimeMillis() - lastPowerButtonWakeup >
                             recentPowerButtonPressThresholdMs
                 val allowHaptic = !sideFpsEnrolled || sideFpsAllowsHaptic
                 if (!allowHaptic) {
-                    logger.d(
-                        "Skip success entry haptic from power button. Recent power button press or button is down."
-                    )
+                    logger.d("Skip success haptic. Recent power button press or button is down.")
                 }
                 allowHaptic
             }
-
-    private val playHapticsOnFaceAuthSuccessAndBypassDisabled: Flow<Boolean> =
-        deviceEntryFaceAuthInteractor.isAuthenticated
-            .filter { it }
-            .sample(keyguardBypassInteractor.isBypassAvailable)
-            .map { !it }
-
-    val playSuccessHaptic: Flow<Unit> =
-        merge(playHapticsOnDeviceEntry, playHapticsOnFaceAuthSuccessAndBypassDisabled)
-            .filter { it }
             // map to Unit
             .map {}
             .dumpWhileCollecting("playSuccessHaptic")
@@ -123,7 +113,7 @@
     private val playErrorHapticForBiometricFailure: Flow<Unit> =
         merge(
                 deviceEntryFingerprintAuthInteractor.fingerprintFailure,
-                deviceEntryBiometricAuthInteractor.faceFailure,
+                deviceEntryBiometricAuthInteractor.faceOnlyFaceFailure,
             )
             // map to Unit
             .map {}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayRepository.kt
index 36d3eb51..d27e33e 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayRepository.kt
@@ -126,10 +126,11 @@
         get() = perDisplayInstances.keys
 
     private suspend fun start() {
-        dumpManager.registerDumpable(this)
+        dumpManager.registerNormalDumpable("PerDisplayRepository-${debugName}", this)
         displayRepository.displayIds.collectLatest { displayIds ->
             val toRemove = perDisplayInstances.keys - displayIds
             toRemove.forEach { displayId ->
+                Log.d(TAG, "<$debugName> destroying instance for displayId=$displayId.")
                 perDisplayInstances.remove(displayId)?.let { instance ->
                     (instanceProvider as? PerDisplayInstanceProviderWithTeardown)?.destroyInstance(
                         instance
@@ -147,6 +148,7 @@
 
         // If it doesn't exist, create it and put it in the map.
         return perDisplayInstances.computeIfAbsent(displayId) { key ->
+            Log.d(TAG, "<$debugName> creating instance for displayId=$key, as it wasn't available.")
             val instance =
                 traceSection({ "creating instance of $debugName for displayId=$key" }) {
                     instanceProvider.createInstance(key)
@@ -182,8 +184,13 @@
  * Provides an instance of a given class **only** for the default display, even if asked for another
  * display.
  *
- * This is useful in case of flag refactors: it can be provided instead of an instance of
+ * This is useful in case of **flag refactors**: it can be provided instead of an instance of
  * [PerDisplayInstanceRepositoryImpl] when a flag related to multi display refactoring is off.
+ *
+ * Note that this still requires all instances to be provided by a [PerDisplayInstanceProvider]. If
+ * you want to provide an existing instance instead for the default display, either implement it in
+ * a custom [PerDisplayInstanceProvider] (e.g. inject it in the constructor and return it if the
+ * displayId is zero), or use [SingleInstanceRepositoryImpl].
  */
 class DefaultDisplayOnlyInstanceRepositoryImpl<T>(
     override val debugName: String,
@@ -196,3 +203,18 @@
 
     override fun get(displayId: Int): T? = lazyDefaultDisplayInstance
 }
+
+/**
+ * Always returns [instance] for any display.
+ *
+ * This can be used to provide a single instance based on a flag value during a refactor. Similar to
+ * [DefaultDisplayOnlyInstanceRepositoryImpl], but also avoids creating the
+ * [PerDisplayInstanceProvider]. This is useful when you want to provide an existing instance only,
+ * without even instantiating a [PerDisplayInstanceProvider].
+ */
+class SingleInstanceRepositoryImpl<T>(override val debugName: String, private val instance: T) :
+    PerDisplayRepository<T> {
+    override val displayIds: Set<Int> = setOf(Display.DEFAULT_DISPLAY)
+
+    override fun get(displayId: Int): T? = instance
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 12718e8b..9edd9dc 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -94,6 +94,7 @@
 public class DozeSensors {
     private static final String TAG = "DozeSensors";
     private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
+    private static final String KEY_DOZE_PULSE_ON_AUTH = "doze_pulse_on_auth";
 
     private final AsyncSensorManager mSensorManager;
     private final AmbientDisplayConfiguration mConfig;
@@ -241,7 +242,7 @@
                 ),
                 new TriggerSensor(
                         findSensor(config.udfpsLongPressSensorType()),
-                        "doze_pulse_on_auth",
+                        KEY_DOZE_PULSE_ON_AUTH,
                         true /* settingDef */,
                         udfpsLongPressConfigured(),
                         DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS,
@@ -421,6 +422,18 @@
                     && (!s.mRequiresTouchscreen || mListeningTouchScreenSensors)
                     && (!s.mRequiresProx || mListeningProxSensors)
                     && (!s.mRequiresAod || mListeningAodOnlySensors);
+
+            //AOD might be turned off in visual because of BetterySaver or isAlwaysOnSuppressed(),
+            //but AOD isn't really turned off, in these cases, udfpsLongPressSensor should be
+            //unregistered.
+            if (!mListeningAodOnlySensors && KEY_DOZE_PULSE_ON_AUTH.equals(s.mSetting)) {
+                if (mConfig.alwaysOnEnabled(mSelectedUserInteractor.getSelectedUserId())
+                        && !mConfig.screenOffUdfpsEnabled(
+                        mSelectedUserInteractor.getSelectedUserId())) {
+                    listen = false;
+                }
+            }
+
             s.setListening(listen);
             if (listen) {
                 anyListening = true;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
index d81949d..c17094b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
@@ -63,7 +63,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
index c7fe1e1..fb4ed14 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -63,7 +63,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
index ca157af..293461d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
@@ -91,6 +91,7 @@
      * }
      * ````
      */
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
     inline fun unsafeAssertInNewMode(isEnabled: Boolean, flagName: Any) =
         check(isEnabled) { "New code path not supported when $flagName is disabled." }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
index 54e27a6..04a0630 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
@@ -88,10 +88,7 @@
     private fun createDialog(): Dialog {
         return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog
             ->
-            val uiState by
-                viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle(
-                    initialValue = ShortcutCustomizationUiState.Inactive
-                )
+            val uiState by viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle()
             val coroutineScope = rememberCoroutineScope()
             ShortcutCustomizationDialog(
                 uiState = uiState,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
index 7e0fa2f..c601e6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
@@ -409,6 +409,7 @@
         color = MaterialTheme.colorScheme.onSurface,
         lineHeight = 32.sp,
         fontWeight = FontWeight.W400,
+        textAlign = TextAlign.Center,
     )
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt
index 9da9a73..32257df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/data/repository/KeyEventRepository.kt
@@ -18,7 +18,7 @@
 
 import android.view.KeyEvent
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.CommandQueue
 import javax.inject.Inject
@@ -29,6 +29,9 @@
 interface KeyEventRepository {
     /** Observable for whether the power button key is pressed/down or not. */
     val isPowerButtonDown: Flow<Boolean>
+
+    /** Observable for when the power button is being pressed but till the duration of long press */
+    val isPowerButtonLongPressed: Flow<Boolean>
 }
 
 @SysUISingleton
@@ -51,6 +54,21 @@
         awaitClose { commandQueue.removeCallback(callback) }
     }
 
+    override val isPowerButtonLongPressed: Flow<Boolean> = conflatedCallbackFlow {
+        val callback =
+            object : CommandQueue.Callbacks {
+                override fun handleSystemKey(event: KeyEvent) {
+                    if (event.keyCode == KeyEvent.KEYCODE_POWER) {
+                        trySendWithFailureLogging(event.action == KeyEvent.ACTION_DOWN
+                                && event.isLongPress, TAG, "updated isPowerButtonLongPressed")
+                    }
+                }
+            }
+        trySendWithFailureLogging(false, TAG, "init isPowerButtonLongPressed")
+        commandQueue.addCallback(callback)
+        awaitClose { commandQueue.removeCallback(callback) }
+    }
+
     companion object {
         private const val TAG = "KeyEventRepositoryImpl"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt
index 9949fa5..ec9bbfb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractor.kt
@@ -32,4 +32,5 @@
     repository: KeyEventRepository,
 ) {
     val isPowerButtonDown = repository.isPowerButtonDown
+    val isPowerButtonLongPressed = repository.isPowerButtonLongPressed
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt
index 1febc79..bc65ad4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt
@@ -42,7 +42,7 @@
 
         when (event.keyCode) {
             KeyEvent.KEYCODE_BACK -> {
-                if (event.handleAction()) {
+                if (!backActionInteractor.isBackCallbackRegistered() && event.handleAction()) {
                     backActionInteractor.onBackRequested()
                 }
                 return true
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 3b85b57..9ade503 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -51,10 +51,10 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.SystemUIAppComponentFactoryBase;
 import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index 2c5bacb..70e2413 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -196,6 +196,9 @@
             confirmCredentialIntent.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
         }
 
+        String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+        confirmCredentialIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+
         // WorkLockActivity is started as a task overlay, so unless credential confirmation is also
         // started as an overlay, it won't be visible.
         final ActivityOptions launchOptions = ActivityOptions.makeBasic();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 45801ba..aeb3270 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -333,7 +333,7 @@
 
                     if (deviceEntryHapticsInteractor != null && vibratorHelper != null) {
                         launch {
-                            deviceEntryHapticsInteractor.playSuccessHaptic.collect {
+                            deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry.collect {
                                 if (msdlFeedback()) {
                                     msdlPlayer?.playToken(
                                         MSDLToken.UNLOCK,
@@ -474,7 +474,7 @@
                 val transition = blueprintViewModel.currentTransition.value
                 val shouldAnimate = transition != null && transition.config.type.animateNotifChanges
                 if (prevTransition == transition && shouldAnimate) {
-                    logger.w("Skipping; layout during transition")
+                    logger.w("Skipping onNotificationContainerBoundsChanged during transition")
                     return
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
index c4a7e1e..55fac3c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToAodTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToOccludedTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel
@@ -272,6 +273,12 @@
 
     @Binds
     @IntoSet
+    abstract fun glanceableHubToLockscreen(
+        impl: GlanceableHubToLockscreenTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun occludedToGlanceableHub(
         impl: OccludedToGlanceableHubTransitionViewModel
     ): DeviceEntryIconTransition
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 0ccb24a..20fc884 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -61,6 +61,7 @@
     primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel,
     lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
     glanceableHubToAodTransitionViewModel: GlanceableHubToAodTransitionViewModel,
+    glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel,
 ) {
     val color: Flow<Int> =
         deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -108,6 +109,7 @@
                             .deviceEntryBackgroundViewAlpha,
                         lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
                         glanceableHubToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        glanceableHubToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
                     )
                     .merge()
                     .onStart {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt
index b4b4c82..bcbe666 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
 import com.android.systemui.keyguard.ui.StateToValue
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.model.Scenes
@@ -49,7 +50,7 @@
     @ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
     animationFlow: KeyguardTransitionAnimationFlow,
     private val blurFactory: GlanceableHubBlurComponent.Factory,
-) : GlanceableHubTransition {
+) : GlanceableHubTransition, DeviceEntryIconTransition {
     private val transitionAnimation =
         animationFlow
             .setup(
@@ -102,4 +103,8 @@
 
     val notificationTranslationX: Flow<Float> =
         keyguardTranslationX.map { it.value }.filterNotNull()
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> = keyguardAlpha
+
+    override val deviceEntryParentViewAlpha: Flow<Float> = keyguardAlpha
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index d4676bc..6d8a943 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -132,6 +132,8 @@
     private val occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel,
     private val occludedToDozingTransitionViewModel: OccludedToDozingTransitionViewModel,
     private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
+    private val occludedToPrimaryBouncerTransitionViewModel:
+        OccludedToPrimaryBouncerTransitionViewModel,
     private val offToLockscreenTransitionViewModel: OffToLockscreenTransitionViewModel,
     private val primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel,
     private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
@@ -288,6 +290,7 @@
                         occludedToAodTransitionViewModel.lockscreenAlpha,
                         occludedToDozingTransitionViewModel.lockscreenAlpha,
                         occludedToLockscreenTransitionViewModel.lockscreenAlpha,
+                        occludedToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
                         offToLockscreenTransitionViewModel.lockscreenAlpha,
                         primaryBouncerToAodTransitionViewModel.lockscreenAlpha,
                         primaryBouncerToGoneTransitionViewModel.lockscreenAlpha,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModel.kt
index f14a5a2..67c3071 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModel.kt
@@ -45,6 +45,12 @@
             )
             .setupWithoutSceneContainer(edge = Edge.create(OCCLUDED, PRIMARY_BOUNCER))
 
+    /**
+     * Reasserts that lockscreen content should not be visible. It is possible the keyguard alpha is
+     * set to 1f if coming from an expanded shade that collapsed to launch an occluding activity.
+     */
+    val lockscreenAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0f)
+
     override val windowBlurRadius: Flow<Float> =
         shadeDependentFlows.transitionFlow(
             flowWhenShadeIsExpanded =
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index faa6c52..a85b9b0 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -327,7 +327,8 @@
     @SysUISingleton
     @KeyguardBlueprintLog
     public static LogBuffer provideKeyguardBlueprintLog(LogBufferFactory factory) {
-        return factory.create("KeyguardBlueprintLog", 100);
+        // TODO(b/389987229): Reduce back to 100
+        return factory.create("KeyguardBlueprintLog", 1000);
     }
 
     /**
@@ -337,7 +338,8 @@
     @SysUISingleton
     @KeyguardClockLog
     public static LogBuffer provideKeyguardClockLog(LogBufferFactory factory) {
-        return factory.create("KeyguardClockLog", 100);
+        // TODO(b/389987229): Reduce back to 100
+        return factory.create("KeyguardClockLog", 1000);
     }
 
     /**
@@ -347,7 +349,8 @@
     @SysUISingleton
     @KeyguardSmallClockLog
     public static LogBuffer provideKeyguardSmallClockLog(LogBufferFactory factory) {
-        return factory.create("KeyguardSmallClockLog", 100);
+        // TODO(b/389987229): Reduce back to 100
+        return factory.create("KeyguardSmallClockLog", 1000);
     }
 
     /**
@@ -357,7 +360,8 @@
     @SysUISingleton
     @KeyguardLargeClockLog
     public static LogBuffer provideKeyguardLargeClockLog(LogBufferFactory factory) {
-        return factory.create("KeyguardLargeClockLog", 100);
+        // TODO(b/389987229): Reduce back to 100
+        return factory.create("KeyguardLargeClockLog", 1000);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/DirectBootCondition.kt b/packages/SystemUI/src/com/android/systemui/lowlightclock/DirectBootCondition.kt
index 4c1da01..57d7098 100644
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/DirectBootCondition.kt
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/DirectBootCondition.kt
@@ -54,7 +54,6 @@
         job?.cancel()
     }
 
-    override fun getStartStrategy(): Int {
-        return START_EAGERLY
-    }
+    override val startStrategy: Int
+        get() = START_EAGERLY
 }
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/ForceLowLightCondition.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/ForceLowLightCondition.java
index 7f21d07..5ec81a9 100644
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/ForceLowLightCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/ForceLowLightCondition.java
@@ -131,7 +131,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightCondition.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightCondition.java
index e91be50..c1a24e7 100644
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightCondition.java
@@ -54,7 +54,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         // As this condition keeps the lowlight sensor active, it should only run when needed.
         return START_WHEN_NEEDED;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/ScreenSaverEnabledCondition.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/ScreenSaverEnabledCondition.java
index fd6ce17..8157255 100644
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/ScreenSaverEnabledCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/ScreenSaverEnabledCondition.java
@@ -70,7 +70,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/media/NotificationMediaManager.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
rename to packages/SystemUI/src/com/android/systemui/media/NotificationMediaManager.java
index 18f4b4a..db4c7a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationMediaManager.java
@@ -11,9 +11,9 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
-package com.android.systemui.statusbar;
+package com.android.systemui.media;
 
 import static com.android.systemui.Flags.mediaControlsUserInitiatedDeleteintent;
 
@@ -40,6 +40,8 @@
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
 import com.android.systemui.media.controls.shared.model.MediaData;
 import com.android.systemui.media.controls.shared.model.SmartspaceMediaData;
+import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.dagger.CentralSurfacesModule;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt
index 46cf0a6..309b675 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt
@@ -66,6 +66,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.NotificationMediaManager.isPlayingState
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager.Companion.isMediaNotification
 import com.android.systemui.media.controls.domain.resume.MediaResumeListener
 import com.android.systemui.media.controls.domain.resume.ResumeMediaBrowser
@@ -83,7 +84,6 @@
 import com.android.systemui.media.controls.util.MediaFlags
 import com.android.systemui.media.controls.util.MediaUiEventLogger
 import com.android.systemui.res.R
-import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
 import com.android.systemui.statusbar.notification.row.HybridGroupManager
 import com.android.systemui.util.Assert
 import com.android.systemui.util.Utils
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
index 5fef81f..da462e6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
@@ -30,6 +30,8 @@
 import android.util.Log
 import androidx.media.utils.MediaConstants
 import com.android.systemui.Flags
+import com.android.systemui.media.NotificationMediaManager.isConnectingState
+import com.android.systemui.media.NotificationMediaManager.isPlayingState
 import com.android.systemui.media.controls.domain.pipeline.LegacyMediaDataManagerImpl.Companion.MAX_COMPACT_ACTIONS
 import com.android.systemui.media.controls.domain.pipeline.LegacyMediaDataManagerImpl.Companion.MAX_NOTIFICATION_ACTIONS
 import com.android.systemui.media.controls.shared.MediaControlDrawables
@@ -38,8 +40,6 @@
 import com.android.systemui.media.controls.shared.model.MediaNotificationAction
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.res.R
-import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
-import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
 import com.android.systemui.util.kotlin.logI
 
 private const val TAG = "MediaActions"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoader.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoader.kt
index 8bb7303..dbd2250 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoader.kt
@@ -51,6 +51,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.graphics.ImageLoader
+import com.android.systemui.media.NotificationMediaManager.isPlayingState
 import com.android.systemui.media.controls.shared.model.MediaAction
 import com.android.systemui.media.controls.shared.model.MediaButton
 import com.android.systemui.media.controls.shared.model.MediaData
@@ -60,7 +61,6 @@
 import com.android.systemui.media.controls.util.MediaDataUtils
 import com.android.systemui.media.controls.util.MediaFlags
 import com.android.systemui.res.R
-import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
 import com.android.systemui.statusbar.notification.row.HybridGroupManager
 import com.android.systemui.util.kotlin.logD
 import java.util.concurrent.ConcurrentHashMap
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
index fe852ce..94df4b3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
@@ -66,6 +66,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.NotificationMediaManager.isPlayingState
 import com.android.systemui.media.controls.data.repository.MediaDataRepository
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager.Companion.isMediaNotification
 import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
@@ -85,7 +86,6 @@
 import com.android.systemui.media.controls.util.MediaUiEventLogger
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
 import com.android.systemui.statusbar.notification.row.HybridGroupManager
 import com.android.systemui.util.Assert
 import com.android.systemui.util.Utils
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt
index 684a560..be4e6cc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt
@@ -25,12 +25,12 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.NotificationMediaManager.isPlayingState
 import com.android.systemui.media.controls.shared.model.MediaData
 import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
 import com.android.systemui.media.controls.util.MediaControllerFactory
 import com.android.systemui.media.controls.util.MediaFlags
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.time.SystemClock
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModel.kt
index a1f0cc3..8744c5c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModel.kt
@@ -39,8 +39,8 @@
 import com.android.systemui.Flags
 import com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.media.NotificationMediaManager
 import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.util.concurrency.RepeatableExecutor
 import java.util.Locale
 import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java
index c58ba37..ac1672d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java
@@ -351,8 +351,9 @@
         @VisibleForTesting
         void showCustomEndSessionDialog(MediaDevice device) {
             MediaSessionReleaseDialog mediaSessionReleaseDialog = new MediaSessionReleaseDialog(
-                    mContext, () -> transferOutput(device), mController.getColorButtonBackground(),
-                    mController.getColorItemContent());
+                    mContext, () -> transferOutput(device),
+                    mController.getColorSchemeLegacy().getColorButtonBackground(),
+                    mController.getColorSchemeLegacy().getColorItemContent());
             mediaSessionReleaseDialog.show();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
index 300a357..795e811 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
@@ -50,9 +50,11 @@
 import com.android.media.flags.Flags;
 import com.android.settingslib.media.InputMediaDevice;
 import com.android.settingslib.media.MediaDevice;
-import com.android.settingslib.utils.ThreadUtils;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.res.R;
 
+import java.util.concurrent.Executor;
 /**
  * A RecyclerView adapter for the legacy UI media output dialog device list.
  */
@@ -61,13 +63,21 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int UNMUTE_DEFAULT_VOLUME = 2;
-    private static final float DEVICE_DISABLED_ALPHA = 0.5f;
-    private static final float DEVICE_ACTIVE_ALPHA = 1f;
+    @VisibleForTesting static final float DEVICE_DISABLED_ALPHA = 0.5f;
+    @VisibleForTesting static final float DEVICE_ACTIVE_ALPHA = 1f;
+    private final Executor mMainExecutor;
+    private final Executor mBackgroundExecutor;
     View mHolderView;
     private boolean mIsInitVolumeFirstTime;
 
-    public MediaOutputAdapterLegacy(MediaSwitchingController controller) {
+    public MediaOutputAdapterLegacy(
+            MediaSwitchingController controller,
+            @Main Executor mainExecutor,
+            @Background Executor backgroundExecutor
+    ) {
         super(controller);
+        mMainExecutor = mainExecutor;
+        mBackgroundExecutor = backgroundExecutor;
         mIsInitVolumeFirstTime = true;
     }
 
@@ -181,9 +191,9 @@
             mEndTouchArea.setVisibility(View.GONE);
             mEndClickIcon.setVisibility(View.GONE);
             mContainerLayout.setOnClickListener(null);
-            mTitleText.setTextColor(mController.getColorItemContent());
-            mSubTitleText.setTextColor(mController.getColorItemContent());
-            mVolumeValueText.setTextColor(mController.getColorItemContent());
+            mTitleText.setTextColor(mController.getColorSchemeLegacy().getColorItemContent());
+            mSubTitleText.setTextColor(mController.getColorSchemeLegacy().getColorItemContent());
+            mVolumeValueText.setTextColor(mController.getColorSchemeLegacy().getColorItemContent());
             mIconAreaLayout.setBackground(null);
             updateIconAreaClickListener(null);
             updateSeekBarProgressColor();
@@ -193,14 +203,14 @@
 
         /** Binds a ViewHolder for a "Connect a device" item. */
         void onBindPairNewDevice() {
-            mTitleText.setTextColor(mController.getColorItemContent());
+            mTitleText.setTextColor(mController.getColorSchemeLegacy().getColorItemContent());
             mCheckBox.setVisibility(View.GONE);
             updateTitle(mContext.getText(R.string.media_output_dialog_pairing_new));
             updateItemBackground(ConnectionState.DISCONNECTED);
             final Drawable addDrawable = mContext.getDrawable(R.drawable.ic_add);
             mTitleIcon.setImageDrawable(addDrawable);
-            mTitleIcon.setImageTintList(
-                    ColorStateList.valueOf(mController.getColorItemContent()));
+            mTitleIcon.setImageTintList(ColorStateList.valueOf(
+                    mController.getColorSchemeLegacy().getColorItemContent()));
             mContainerLayout.setOnClickListener(mController::launchBluetoothPairing);
         }
 
@@ -297,8 +307,8 @@
         protected void updateLoadingIndicator(ConnectionState connectionState) {
             if (connectionState == ConnectionState.CONNECTING) {
                 mProgressBar.setVisibility(View.VISIBLE);
-                mProgressBar.getIndeterminateDrawable().setTintList(
-                        ColorStateList.valueOf(mController.getColorItemContent()));
+                mProgressBar.getIndeterminateDrawable().setTintList(ColorStateList.valueOf(
+                        mController.getColorSchemeLegacy().getColorItemContent()));
             } else {
                 mProgressBar.setVisibility(View.GONE);
             }
@@ -318,8 +328,8 @@
 
             // Connected or connecting state has a darker background.
             int backgroundColor = isConnected || isConnecting
-                    ? mController.getColorConnectedItemBackground()
-                    : mController.getColorItemBackground();
+                    ? mController.getColorSchemeLegacy().getColorConnectedItemBackground()
+                    : mController.getColorSchemeLegacy().getColorItemBackground();
             mItemLayout.setBackgroundTintList(ColorStateList.valueOf(backgroundColor));
         }
 
@@ -332,13 +342,13 @@
         }
 
         private void updateSeekBarProgressColor() {
-            mSeekBar.setProgressTintList(
-                    ColorStateList.valueOf(mController.getColorSeekbarProgress()));
+            mSeekBar.setProgressTintList(ColorStateList.valueOf(
+                    mController.getColorSchemeLegacy().getColorSeekbarProgress()));
             final Drawable contrastDotDrawable =
                     ((LayerDrawable) mSeekBar.getProgressDrawable()).findDrawableByLayerId(
                             R.id.contrast_dot);
-            contrastDotDrawable.setTintList(
-                    ColorStateList.valueOf(mController.getColorItemContent()));
+            contrastDotDrawable.setTintList(ColorStateList.valueOf(
+                    mController.getColorSchemeLegacy().getColorItemContent()));
         }
 
         void updateSeekbarProgressBackground() {
@@ -503,9 +513,10 @@
             boolean isInputMediaDevice = device instanceof InputMediaDevice;
             int id = getDrawableId(isInputMediaDevice, isMutedVolumeIcon);
             mTitleIcon.setImageDrawable(mContext.getDrawable(id));
-            mTitleIcon.setImageTintList(ColorStateList.valueOf(mController.getColorItemContent()));
-            mIconAreaLayout.setBackgroundTintList(
-                    ColorStateList.valueOf(mController.getColorSeekbarProgress()));
+            mTitleIcon.setImageTintList(ColorStateList.valueOf(
+                    mController.getColorSchemeLegacy().getColorItemContent()));
+            mIconAreaLayout.setBackgroundTintList(ColorStateList.valueOf(
+                    mController.getColorSchemeLegacy().getColorSeekbarProgress()));
         }
 
         @VisibleForTesting
@@ -534,8 +545,8 @@
                 mStatusIcon.setVisibility(View.GONE);
             } else {
                 mStatusIcon.setImageDrawable(deviceStatusIcon);
-                mStatusIcon.setImageTintList(
-                        ColorStateList.valueOf(mController.getColorItemContent()));
+                mStatusIcon.setImageTintList(ColorStateList.valueOf(
+                        mController.getColorSchemeLegacy().getColorItemContent()));
                 if (deviceStatusIcon instanceof AnimatedVectorDrawable) {
                     ((AnimatedVectorDrawable) deviceStatusIcon).start();
                 }
@@ -585,9 +596,10 @@
         private void updateEndAreaWithIcon(View.OnClickListener clickListener,
                 @DrawableRes int iconDrawableId,
                 @StringRes int accessibilityStringId) {
-            updateEndAreaColor(mController.getColorSeekbarProgress());
+            updateEndAreaColor(mController.getColorSchemeLegacy().getColorSeekbarProgress());
             mEndClickIcon.setImageTintList(
-                    ColorStateList.valueOf(mController.getColorItemContent()));
+                    ColorStateList.valueOf(
+                            mController.getColorSchemeLegacy().getColorItemContent()));
             mEndClickIcon.setOnClickListener(clickListener);
             Drawable drawable = mContext.getDrawable(iconDrawableId);
             mEndClickIcon.setImageDrawable(drawable);
@@ -600,8 +612,9 @@
         private void updateEndAreaForGroupCheckBox(@NonNull MediaDevice device,
                 @NonNull GroupStatus groupStatus) {
             boolean isEnabled = isGroupCheckboxEnabled(groupStatus);
-            updateEndAreaColor(groupStatus.selected() ? mController.getColorSeekbarProgress()
-                    : mController.getColorItemBackground());
+            updateEndAreaColor(groupStatus.selected()
+                    ? mController.getColorSchemeLegacy().getColorSeekbarProgress()
+                    : mController.getColorSchemeLegacy().getColorItemBackground());
             mCheckBox.setContentDescription(mContext.getString(
                     groupStatus.selected() ? R.string.accessibility_remove_device_from_group
                             : R.string.accessibility_add_device_to_group));
@@ -611,7 +624,7 @@
                     isEnabled ? (buttonView, isChecked) -> onGroupActionTriggered(
                             !groupStatus.selected(), device) : null);
             mCheckBox.setEnabled(isEnabled);
-            setCheckBoxColor(mCheckBox, mController.getColorItemContent());
+            setCheckBoxColor(mCheckBox, mController.getColorSchemeLegacy().getColorItemContent());
         }
 
         private void setCheckBoxColor(CheckBox checkBox, int color) {
@@ -714,15 +727,15 @@
         }
 
         protected void setUpDeviceIcon(@NonNull MediaDevice device) {
-            ThreadUtils.postOnBackgroundThread(() -> {
+            mBackgroundExecutor.execute(() -> {
                 Icon icon = mController.getDeviceIconCompat(device).toIcon(mContext);
-                ThreadUtils.postOnMainThread(() -> {
+                mMainExecutor.execute(() -> {
                     if (!TextUtils.equals(mDeviceId, device.getId())) {
                         return;
                     }
                     mTitleIcon.setImageIcon(icon);
-                    mTitleIcon.setImageTintList(
-                            ColorStateList.valueOf(mController.getColorItemContent()));
+                    mTitleIcon.setImageTintList(ColorStateList.valueOf(
+                            mController.getColorSchemeLegacy().getColorItemContent()));
                 });
             });
         }
@@ -807,7 +820,7 @@
         }
 
         void onBind(String groupDividerTitle) {
-            mTitleText.setTextColor(mController.getColorItemContent());
+            mTitleText.setTextColor(mController.getColorSchemeLegacy().getColorItemContent());
             mTitleText.setText(groupDividerTitle);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index d791361..49d09cf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -40,7 +40,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowManager;
@@ -93,13 +92,10 @@
     private ImageView mAppResourceIcon;
     private ImageView mBroadcastIcon;
     private RecyclerView mDevicesRecyclerView;
-    private LinearLayout mDeviceListLayout;
+    private ViewGroup mDeviceListLayout;
     private LinearLayout mMediaMetadataSectionLayout;
     private Button mDoneButton;
     private Button mStopButton;
-    private int mListMaxHeight;
-    private int mItemHeight;
-    private int mListPaddingTop;
     private WallpaperColors mWallpaperColors;
     private boolean mShouldLaunchLeBroadcastDialog;
     private boolean mIsLeBroadcastCallbackRegistered;
@@ -109,17 +105,6 @@
 
     protected Executor mExecutor;
 
-    private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> {
-        ViewGroup.LayoutParams params = mDeviceListLayout.getLayoutParams();
-        int totalItemsHeight = mAdapter.getItemCount() * mItemHeight
-                + mListPaddingTop;
-        int correctHeight = Math.min(totalItemsHeight, mListMaxHeight);
-        // Set max height for list
-        if (correctHeight != params.height) {
-            params.height = correctHeight;
-            mDeviceListLayout.setLayoutParams(params);
-        }
-    };
 
     private final BluetoothLeBroadcast.Callback mBroadcastCallback =
             new BluetoothLeBroadcast.Callback() {
@@ -220,12 +205,6 @@
         mBroadcastSender = broadcastSender;
         mMediaSwitchingController = mediaSwitchingController;
         mLayoutManager = new LayoutManagerWrapper(mContext);
-        mListMaxHeight = context.getResources().getDimensionPixelSize(
-                R.dimen.media_output_dialog_list_max_height);
-        mItemHeight = context.getResources().getDimensionPixelSize(
-                R.dimen.media_output_dialog_list_item_height);
-        mListPaddingTop = mContext.getResources().getDimensionPixelSize(
-                R.dimen.media_output_dialog_list_padding_top);
         mExecutor = Executors.newSingleThreadExecutor();
         mIncludePlaybackAndAppMetadata = includePlaybackAndAppMetadata;
     }
@@ -258,8 +237,6 @@
         mAppResourceIcon = mDialogView.requireViewById(R.id.app_source_icon);
         mBroadcastIcon = mDialogView.requireViewById(R.id.broadcast_icon);
 
-        mDeviceListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
-                mDeviceListLayoutListener);
         // Init device list
         mLayoutManager.setAutoMeasureEnabled(true);
         mDevicesRecyclerView.setLayoutManager(mLayoutManager);
@@ -342,7 +319,8 @@
                 WallpaperColors wallpaperColors = WallpaperColors.fromBitmap(icon.getBitmap());
                 colorSetUpdated = !wallpaperColors.equals(mWallpaperColors);
                 if (colorSetUpdated) {
-                    mMediaSwitchingController.setCurrentColorScheme(wallpaperColors, isDarkThemeOn);
+                    mMediaSwitchingController.updateCurrentColorScheme(wallpaperColors,
+                            isDarkThemeOn);
                     updateButtonBackgroundColorFilter();
                     updateDialogBackgroundColor();
                 }
@@ -359,7 +337,8 @@
             mAppResourceIcon.setVisibility(View.GONE);
         } else if (appSourceIcon != null) {
             Icon appIcon = appSourceIcon.toIcon(mContext);
-            mAppResourceIcon.setColorFilter(mMediaSwitchingController.getColorItemContent());
+            mAppResourceIcon.setColorFilter(
+                    mMediaSwitchingController.getColorSchemeLegacy().getColorItemContent());
             mAppResourceIcon.setImageIcon(appIcon);
         } else {
             Drawable appIconDrawable = mMediaSwitchingController.getAppSourceIconFromPackage();
@@ -369,12 +348,6 @@
                 mAppResourceIcon.setVisibility(View.GONE);
             }
         }
-        if (mHeaderIcon.getVisibility() == View.VISIBLE) {
-            final int size = getHeaderIconSize();
-            final int padding = mContext.getResources().getDimensionPixelSize(
-                    R.dimen.media_output_dialog_header_icon_padding);
-            mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
-        }
 
         if (!mIncludePlaybackAndAppMetadata) {
             mHeaderTitle.setVisibility(View.GONE);
@@ -419,18 +392,19 @@
     private void updateButtonBackgroundColorFilter() {
         ColorFilter buttonColorFilter =
                 new PorterDuffColorFilter(
-                        mMediaSwitchingController.getColorButtonBackground(),
+                        mMediaSwitchingController.getColorSchemeLegacy().getColorButtonBackground(),
                         PorterDuff.Mode.SRC_IN);
         mDoneButton.getBackground().setColorFilter(buttonColorFilter);
         mStopButton.getBackground().setColorFilter(buttonColorFilter);
-        mDoneButton.setTextColor(mMediaSwitchingController.getColorPositiveButtonText());
+        mDoneButton.setTextColor(
+                mMediaSwitchingController.getColorSchemeLegacy().getColorPositiveButtonText());
     }
 
     private void updateDialogBackgroundColor() {
-        getDialogView()
-                .getBackground()
-                .setTint(mMediaSwitchingController.getColorDialogBackground());
-        mDeviceListLayout.setBackgroundColor(mMediaSwitchingController.getColorDialogBackground());
+        getDialogView().getBackground().setTint(
+                mMediaSwitchingController.getColorSchemeLegacy().getColorDialogBackground());
+        mDeviceListLayout.setBackgroundColor(
+                mMediaSwitchingController.getColorSchemeLegacy().getColorDialogBackground());
     }
 
     public void handleLeBroadcastStarted() {
@@ -520,8 +494,6 @@
 
     abstract IconCompat getHeaderIcon();
 
-    abstract int getHeaderIconSize();
-
     abstract CharSequence getHeaderText();
 
     abstract CharSequence getHeaderSubtitle();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 9ade9e2..791a61c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -52,6 +52,8 @@
 
 import com.google.zxing.WriterException;
 
+import java.util.concurrent.Executor;
+
 /**
  * Dialog for media output broadcast.
  */
@@ -239,13 +241,16 @@
             Context context,
             boolean aboveStatusbar,
             BroadcastSender broadcastSender,
-            MediaSwitchingController mediaSwitchingController) {
+            MediaSwitchingController mediaSwitchingController,
+            Executor mainExecutor,
+            Executor backgroundExecutor) {
         super(
                 context,
                 broadcastSender,
                 mediaSwitchingController, /* includePlaybackAndAppMetadata */
                 true);
-        mAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mainExecutor,
+                backgroundExecutor);
         // TODO(b/226710953): Move the part to MediaOutputBaseDialog for every class
         //  that extends MediaOutputBaseDialog
         if (!aboveStatusbar) {
@@ -295,12 +300,6 @@
     }
 
     @Override
-    int getHeaderIconSize() {
-        return mContext.getResources().getDimensionPixelSize(
-                R.dimen.media_output_dialog_header_album_icon_size);
-    }
-
-    @Override
     CharSequence getHeaderText() {
         return mMediaSwitchingController.getHeaderTitle();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
index 2e7e66f..81c85a6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
@@ -20,6 +20,9 @@
 import android.view.View
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import java.util.concurrent.Executor
 import javax.inject.Inject
 
 /** Manager to create and show a [MediaOutputBroadcastDialog]. */
@@ -29,7 +32,9 @@
     private val context: Context,
     private val broadcastSender: BroadcastSender,
     private val dialogTransitionAnimator: DialogTransitionAnimator,
-    private val mediaSwitchingControllerFactory: MediaSwitchingController.Factory
+    private val mediaSwitchingControllerFactory: MediaSwitchingController.Factory,
+    @Main private val mainExecutor: Executor,
+    @Background private val backgroundExecutor: Executor,
 ) {
     var mediaOutputBroadcastDialog: MediaOutputBroadcastDialog? = null
 
@@ -47,7 +52,14 @@
                 /* token */ null,
             )
         val dialog =
-            MediaOutputBroadcastDialog(context, aboveStatusBar, broadcastSender, controller)
+            MediaOutputBroadcastDialog(
+                context,
+                aboveStatusBar,
+                broadcastSender,
+                controller,
+                mainExecutor,
+                backgroundExecutor,
+            )
         mediaOutputBroadcastDialog = dialog
 
         // Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputColorSchemeLegacy.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputColorSchemeLegacy.kt
new file mode 100644
index 0000000..7f0fa46
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputColorSchemeLegacy.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.dialog
+
+import android.content.Context
+import com.android.settingslib.Utils
+import com.android.systemui.monet.ColorScheme
+import com.android.systemui.res.R
+
+abstract class MediaOutputColorSchemeLegacy {
+    companion object Factory {
+        @JvmStatic
+        fun fromSystemColors(context: Context): MediaOutputColorSchemeLegacy {
+            return MediaOutputColorSchemeLegacySystem(context)
+        }
+
+        @JvmStatic
+        fun fromDynamicColors(
+            colorScheme: ColorScheme,
+            isDarkTheme: Boolean,
+        ): MediaOutputColorSchemeLegacy {
+            return MediaOutputColorSchemeLegacyDynamic(colorScheme, isDarkTheme)
+        }
+    }
+
+    abstract fun getColorConnectedItemBackground(): Int
+
+    abstract fun getColorPositiveButtonText(): Int
+
+    abstract fun getColorDialogBackground(): Int
+
+    abstract fun getColorItemContent(): Int
+
+    abstract fun getColorSeekbarProgress(): Int
+
+    abstract fun getColorButtonBackground(): Int
+
+    abstract fun getColorItemBackground(): Int
+}
+
+class MediaOutputColorSchemeLegacySystem(private val mContext: Context) :
+    MediaOutputColorSchemeLegacy() {
+
+    override fun getColorConnectedItemBackground() =
+        Utils.getColorStateListDefaultColor(
+            mContext,
+            R.color.media_dialog_connected_item_background,
+        )
+
+    override fun getColorPositiveButtonText() =
+        Utils.getColorStateListDefaultColor(mContext, R.color.media_dialog_solid_button_text)
+
+    override fun getColorDialogBackground() =
+        Utils.getColorStateListDefaultColor(mContext, R.color.media_dialog_background)
+
+    override fun getColorItemContent() =
+        Utils.getColorStateListDefaultColor(mContext, R.color.media_dialog_item_main_content)
+
+    override fun getColorSeekbarProgress() =
+        Utils.getColorStateListDefaultColor(mContext, R.color.media_dialog_seekbar_progress)
+
+    override fun getColorButtonBackground() =
+        Utils.getColorStateListDefaultColor(mContext, R.color.media_dialog_button_background)
+
+    override fun getColorItemBackground() =
+        Utils.getColorStateListDefaultColor(mContext, R.color.media_dialog_item_background)
+}
+
+class MediaOutputColorSchemeLegacyDynamic(colorScheme: ColorScheme, isDarkTheme: Boolean) :
+    MediaOutputColorSchemeLegacy() {
+    private var mColorItemContent: Int
+    private var mColorSeekbarProgress: Int
+    private var mColorButtonBackground: Int
+    private var mColorItemBackground: Int
+    private var mColorConnectedItemBackground: Int
+    private var mColorPositiveButtonText: Int
+    private var mColorDialogBackground: Int
+
+    init {
+        if (isDarkTheme) {
+            mColorItemContent = colorScheme.accent1.s100 // A1-100
+            mColorSeekbarProgress = colorScheme.accent2.s600 // A2-600
+            mColorButtonBackground = colorScheme.accent1.s300 // A1-300
+            mColorItemBackground = colorScheme.neutral2.s800 // N2-800
+            mColorConnectedItemBackground = colorScheme.accent2.s800 // A2-800
+            mColorPositiveButtonText = colorScheme.accent2.s800 // A2-800
+            mColorDialogBackground = colorScheme.neutral1.s900 // N1-900
+        } else {
+            mColorItemContent = colorScheme.accent1.s800 // A1-800
+            mColorSeekbarProgress = colorScheme.accent1.s300 // A1-300
+            mColorButtonBackground = colorScheme.accent1.s600 // A1-600
+            mColorItemBackground = colorScheme.accent2.s50 // A2-50
+            mColorConnectedItemBackground = colorScheme.accent1.s100 // A1-100
+            mColorPositiveButtonText = colorScheme.neutral1.s50 // N1-50
+            mColorDialogBackground = colorScheme.backgroundColor
+        }
+    }
+
+    override fun getColorConnectedItemBackground() = mColorConnectedItemBackground
+
+    override fun getColorPositiveButtonText() = mColorPositiveButtonText
+
+    override fun getColorDialogBackground() = mColorDialogBackground
+
+    override fun getColorItemContent() = mColorItemContent
+
+    override fun getColorSeekbarProgress() = mColorSeekbarProgress
+
+    override fun getColorButtonBackground() = mColorButtonBackground
+
+    override fun getColorItemBackground() = mColorItemBackground
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index 2e602be..163ff24 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -34,6 +34,8 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.res.R;
 
+import java.util.concurrent.Executor;
+
 /**
  * Dialog for media output transferring.
  */
@@ -49,11 +51,14 @@
             MediaSwitchingController mediaSwitchingController,
             DialogTransitionAnimator dialogTransitionAnimator,
             UiEventLogger uiEventLogger,
+            Executor mainExecutor,
+            Executor backgroundExecutor,
             boolean includePlaybackAndAppMetadata) {
         super(context, broadcastSender, mediaSwitchingController, includePlaybackAndAppMetadata);
         mDialogTransitionAnimator = dialogTransitionAnimator;
         mUiEventLogger = uiEventLogger;
-        mAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
+        mAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController, mainExecutor,
+                backgroundExecutor);
         if (!aboveStatusbar) {
             getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
         }
@@ -76,12 +81,6 @@
     }
 
     @Override
-    int getHeaderIconSize() {
-        return mContext.getResources().getDimensionPixelSize(
-                R.dimen.media_output_dialog_header_album_icon_size);
-    }
-
-    @Override
     CharSequence getHeaderText() {
         return mMediaSwitchingController.getHeaderTitle();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
index 4e9451a..d3a81a5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
@@ -25,6 +25,9 @@
 import com.android.systemui.animation.DialogCuj
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import java.util.concurrent.Executor
 import javax.inject.Inject
 
 /** Manager to create and show a [MediaOutputDialog]. */
@@ -37,6 +40,9 @@
     private val dialogTransitionAnimator: DialogTransitionAnimator,
     private val mediaSwitchingControllerFactory: MediaSwitchingController.Factory,
 ) {
+    @Inject @Main lateinit var mainExecutor: Executor
+    @Inject @Background lateinit var backgroundExecutor: Executor
+
     companion object {
         const val INTERACTION_JANK_TAG = "media_output"
         var mediaOutputDialog: MediaOutputDialog? = null
@@ -51,7 +57,7 @@
         aboveStatusBar: Boolean,
         view: View? = null,
         userHandle: UserHandle? = null,
-        token: MediaSession.Token? = null
+        token: MediaSession.Token? = null,
     ) {
         createAndShowWithController(
             packageName,
@@ -62,8 +68,8 @@
                         it,
                         DialogCuj(
                             InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
-                            INTERACTION_JANK_TAG
-                        )
+                            INTERACTION_JANK_TAG,
+                        ),
                     )
                 },
             userHandle = userHandle,
@@ -128,15 +134,14 @@
                 controller,
                 dialogTransitionAnimator,
                 uiEventLogger,
-                includePlaybackAndAppMetadata
+                mainExecutor,
+                backgroundExecutor,
+                includePlaybackAndAppMetadata,
             )
 
         // Show the dialog.
         if (dialogTransitionAnimatorController != null) {
-            dialogTransitionAnimator.show(
-                mediaOutputDialog,
-                dialogTransitionAnimatorController,
-            )
+            dialogTransitionAnimator.show(mediaOutputDialog, dialogTransitionAnimatorController)
         } else {
             mediaOutputDialog.show()
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
index 1f2f571..9e6fa48 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
@@ -83,6 +83,8 @@
 import com.android.systemui.animation.ActivityTransitionAnimator;
 import com.android.systemui.animation.DialogTransitionAnimator;
 import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.dialog.MediaItem.MediaItemType;
 import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
@@ -114,6 +116,8 @@
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import javax.inject.Inject;
+
 /**
  * Controller for a dialog that allows users to switch media output and input devices, control
  * volume, connect to new devices, etc.
@@ -149,7 +153,8 @@
     private final NearbyMediaDevicesManager mNearbyMediaDevicesManager;
     private final Map<String, Integer> mNearbyDeviceInfoMap = new ConcurrentHashMap<>();
     private final MediaSession.Token mToken;
-
+    @Inject @Main Executor mMainExecutor;
+    @Inject @Background Executor mBackgroundExecutor;
     @VisibleForTesting
     boolean mIsRefreshing = false;
     @VisibleForTesting
@@ -163,17 +168,10 @@
     @VisibleForTesting
     MediaOutputMetricLogger mMetricLogger;
     private int mCurrentState;
-
-    private int mColorItemContent;
-    private int mColorSeekbarProgress;
-    private int mColorButtonBackground;
-    private int mColorItemBackground;
-    private int mColorConnectedItemBackground;
-    private int mColorPositiveButtonText;
-    private int mColorDialogBackground;
     private FeatureFlags mFeatureFlags;
     private UserTracker mUserTracker;
     private VolumePanelGlobalStateInteractor mVolumePanelGlobalStateInteractor;
+    @NonNull private MediaOutputColorSchemeLegacy mMediaOutputColorSchemeLegacy;
 
     public enum BroadcastNotifyDialog {
         ACTION_FIRST_LAUNCH,
@@ -230,20 +228,7 @@
         mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
         mDialogTransitionAnimator = dialogTransitionAnimator;
         mNearbyMediaDevicesManager = nearbyMediaDevicesManager;
-        mColorItemContent = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_item_main_content);
-        mColorSeekbarProgress = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_seekbar_progress);
-        mColorButtonBackground = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_button_background);
-        mColorItemBackground = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_item_background);
-        mColorConnectedItemBackground = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_connected_item_background);
-        mColorPositiveButtonText = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_solid_button_text);
-        mColorDialogBackground = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_background);
+        mMediaOutputColorSchemeLegacy = MediaOutputColorSchemeLegacy.fromSystemColors(mContext);
 
         if (enableInputRouting()) {
             mInputRouteManager = new InputRouteManager(mContext, audioManager);
@@ -568,26 +553,15 @@
         return null;
     }
 
-    void setCurrentColorScheme(WallpaperColors wallpaperColors, boolean isDarkTheme) {
-        ColorScheme mCurrentColorScheme = new ColorScheme(wallpaperColors,
+    void updateCurrentColorScheme(WallpaperColors wallpaperColors, boolean isDarkTheme) {
+        ColorScheme currentColorScheme = new ColorScheme(wallpaperColors,
                 isDarkTheme);
-        if (isDarkTheme) {
-            mColorItemContent = mCurrentColorScheme.getAccent1().getS100(); // A1-100
-            mColorSeekbarProgress = mCurrentColorScheme.getAccent2().getS600(); // A2-600
-            mColorButtonBackground = mCurrentColorScheme.getAccent1().getS300(); // A1-300
-            mColorItemBackground = mCurrentColorScheme.getNeutral2().getS800(); // N2-800
-            mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().getS800(); // A2-800
-            mColorPositiveButtonText = mCurrentColorScheme.getAccent2().getS800(); // A2-800
-            mColorDialogBackground = mCurrentColorScheme.getNeutral1().getS900(); // N1-900
-        } else {
-            mColorItemContent = mCurrentColorScheme.getAccent1().getS800(); // A1-800
-            mColorSeekbarProgress = mCurrentColorScheme.getAccent1().getS300(); // A1-300
-            mColorButtonBackground = mCurrentColorScheme.getAccent1().getS600(); // A1-600
-            mColorItemBackground = mCurrentColorScheme.getAccent2().getS50(); // A2-50
-            mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().getS100(); // A1-100
-            mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().getS50(); // N1-50
-            mColorDialogBackground = mCurrentColorScheme.getBackgroundColor();
-        }
+        mMediaOutputColorSchemeLegacy = MediaOutputColorSchemeLegacy.fromDynamicColors(
+                currentColorScheme, isDarkTheme);
+    }
+
+    MediaOutputColorSchemeLegacy getColorSchemeLegacy() {
+        return mMediaOutputColorSchemeLegacy;
     }
 
     public void refreshDataSetIfNeeded() {
@@ -598,34 +572,6 @@
         }
     }
 
-    public int getColorConnectedItemBackground() {
-        return mColorConnectedItemBackground;
-    }
-
-    public int getColorPositiveButtonText() {
-        return mColorPositiveButtonText;
-    }
-
-    public int getColorDialogBackground() {
-        return mColorDialogBackground;
-    }
-
-    public int getColorItemContent() {
-        return mColorItemContent;
-    }
-
-    public int getColorSeekbarProgress() {
-        return mColorSeekbarProgress;
-    }
-
-    public int getColorButtonBackground() {
-        return mColorButtonBackground;
-    }
-
-    public int getColorItemBackground() {
-        return mColorItemBackground;
-    }
-
     private void buildMediaItems(List<MediaDevice> devices) {
         synchronized (mMediaDevicesLock) {
             List<MediaItem> updatedMediaItems = buildMediaItems(mOutputMediaItemList, devices);
@@ -648,10 +594,6 @@
             final MediaDevice connectedMediaDevice =
                     needToHandleMutingExpectedDevice ? null
                             : getCurrentConnectedMediaDevice();
-
-            Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
-                    .map(MediaDevice::getId)
-                    .collect(Collectors.toSet());
             if (oldMediaItems.isEmpty()) {
                 if (connectedMediaDevice == null) {
                     if (DEBUG) {
@@ -660,14 +602,12 @@
                     return categorizeMediaItemsLocked(
                             /* connectedMediaDevice */ null,
                             devices,
-                            selectedDevicesIds,
                             needToHandleMutingExpectedDevice);
                 } else {
                     // selected device exist
                     return categorizeMediaItemsLocked(
                             connectedMediaDevice,
                             devices,
-                            selectedDevicesIds,
                             /* needToHandleMutingExpectedDevice */ false);
                 }
             }
@@ -701,18 +641,28 @@
                 devices.removeAll(targetMediaDevices);
                 targetMediaDevices.addAll(devices);
             }
-            List<MediaItem> finalMediaItems = new ArrayList<>();
+            List<MediaItem> finalMediaItems = targetMediaDevices.stream()
+                    .map(MediaItem::createDeviceMediaItem)
+                    .collect(Collectors.toList());
+
             boolean shouldAddFirstSeenSelectedDevice =
                     com.android.media.flags.Flags.enableOutputSwitcherDeviceGrouping();
-            for (MediaDevice targetMediaDevice : targetMediaDevices) {
-                if (shouldAddFirstSeenSelectedDevice
-                        && selectedDevicesIds.contains(targetMediaDevice.getId())) {
-                    finalMediaItems.add(MediaItem.createDeviceMediaItem(
-                            targetMediaDevice, /* isFirstDeviceInGroup */ true));
-                    shouldAddFirstSeenSelectedDevice = false;
-                } else {
-                    finalMediaItems.add(MediaItem.createDeviceMediaItem(
-                            targetMediaDevice, /* isFirstDeviceInGroup */ false));
+
+            if (shouldAddFirstSeenSelectedDevice) {
+                finalMediaItems.clear();
+                Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
+                        .map(MediaDevice::getId)
+                        .collect(Collectors.toSet());
+                for (MediaDevice targetMediaDevice : targetMediaDevices) {
+                    if (shouldAddFirstSeenSelectedDevice
+                            && selectedDevicesIds.contains(targetMediaDevice.getId())) {
+                        finalMediaItems.add(MediaItem.createDeviceMediaItem(
+                                targetMediaDevice, /* isFirstDeviceInGroup */ true));
+                        shouldAddFirstSeenSelectedDevice = false;
+                    } else {
+                        finalMediaItems.add(MediaItem.createDeviceMediaItem(
+                                targetMediaDevice, /* isFirstDeviceInGroup */ false));
+                    }
                 }
             }
             dividerItems.forEach(finalMediaItems::add);
@@ -741,9 +691,11 @@
     @GuardedBy("mMediaDevicesLock")
     private List<MediaItem> categorizeMediaItemsLocked(MediaDevice connectedMediaDevice,
             List<MediaDevice> devices,
-            Set<String> selectedDevicesIds,
             boolean needToHandleMutingExpectedDevice) {
         List<MediaItem> finalMediaItems = new ArrayList<>();
+        Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
+                .map(MediaDevice::getId)
+                .collect(Collectors.toSet());
         if (connectedMediaDevice != null) {
             selectedDevicesIds.add(connectedMediaDevice.getId());
         }
@@ -1091,7 +1043,7 @@
                         mVolumePanelGlobalStateInteractor,
                         mUserTracker);
         MediaOutputBroadcastDialog dialog = new MediaOutputBroadcastDialog(mContext, true,
-                broadcastSender, controller);
+                broadcastSender, controller, mMainExecutor, mBackgroundExecutor);
         dialog.show();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/domain/interactor/MediaInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/domain/interactor/MediaInteractor.kt
new file mode 100644
index 0000000..afed141
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/domain/interactor/MediaInteractor.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.domain.interactor
+
+import com.android.systemui.media.remedia.domain.model.MediaSessionModel
+
+/**
+ * Defines interface for classes that can provide business logic in the domain of the media controls
+ * element.
+ */
+interface MediaInteractor {
+
+    /** The list of sessions. Needs to be backed by a compose snapshot state. */
+    val sessions: List<MediaSessionModel>
+
+    /** Seek to [to], in milliseconds on the media session with the given [sessionKey]. */
+    fun seek(sessionKey: Any, to: Long)
+
+    /** Hide the representation of the media session with the given [sessionKey]. */
+    fun hide(sessionKey: Any)
+
+    /** Open media settings. */
+    fun openMediaSettings()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaActionModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaActionModel.kt
new file mode 100644
index 0000000..02e4d7a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaActionModel.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.domain.model
+
+import com.android.systemui.common.shared.model.Icon
+
+sealed interface MediaActionModel {
+    data class Action(val icon: Icon, val onClick: (() -> Unit)?) : MediaActionModel
+
+    data object ReserveSpace : MediaActionModel
+
+    data object None : MediaActionModel
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaOutputDeviceModel.kt
similarity index 68%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaOutputDeviceModel.kt
index 9b7cd70..d581ae3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaOutputDeviceModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.media.remedia.domain.model
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.common.shared.model.Icon
+
+data class MediaOutputDeviceModel(val name: String, val icon: Icon, val isInProgress: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaSessionModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaSessionModel.kt
new file mode 100644
index 0000000..e64ce73
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaSessionModel.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.domain.model
+
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.graphics.ImageBitmap
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.media.remedia.shared.model.MediaCardActionButtonLayout
+import com.android.systemui.media.remedia.shared.model.MediaColorScheme
+import com.android.systemui.media.remedia.shared.model.MediaSessionState
+
+/** Data model representing a media session. */
+@Stable
+interface MediaSessionModel {
+    /** Unique identifier. */
+    val key: Any
+
+    val appName: String
+
+    val appIcon: Icon
+
+    val background: ImageBitmap?
+
+    val colorScheme: MediaColorScheme
+
+    val title: String
+
+    val subtitle: String
+
+    val onClick: () -> Unit
+
+    /**
+     * Whether the session is currently active. Under some UIs, only currently active session should
+     * be shown.
+     */
+    val isActive: Boolean
+
+    /** Whether the session can be hidden/dismissed by the user. */
+    val canBeHidden: Boolean
+
+    /**
+     * Whether the session currently supports scrubbing (e.g. moving to a different position iin the
+     * playback.
+     */
+    val canBeScrubbed: Boolean
+
+    val state: MediaSessionState
+
+    /** The position of the playback within the current track. */
+    val positionMs: Long
+
+    /** The total duration of the current track. */
+    val durationMs: Long
+
+    val outputDevice: MediaOutputDeviceModel
+
+    /** How to lay out the action buttons. */
+    val actionButtonLayout: MediaCardActionButtonLayout
+    val playPauseAction: MediaActionModel
+    val leftAction: MediaActionModel
+    val rightAction: MediaActionModel
+    val additionalActions: List<MediaActionModel.Action>
+}
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaActionState.kt
similarity index 75%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaActionState.kt
index 6b8161c..c3ce503 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaActionState.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,6 +14,10 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package com.android.systemui.media.remedia.shared.model
 
-parcelable SoundProfileHandle;
+enum class MediaActionState {
+    Enabled,
+    Disabled,
+    Hidden,
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaCardActionButtonLayout.kt
similarity index 61%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaCardActionButtonLayout.kt
index 9b7cd70..554fb1f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaCardActionButtonLayout.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.media.remedia.shared.model
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+enum class MediaCardActionButtonLayout {
+    /** Shows the play/pause button and left/right buttons in privileged positions on the card */
+    WithPlayPause,
+    /** Shows all action buttons along the bottom row. */
+    SecondaryActionsOnly,
+}
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaColorScheme.kt
similarity index 71%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaColorScheme.kt
index 6b8161c..8dba170 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaColorScheme.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,6 +14,8 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package com.android.systemui.media.remedia.shared.model
 
-parcelable SoundProfileHandle;
+import androidx.compose.ui.graphics.Color
+
+data class MediaColorScheme(val primary: Color, val onPrimary: Color)
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/DismissibleHorizontalPager.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/DismissibleHorizontalPager.kt
new file mode 100644
index 0000000..fea5b326
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/DismissibleHorizontalPager.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.ui.compose
+
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.AnimationVector1D
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.PagerScope
+import androidx.compose.foundation.pager.PagerState
+import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.Velocity
+import androidx.compose.ui.unit.dp
+import com.android.compose.modifiers.thenIf
+import kotlinx.coroutines.launch
+
+/** State for a [DismissibleHorizontalPager] */
+class DismissibleHorizontalPagerState(
+    val isDismissible: Boolean,
+    val isScrollingEnabled: Boolean,
+    val pagerState: PagerState,
+    val offset: Animatable<Float, AnimationVector1D>,
+)
+
+/**
+ * Returns a remembered [DismissibleHorizontalPagerState] that starts at [initialPage] and has
+ * [pageCount] total pages.
+ */
+@Composable
+fun rememberDismissibleHorizontalPagerState(
+    isDismissible: Boolean = true,
+    isScrollingEnabled: Boolean = true,
+    initialPage: Int = 0,
+    pageCount: () -> Int,
+): DismissibleHorizontalPagerState {
+    val pagerState = rememberPagerState(initialPage = initialPage, pageCount = pageCount)
+    val offset = remember { Animatable(0f) }
+
+    return remember(isDismissible, isScrollingEnabled, pagerState, offset) {
+        DismissibleHorizontalPagerState(
+            isDismissible = isDismissible,
+            isScrollingEnabled = isScrollingEnabled,
+            pagerState = pagerState,
+            offset = offset,
+        )
+    }
+}
+
+/**
+ * A [HorizontalPager] that can be swiped-away to dismiss by the user when swiped farther left or
+ * right once fully scrolled to the left-most or right-most page, respectively.
+ */
+@Composable
+fun DismissibleHorizontalPager(
+    state: DismissibleHorizontalPagerState,
+    onDismissed: () -> Unit,
+    modifier: Modifier = Modifier,
+    key: ((Int) -> Any)? = null,
+    pageSpacing: Dp = 0.dp,
+    indicator: @Composable BoxScope.() -> Unit,
+    pageContent: @Composable PagerScope.(page: Int) -> Unit,
+) {
+    val scope = rememberCoroutineScope()
+
+    val nestedScrollConnection = remember {
+        object : NestedScrollConnection {
+            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+                return if (state.offset.value > 0f && available.x < 0f) {
+                    scope.launch { state.offset.snapTo(state.offset.value + available.x) }
+                    Offset(available.x, 0f)
+                } else if (state.offset.value < 0f && available.x > 0f) {
+                    scope.launch { state.offset.snapTo(state.offset.value + available.x) }
+                    Offset(available.x, 0f)
+                } else {
+                    Offset.Zero
+                }
+            }
+
+            override fun onPostScroll(
+                consumed: Offset,
+                available: Offset,
+                source: NestedScrollSource,
+            ): Offset {
+                return if (available.x > 0f) {
+                    scope.launch { state.offset.snapTo(state.offset.value + available.x) }
+                    Offset(available.x, 0f)
+                } else if (available.x < 0f) {
+                    scope.launch { state.offset.snapTo(state.offset.value + available.x) }
+                    Offset(available.x, 0f)
+                } else {
+                    Offset.Zero
+                }
+            }
+
+            override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
+                scope.launch {
+                    state.offset.animateTo(
+                        if (state.offset.value >= state.pagerState.layoutInfo.pageSize / 2f) {
+                            state.pagerState.layoutInfo.pageSize * 2f
+                        } else if (
+                            state.offset.value <= -state.pagerState.layoutInfo.pageSize / 2f
+                        ) {
+                            -state.pagerState.layoutInfo.pageSize * 2f
+                        } else {
+                            0f
+                        }
+                    )
+                    if (state.offset.value != 0f) {
+                        onDismissed()
+                    }
+                }
+                return super.onPostFling(consumed, available)
+            }
+        }
+    }
+
+    Box(modifier = modifier) {
+        HorizontalPager(
+            state = state.pagerState,
+            userScrollEnabled = state.isScrollingEnabled,
+            key = key,
+            pageSpacing = pageSpacing,
+            pageContent = pageContent,
+            modifier =
+                Modifier.thenIf(state.isDismissible) {
+                    Modifier.nestedScroll(nestedScrollConnection).graphicsLayer {
+                        translationX = state.offset.value
+                    }
+                },
+        )
+
+        indicator()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt
index 1e69549..9c65680 100644
--- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt
@@ -14,45 +14,861 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalMaterial3Api::class)
+
 package com.android.systemui.media.remedia.ui.compose
 
+import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.animation.Crossfade
+import androidx.compose.animation.animateColorAsState
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.RepeatMode
 import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.tween
 import androidx.compose.animation.graphics.res.animatedVectorResource
 import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
 import androidx.compose.animation.graphics.vector.AnimatedImageVector
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.hoverable
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButtonDefaults
 import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Slider
+import androidx.compose.material3.SliderColors
+import androidx.compose.material3.SliderDefaults.colors
+import androidx.compose.material3.SliderState
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.Stable
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.center
+import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.CompositingStrategy
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.drawscope.clipRect
+import androidx.compose.ui.graphics.drawscope.translate
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastForEachIndexed
 import com.android.compose.PlatformButton
 import com.android.compose.PlatformIconButton
+import com.android.compose.PlatformOutlinedButton
 import com.android.compose.animation.scene.ContentScope
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
+import com.android.compose.animation.scene.transitions
+import com.android.compose.ui.graphics.painter.rememberDrawablePainter
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.common.ui.compose.PagerDots
 import com.android.systemui.common.ui.compose.load
+import com.android.systemui.communal.ui.compose.extensions.detectLongPressGesture
+import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.media.remedia.shared.model.MediaCardActionButtonLayout
+import com.android.systemui.media.remedia.shared.model.MediaColorScheme
 import com.android.systemui.media.remedia.shared.model.MediaSessionState
+import com.android.systemui.media.remedia.ui.viewmodel.MediaCardGutsViewModel
+import com.android.systemui.media.remedia.ui.viewmodel.MediaCardViewModel
+import com.android.systemui.media.remedia.ui.viewmodel.MediaCarouselVisibility
+import com.android.systemui.media.remedia.ui.viewmodel.MediaNavigationViewModel
 import com.android.systemui.media.remedia.ui.viewmodel.MediaOutputSwitcherChipViewModel
 import com.android.systemui.media.remedia.ui.viewmodel.MediaPlayPauseActionViewModel
 import com.android.systemui.media.remedia.ui.viewmodel.MediaSecondaryActionViewModel
+import com.android.systemui.media.remedia.ui.viewmodel.MediaViewModel
+import kotlin.math.max
+
+/**
+ * Renders a media controls UI element.
+ *
+ * This composable supports a multitude of presentation styles/layouts controlled by the
+ * [presentationStyle] parameter. If the card carousel can be swiped away to dismiss by the user,
+ * the [onDismissed] callback will be invoked when/if that happens.
+ */
+@Composable
+fun Media(
+    viewModelFactory: MediaViewModel.Factory,
+    presentationStyle: MediaPresentationStyle,
+    behavior: MediaUiBehavior,
+    onDismissed: () -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    val context = LocalContext.current
+    val viewModel: MediaViewModel =
+        rememberViewModel("Media.viewModel") {
+            viewModelFactory.create(
+                context = context,
+                carouselVisibility = behavior.carouselVisibility,
+            )
+        }
+
+    CardCarousel(
+        viewModel = viewModel,
+        presentationStyle = presentationStyle,
+        behavior = behavior,
+        onDismissed = onDismissed,
+        modifier = modifier,
+    )
+}
+
+/**
+ * Renders a media controls carousel of cards.
+ *
+ * This composable supports a multitude of presentation styles/layouts controlled by the
+ * [presentationStyle] parameter. The behavior is controlled by [behavior]. If
+ * [MediaUiBehavior.isCarouselDismissible] is `true`, the [onDismissed] callback will be invoked
+ * when/if that happens.
+ */
+@Composable
+private fun CardCarousel(
+    viewModel: MediaViewModel,
+    presentationStyle: MediaPresentationStyle,
+    behavior: MediaUiBehavior,
+    onDismissed: () -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    AnimatedVisibility(visible = viewModel.isCarouselVisible, modifier = modifier) {
+        CardCarouselContent(
+            viewModel = viewModel,
+            presentationStyle = presentationStyle,
+            behavior = behavior,
+            onDismissed = onDismissed,
+        )
+    }
+}
+
+@Composable
+private fun CardCarouselContent(
+    viewModel: MediaViewModel,
+    presentationStyle: MediaPresentationStyle,
+    behavior: MediaUiBehavior,
+    onDismissed: () -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    val pagerState =
+        rememberDismissibleHorizontalPagerState(
+            isDismissible = behavior.isCarouselDismissible,
+            isScrollingEnabled = behavior.isCarouselScrollingEnabled,
+        ) {
+            viewModel.cards.size
+        }
+
+    val roundedCornerShape = RoundedCornerShape(32.dp)
+
+    LaunchedEffect(pagerState.pagerState.currentPage) {
+        viewModel.onCardSelected(pagerState.pagerState.currentPage)
+    }
+
+    DismissibleHorizontalPager(
+        state = pagerState,
+        onDismissed = onDismissed,
+        pageSpacing = 8.dp,
+        key = { index -> viewModel.cards[index].key },
+        indicator = {
+            if (pagerState.pagerState.pageCount > 1) {
+                PagerDots(
+                    pagerState = pagerState.pagerState,
+                    activeColor = Color(0xffdee0ff),
+                    nonActiveColor = Color(0xffa7a9ca),
+                    dotSize = 6.dp,
+                    spaceSize = 6.dp,
+                    modifier =
+                        Modifier.align(Alignment.BottomCenter).padding(8.dp).graphicsLayer {
+                            translationX = pagerState.offset.value
+                        },
+                )
+            }
+        },
+        modifier = modifier.padding(8.dp).clip(roundedCornerShape),
+    ) { index ->
+        Card(
+            viewModel = viewModel.cards[index],
+            presentationStyle = presentationStyle,
+            modifier = Modifier.clip(roundedCornerShape),
+        )
+    }
+}
+
+/** Renders the UI of a single media card. */
+@Composable
+private fun Card(
+    viewModel: MediaCardViewModel,
+    presentationStyle: MediaPresentationStyle,
+    modifier: Modifier = Modifier,
+) {
+    val stlState =
+        rememberMutableSceneTransitionLayoutState(
+            initialScene = presentationStyle.toScene(),
+            transitions = Media.Transitions,
+        )
+
+    // Each time the presentation style changes, animate to the corresponding scene.
+    LaunchedEffect(presentationStyle) {
+        stlState.setTargetScene(targetScene = presentationStyle.toScene(), animationScope = this)
+    }
+
+    Box(modifier) {
+        if (stlState.currentScene != Media.Scenes.Compact) {
+            CardBackground(image = viewModel.background, modifier = Modifier.matchParentSize())
+        }
+
+        key(stlState) {
+            SceneTransitionLayout(state = stlState) {
+                scene(Media.Scenes.Default) {
+                    CardForeground(viewModel = viewModel, threeRows = true, fillHeight = false)
+                }
+
+                scene(Media.Scenes.Compressed) {
+                    CardForeground(viewModel = viewModel, threeRows = false, fillHeight = false)
+                }
+
+                scene(Media.Scenes.Compact) { CompactCardForeground(viewModel = viewModel) }
+            }
+        }
+    }
+}
+
+@Composable
+private fun rememberAnimatedColorScheme(colorScheme: MediaColorScheme): AnimatedColorScheme {
+    val animatedPrimary by animateColorAsState(targetValue = colorScheme.primary)
+    val animatedOnPrimary by animateColorAsState(targetValue = colorScheme.onPrimary)
+
+    return remember {
+        object : AnimatedColorScheme {
+            override val primary: Color
+                get() = animatedPrimary
+
+            override val onPrimary: Color
+                get() = animatedOnPrimary
+        }
+    }
+}
+
+/**
+ * Renders the foreground of a card, including all UI content and the internal "guts".
+ *
+ * If [threeRows] is `true`, the layout will be organized as three horizontal rows; if `false`, two
+ * rows will be used, resulting in a more compact layout.
+ *
+ * If [fillHeight] is `true`, the card will grow vertically to fill all available space in its
+ * parent. If not, it'll only be as tall as needed to show its UI.
+ */
+@Composable
+private fun ContentScope.CardForeground(
+    viewModel: MediaCardViewModel,
+    threeRows: Boolean,
+    fillHeight: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    // Can't use a Crossfade composable because of the custom layout logic below. Animate the alpha
+    // of the guts (and, indirectly, of the content) from here.
+    val gutsAlphaAnimatable = remember { Animatable(0f) }
+    val isGutsVisible = viewModel.guts.isVisible
+    LaunchedEffect(isGutsVisible) { gutsAlphaAnimatable.animateTo(if (isGutsVisible) 1f else 0f) }
+
+    val colorScheme = rememberAnimatedColorScheme(viewModel.colorScheme)
+
+    // Use a custom layout to measure the content even if the content is being hidden because the
+    // internal guts are showing. This is needed because only the content knows the size the of the
+    // card and the guts are set to be the same size of the content.
+    Layout(
+        content = {
+            CardForegroundContent(
+                viewModel = viewModel,
+                threeRows = threeRows,
+                fillHeight = fillHeight,
+                colorScheme = colorScheme,
+                modifier =
+                    Modifier.graphicsLayer {
+                        compositingStrategy = CompositingStrategy.ModulateAlpha
+                        alpha = 1f - gutsAlphaAnimatable.value
+                    },
+            )
+
+            CardGuts(
+                viewModel = viewModel.guts,
+                colorScheme = colorScheme,
+                modifier =
+                    Modifier.graphicsLayer {
+                        compositingStrategy = CompositingStrategy.ModulateAlpha
+                        alpha = gutsAlphaAnimatable.value
+                    },
+            )
+        },
+        modifier = modifier,
+    ) { measurables, constraints ->
+        check(measurables.size == 2)
+        val contentPlaceable = measurables[0].measure(constraints)
+        // Guts should always have the exact dimensions as the content, even if we don't show the
+        // content.
+        val gutsPlaceable =
+            measurables[1].measure(
+                Constraints.fixed(contentPlaceable.width, contentPlaceable.height)
+            )
+
+        layout(contentPlaceable.measuredWidth, contentPlaceable.measuredHeight) {
+            if (!viewModel.guts.isVisible || gutsAlphaAnimatable.isRunning) {
+                contentPlaceable.place(0, 0)
+            }
+            if (viewModel.guts.isVisible || gutsAlphaAnimatable.isRunning) {
+                gutsPlaceable.place(0, 0)
+            }
+        }
+    }
+}
+
+@Composable
+private fun ContentScope.CardForegroundContent(
+    viewModel: MediaCardViewModel,
+    threeRows: Boolean,
+    fillHeight: Boolean,
+    colorScheme: AnimatedColorScheme,
+    modifier: Modifier = Modifier,
+) {
+    Column(
+        modifier =
+            modifier
+                .combinedClickable(
+                    onClick = viewModel.onClick,
+                    onLongClick = viewModel.onLongClick,
+                    onClickLabel = viewModel.onClickLabel,
+                )
+                .padding(16.dp)
+    ) {
+        // Always add the first/top row, regardless of presentation style.
+        Row(verticalAlignment = Alignment.CenterVertically) {
+            // Icon.
+            Icon(
+                icon = viewModel.icon,
+                tint = colorScheme.primary,
+                modifier = Modifier.size(24.dp).clip(CircleShape),
+            )
+            Spacer(modifier = Modifier.weight(1f))
+            viewModel.outputSwitcherChips.fastForEach { chip ->
+                OutputSwitcherChip(
+                    viewModel = chip,
+                    colorScheme = colorScheme,
+                    modifier = Modifier.padding(start = 8.dp),
+                )
+            }
+        }
+
+        // If the card is taller than necessary to show all the rows, this adds spacing
+        // between the top row and the rows below, anchoring the next rows to the bottom
+        // of the card.
+        if (fillHeight) {
+            Spacer(Modifier.weight(1f))
+        }
+
+        if (threeRows) {
+            // Three row presentation style.
+            //
+            // Second row.
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                modifier = Modifier.padding(top = 16.dp),
+            ) {
+                Metadata(
+                    title = viewModel.title,
+                    subtitle = viewModel.subtitle,
+                    color = Color.White,
+                    modifier = Modifier.weight(1f).padding(end = 8.dp),
+                )
+
+                if (viewModel.actionButtonLayout == MediaCardActionButtonLayout.WithPlayPause) {
+                    AnimatedVisibility(visible = viewModel.playPauseAction != null) {
+                        PlayPauseAction(
+                            viewModel = checkNotNull(viewModel.playPauseAction),
+                            buttonWidth = 48.dp,
+                            buttonColor = colorScheme.primary,
+                            iconColor = colorScheme.onPrimary,
+                            buttonCornerRadius = { isPlaying -> if (isPlaying) 16.dp else 48.dp },
+                        )
+                    }
+                }
+            }
+
+            // Third row.
+            Row(
+                horizontalArrangement = Arrangement.spacedBy(8.dp),
+                verticalAlignment = Alignment.CenterVertically,
+                modifier = Modifier.padding(top = 24.dp),
+            ) {
+                Navigation(
+                    viewModel = viewModel.navigation,
+                    isSeekBarVisible = true,
+                    areActionsVisible =
+                        viewModel.actionButtonLayout == MediaCardActionButtonLayout.WithPlayPause,
+                    modifier = Modifier.weight(1f),
+                )
+
+                viewModel.additionalActions.fastForEachIndexed { index, action ->
+                    SecondaryAction(
+                        viewModel = action,
+                        element = Media.Elements.additionalActionButton(index),
+                    )
+                }
+            }
+        } else {
+            // Two row presentation style.
+            //
+            // Bottom row.
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                modifier = Modifier.padding(top = 36.dp),
+            ) {
+                Metadata(
+                    title = viewModel.title,
+                    subtitle = viewModel.subtitle,
+                    color = Color.White,
+                    modifier = Modifier.weight(1f).padding(end = 8.dp),
+                )
+
+                Navigation(
+                    viewModel = viewModel.navigation,
+                    isSeekBarVisible = false,
+                    areActionsVisible =
+                        viewModel.actionButtonLayout == MediaCardActionButtonLayout.WithPlayPause,
+                    modifier = Modifier.padding(end = 8.dp),
+                )
+
+                if (
+                    viewModel.actionButtonLayout == MediaCardActionButtonLayout.SecondaryActionsOnly
+                ) {
+                    viewModel.additionalActions.fastForEachIndexed { index, action ->
+                        SecondaryAction(
+                            viewModel = action,
+                            element = Media.Elements.additionalActionButton(index),
+                            modifier = Modifier.padding(end = 8.dp),
+                        )
+                    }
+                }
+
+                AnimatedVisibility(visible = viewModel.playPauseAction != null) {
+                    PlayPauseAction(
+                        viewModel = checkNotNull(viewModel.playPauseAction),
+                        buttonWidth = 48.dp,
+                        buttonColor = colorScheme.primary,
+                        iconColor = colorScheme.onPrimary,
+                        buttonCornerRadius = { isPlaying -> if (isPlaying) 16.dp else 48.dp },
+                    )
+                }
+            }
+        }
+    }
+}
+
+/**
+ * Renders a simplified version of [CardForeground] that puts everything on a single row and doesn't
+ * support the guts.
+ */
+@Composable
+private fun ContentScope.CompactCardForeground(
+    viewModel: MediaCardViewModel,
+    modifier: Modifier = Modifier,
+) {
+    Row(
+        horizontalArrangement = Arrangement.spacedBy(16.dp),
+        verticalAlignment = Alignment.CenterVertically,
+        modifier =
+            modifier
+                .clickable(onClick = viewModel.onClick, onClickLabel = viewModel.onClickLabel)
+                .background(MaterialTheme.colorScheme.surfaceContainer)
+                .padding(16.dp),
+    ) {
+        Icon(
+            icon = viewModel.icon,
+            tint = MaterialTheme.colorScheme.onSurface,
+            modifier = Modifier.size(24.dp),
+        )
+
+        Metadata(
+            title = viewModel.title,
+            subtitle = viewModel.subtitle,
+            color = MaterialTheme.colorScheme.onSurface,
+            modifier = Modifier.weight(1f),
+        )
+
+        SecondaryAction(
+            viewModel = viewModel.outputSwitcherChipButton,
+            element = Media.Elements.OutputSwitcherButton,
+            iconColor = MaterialTheme.colorScheme.onSurface,
+        )
+
+        val rightAction = (viewModel.navigation as? MediaNavigationViewModel.Showing)?.right
+        if (rightAction != null) {
+            SecondaryAction(
+                viewModel = rightAction,
+                element = Media.Elements.NextButton,
+                iconColor = MaterialTheme.colorScheme.onSurface,
+            )
+        }
+
+        AnimatedVisibility(visible = viewModel.playPauseAction != null) {
+            PlayPauseAction(
+                viewModel = checkNotNull(viewModel.playPauseAction),
+                buttonWidth = 72.dp,
+                buttonColor = MaterialTheme.colorScheme.primaryContainer,
+                iconColor = MaterialTheme.colorScheme.onPrimaryContainer,
+                buttonCornerRadius = { isPlaying -> if (isPlaying) 16.dp else 24.dp },
+            )
+        }
+    }
+}
+
+/** Renders the background of a card, loading the artwork and showing an overlay on top of it. */
+@Composable
+private fun CardBackground(image: ImageBitmap?, modifier: Modifier = Modifier) {
+    Crossfade(targetState = image, modifier = modifier) { imageOrNull ->
+        if (imageOrNull != null) {
+            // Loaded art.
+            val gradientBaseColor = MaterialTheme.colorScheme.onSurface
+            Image(
+                bitmap = imageOrNull,
+                contentDescription = null,
+                contentScale = ContentScale.Crop,
+                modifier =
+                    Modifier.fillMaxSize().drawWithContent {
+                        // Draw the content (loaded art).
+                        drawContent()
+
+                        if (image != null) {
+                            // Then draw the overlay.
+                            drawRect(
+                                brush =
+                                    Brush.radialGradient(
+                                        0f to gradientBaseColor.copy(alpha = 0.65f),
+                                        1f to gradientBaseColor.copy(alpha = 0.75f),
+                                        center = size.center,
+                                        radius = max(size.width, size.height) / 2,
+                                    )
+                            )
+                        }
+                    },
+            )
+        } else {
+            // Placeholder.
+            Box(Modifier.background(MaterialTheme.colorScheme.onSurface).fillMaxSize())
+        }
+    }
+}
+
+/**
+ * Renders the navigation UI (seek bar and/or previous/next buttons).
+ *
+ * If [isSeekBarVisible] is `false`, the seek bar will not be included in the layout, even if it
+ * would otherwise be showing based on the view-model alone. This is meant for callers to decide
+ * whether they'd like to show the seek bar in addition to the prev/next buttons or just show the
+ * buttons.
+ *
+ * If [areActionsVisible] is `false`, the left/right buttons to the left and right of the seek bar
+ * will not be included in the layout.
+ */
+@Composable
+private fun ContentScope.Navigation(
+    viewModel: MediaNavigationViewModel,
+    isSeekBarVisible: Boolean,
+    areActionsVisible: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    when (viewModel) {
+        is MediaNavigationViewModel.Showing -> {
+            Row(
+                horizontalArrangement = Arrangement.spacedBy(8.dp),
+                verticalAlignment = Alignment.CenterVertically,
+                modifier = modifier,
+            ) {
+                if (areActionsVisible) {
+                    SecondaryAction(viewModel = viewModel.left, element = Media.Elements.PrevButton)
+                }
+
+                val interactionSource = remember { MutableInteractionSource() }
+                val colors =
+                    colors(
+                        activeTrackColor = Color.White,
+                        inactiveTrackColor = Color.White.copy(alpha = 0.3f),
+                        thumbColor = Color.White,
+                    )
+                if (isSeekBarVisible) {
+                    // To allow the seek bar slider to fade in and out, it's tagged as an element.
+                    Element(key = Media.Elements.SeekBarSlider, modifier = Modifier.weight(1f)) {
+                        Slider(
+                            interactionSource = interactionSource,
+                            value = viewModel.progress,
+                            onValueChange = { progress -> viewModel.onScrubChange(progress) },
+                            onValueChangeFinished = { viewModel.onScrubFinished() },
+                            colors = colors,
+                            thumb = {
+                                SeekBarThumb(interactionSource = interactionSource, colors = colors)
+                            },
+                            track = { sliderState ->
+                                SeekBarTrack(
+                                    sliderState = sliderState,
+                                    isSquiggly = viewModel.isSquiggly,
+                                    colors = colors,
+                                    modifier = Modifier.fillMaxWidth(),
+                                )
+                            },
+                            modifier = Modifier.fillMaxWidth(),
+                        )
+                    }
+                }
+
+                if (areActionsVisible) {
+                    SecondaryAction(
+                        viewModel = viewModel.right,
+                        element = Media.Elements.NextButton,
+                    )
+                }
+            }
+        }
+
+        is MediaNavigationViewModel.Hidden -> Unit
+    }
+}
+
+/** Renders the thumb of the seek bar. */
+@Composable
+private fun SeekBarThumb(
+    interactionSource: MutableInteractionSource,
+    colors: SliderColors,
+    modifier: Modifier = Modifier,
+) {
+    val interactions = remember { mutableStateListOf<Interaction>() }
+    LaunchedEffect(interactionSource) {
+        interactionSource.interactions.collect { interaction ->
+            when (interaction) {
+                is PressInteraction.Press -> interactions.add(interaction)
+                is PressInteraction.Release -> interactions.remove(interaction.press)
+                is PressInteraction.Cancel -> interactions.remove(interaction.press)
+                is DragInteraction.Start -> interactions.add(interaction)
+                is DragInteraction.Stop -> interactions.remove(interaction.start)
+                is DragInteraction.Cancel -> interactions.remove(interaction.start)
+            }
+        }
+    }
+
+    Spacer(
+        modifier
+            .size(width = 4.dp, height = 16.dp)
+            .hoverable(interactionSource = interactionSource)
+            .background(color = colors.thumbColor, shape = RoundedCornerShape(16.dp))
+    )
+}
+
+/**
+ * Renders the track of the seek bar.
+ *
+ * If [isSquiggly] is `true`, the part to the left of the thumb will animate a squiggly line that
+ * oscillates up and down. The [waveLength] and [amplitude] control the geometry of the squiggle and
+ * the [waveSpeedDpPerSec] controls the speed by which it seems to "move" horizontally.
+ */
+@Composable
+private fun SeekBarTrack(
+    sliderState: SliderState,
+    isSquiggly: Boolean,
+    colors: SliderColors,
+    modifier: Modifier = Modifier,
+    waveLength: Dp = 20.dp,
+    amplitude: Dp = 3.dp,
+    waveSpeedDpPerSec: Dp = 8.dp,
+) {
+    // Animating the amplitude allows the squiggle to gradually grow to its full height or shrink
+    // back to a flat line as needed.
+    val animatedAmplitude by
+        animateDpAsState(
+            targetValue = if (isSquiggly) amplitude else 0.dp,
+            label = "SeekBarTrack.amplitude",
+        )
+
+    // This animates the horizontal movement of the squiggle.
+    val animatedWaveOffset = remember { Animatable(0f) }
+
+    LaunchedEffect(isSquiggly) {
+        if (isSquiggly) {
+            animatedWaveOffset.snapTo(0f)
+            animatedWaveOffset.animateTo(
+                targetValue = 1f,
+                animationSpec =
+                    infiniteRepeatable(
+                        animation =
+                            tween(
+                                durationMillis = (1000 * (waveLength / waveSpeedDpPerSec)).toInt(),
+                                easing = LinearEasing,
+                            ),
+                        repeatMode = RepeatMode.Restart,
+                    ),
+            )
+        }
+    }
+
+    // Render the track.
+    Canvas(modifier = modifier) {
+        val thumbPositionPx = size.width * sliderState.value
+
+        // The squiggly part before the thumb.
+        if (thumbPositionPx > 0) {
+            val amplitudePx = amplitude.toPx()
+            val animatedAmplitudePx = animatedAmplitude.toPx()
+            val waveLengthPx = waveLength.toPx()
+
+            val path =
+                Path().apply {
+                    val halfWaveLengthPx = waveLengthPx / 2
+                    val halfWaveCount = (thumbPositionPx / halfWaveLengthPx).toInt()
+
+                    repeat(halfWaveCount + 3) { index ->
+                        // Draw a half wave (either a hill or a valley shape starting and ending on
+                        // the horizontal center).
+                        relativeQuadraticTo(
+                            // The control point for the bezier curve is on top of the peak of the
+                            // hill or the very center bottom of the valley shape.
+                            dx1 = halfWaveLengthPx / 2,
+                            dy1 = if (index % 2 == 0) -animatedAmplitudePx else animatedAmplitudePx,
+                            // Advance horizontally, half a wave length at a time.
+                            dx2 = halfWaveLengthPx,
+                            dy2 = 0f,
+                        )
+                    }
+                }
+
+            // Now that the squiggle is rendered a bit past the thumb, clip off the part that passed
+            // the thumb. It's easier to clip the extra squiggle than to figure out the bezier curve
+            // for part of a hill/valley.
+            clipRect(
+                left = 0f,
+                top = -amplitudePx,
+                right = thumbPositionPx,
+                bottom = amplitudePx * 2,
+            ) {
+                translate(left = -waveLengthPx * animatedWaveOffset.value, top = 0f) {
+                    // Actually render the squiggle.
+                    drawPath(
+                        path = path,
+                        color = colors.activeTrackColor,
+                        style = Stroke(width = 2.dp.toPx(), cap = StrokeCap.Round),
+                    )
+                }
+            }
+        }
+
+        // The flat line after the thumb.
+        drawLine(
+            color = colors.inactiveTrackColor,
+            start = Offset(thumbPositionPx, 0f),
+            end = Offset(size.width, 0f),
+            strokeWidth = 2.dp.toPx(),
+            cap = StrokeCap.Round,
+        )
+    }
+}
+
+/** Renders the internal "guts" of a card. */
+@Composable
+private fun CardGuts(
+    viewModel: MediaCardGutsViewModel,
+    colorScheme: AnimatedColorScheme,
+    modifier: Modifier = Modifier,
+) {
+    Box(
+        modifier =
+            modifier.pointerInput(Unit) { detectLongPressGesture { viewModel.onLongClick() } }
+    ) {
+        // Settings button.
+        Icon(
+            icon = checkNotNull(viewModel.settingsButton.icon),
+            modifier =
+                Modifier.align(Alignment.TopEnd).padding(top = 16.dp, end = 16.dp).clickable {
+                    viewModel.settingsButton.onClick()
+                },
+        )
+
+        //  Content.
+        Column(
+            horizontalAlignment = Alignment.CenterHorizontally,
+            verticalArrangement = Arrangement.spacedBy(16.dp),
+            modifier =
+                Modifier.align(Alignment.BottomCenter)
+                    .fillMaxWidth()
+                    .padding(start = 16.dp, end = 32.dp, bottom = 40.dp),
+        ) {
+            Text(text = viewModel.text, color = Color.White)
+
+            Row(
+                horizontalArrangement = Arrangement.spacedBy(8.dp),
+                verticalAlignment = Alignment.CenterVertically,
+            ) {
+                PlatformButton(
+                    onClick = viewModel.primaryAction.onClick,
+                    colors = ButtonDefaults.buttonColors(containerColor = Color.White),
+                ) {
+                    Text(
+                        text = checkNotNull(viewModel.primaryAction.text),
+                        color = colorScheme.onPrimary,
+                    )
+                }
+
+                viewModel.secondaryAction?.let { button ->
+                    PlatformOutlinedButton(
+                        onClick = button.onClick,
+                        border = BorderStroke(width = 1.dp, color = Color.White),
+                    ) {
+                        Text(text = checkNotNull(button.text), color = Color.White)
+                    }
+                }
+            }
+        }
+    }
+}
 
 /** Renders the metadata labels of a track. */
 @Composable
@@ -95,28 +911,22 @@
 @Composable
 private fun OutputSwitcherChip(
     viewModel: MediaOutputSwitcherChipViewModel,
+    colorScheme: AnimatedColorScheme,
     modifier: Modifier = Modifier,
 ) {
     PlatformButton(
         onClick = viewModel.onClick,
-        colors =
-            ButtonDefaults.buttonColors(
-                containerColor = LocalAndroidColorScheme.current.primaryFixed
-            ),
+        colors = ButtonDefaults.buttonColors(containerColor = colorScheme.primary),
         contentPadding = PaddingValues(start = 8.dp, end = 12.dp, top = 4.dp, bottom = 4.dp),
         modifier = modifier.height(24.dp),
     ) {
-        Icon(
-            icon = viewModel.icon,
-            tint = LocalAndroidColorScheme.current.onPrimaryFixed,
-            modifier = Modifier.size(16.dp),
-        )
+        Icon(icon = viewModel.icon, tint = colorScheme.onPrimary, modifier = Modifier.size(16.dp))
         viewModel.text?.let {
             Spacer(Modifier.size(4.dp))
             Text(
                 text = viewModel.text,
                 style = MaterialTheme.typography.bodySmall,
-                color = LocalAndroidColorScheme.current.onPrimaryFixed,
+                color = colorScheme.onPrimary,
             )
         }
     }
@@ -140,7 +950,8 @@
     // This element can be animated when switching between scenes inside a media card.
     Element(key = Media.Elements.PlayPauseButton, modifier = modifier) {
         PlatformButton(
-            onClick = viewModel.onClick,
+            onClick = viewModel.onClick ?: {},
+            enabled = viewModel.onClick != null,
             colors = ButtonDefaults.buttonColors(containerColor = buttonColor),
             shape = RoundedCornerShape(cornerRadius),
             modifier = Modifier.size(width = buttonWidth, height = 48.dp),
@@ -148,22 +959,29 @@
             when (viewModel.state) {
                 is MediaSessionState.Playing,
                 is MediaSessionState.Paused -> {
-                    // TODO(b/399860531): load this expensive-to-load animated vector drawable off
-                    //  the main thread.
-                    val iconResource = checkNotNull(viewModel.icon)
-                    Icon(
-                        painter =
-                            rememberAnimatedVectorPainter(
-                                animatedImageVector =
-                                    AnimatedImageVector.animatedVectorResource(
-                                        id = iconResource.res
-                                    ),
-                                atEnd = viewModel.state == MediaSessionState.Playing,
-                            ),
-                        contentDescription = iconResource.contentDescription?.load(),
-                        tint = iconColor,
-                        modifier = Modifier.size(24.dp),
-                    )
+                    val painterOrNull =
+                        when (viewModel.icon) {
+                            // TODO(b/399860531): load this expensive-to-load animated vector
+                            //  drawable off the main thread.
+                            is Icon.Resource ->
+                                rememberAnimatedVectorPainter(
+                                    animatedImageVector =
+                                        AnimatedImageVector.animatedVectorResource(
+                                            id = viewModel.icon.res
+                                        ),
+                                    atEnd = viewModel.state == MediaSessionState.Playing,
+                                )
+                            is Icon.Loaded -> rememberDrawablePainter(viewModel.icon.drawable)
+                            null -> null
+                        }
+                    painterOrNull?.let { painter ->
+                        Icon(
+                            painter = painter,
+                            contentDescription = viewModel.icon?.contentDescription?.load(),
+                            tint = iconColor,
+                            modifier = Modifier.size(24.dp),
+                        )
+                    }
                 }
                 is MediaSessionState.Buffering -> {
                     CircularProgressIndicator(color = iconColor, modifier = Modifier.size(24.dp))
@@ -186,7 +1004,7 @@
     element: ElementKey? = null,
     iconColor: Color = Color.White,
 ) {
-    if (element != null) {
+    if (viewModel !is MediaSecondaryActionViewModel.None && element != null) {
         Element(key = element, modifier = modifier) {
             SecondaryActionContent(viewModel = viewModel, iconColor = iconColor)
         }
@@ -202,19 +1020,74 @@
     iconColor: Color,
     modifier: Modifier = Modifier,
 ) {
-    PlatformIconButton(
-        onClick = viewModel.onClick,
-        iconResource = (viewModel.icon as Icon.Resource).res,
-        contentDescription = viewModel.icon.contentDescription?.load(),
-        colors = IconButtonDefaults.iconButtonColors(contentColor = iconColor),
-        enabled = viewModel.isEnabled,
-        modifier = modifier.size(48.dp).padding(13.dp),
-    )
+    val sharedModifier = modifier.size(48.dp).padding(13.dp)
+    when (viewModel) {
+        is MediaSecondaryActionViewModel.Action ->
+            PlatformIconButton(
+                onClick = viewModel.onClick ?: {},
+                iconResource = (viewModel.icon as Icon.Resource).res,
+                contentDescription = viewModel.icon.contentDescription?.load(),
+                colors = IconButtonDefaults.iconButtonColors(contentColor = iconColor),
+                enabled = viewModel.onClick != null,
+                modifier = sharedModifier,
+            )
+
+        is MediaSecondaryActionViewModel.ReserveSpace -> Spacer(modifier = sharedModifier)
+
+        is MediaSecondaryActionViewModel.None -> Unit
+    }
+}
+
+/** Enumerates all supported media presentation styles. */
+enum class MediaPresentationStyle {
+    /** The "normal" 3-row carousel look. */
+    Default,
+    /** Similar to [Default] but not as tall (2-row carousel look). */
+    Compressed,
+    /** A special single-row treatment that fits nicely in quick settings. */
+    Compact,
+}
+
+data class MediaUiBehavior(
+    val isCarouselDismissible: Boolean = true,
+    val isCarouselScrollingEnabled: Boolean = true,
+    val carouselVisibility: MediaCarouselVisibility = MediaCarouselVisibility.WhenNotEmpty,
+    val isFalsingProtectionNeeded: Boolean = false,
+)
+
+@Stable
+private interface AnimatedColorScheme {
+    val primary: Color
+    val onPrimary: Color
 }
 
 private object Media {
 
     /**
+     * Scenes.
+     *
+     * The implementation uses a [SceneTransitionLayout] to smoothly animate transitions between
+     * different card layouts. Each card layout is identified as its own "scene" and the STL
+     * framework takes care of animating the layouts and their elements as the card morphs between
+     * scenes.
+     */
+    object Scenes {
+        /** The "normal" 3-row carousel look. */
+        val Default = SceneKey("default")
+        /** Similar to [Default] but not as tall (2-row carousel look). */
+        val Compressed = SceneKey("compressed")
+        /** A special single-row treatment that fits nicely in quick settings. */
+        val Compact = SceneKey("compact")
+    }
+
+    /** Definitions of how scene changes are transition-animated. */
+    val Transitions = transitions {
+        from(Scenes.Default, to = Scenes.Compact) {}
+        from(Scenes.Default, to = Scenes.Compressed) { fade(Elements.SeekBarSlider) }
+        from(Scenes.Compact, to = Scenes.Compressed) { fade(Elements.SeekBarSlider) }
+    }
+
+    /**
      * Element keys.
      *
      * Composables that are wrapped in [ContentScope.Element] with one of these as their `key`
@@ -227,5 +1100,21 @@
     object Elements {
         val PlayPauseButton = ElementKey("play_pause")
         val Metadata = ElementKey("metadata")
+        val PrevButton = ElementKey("prev")
+        val NextButton = ElementKey("next")
+        val SeekBarSlider = ElementKey("seek_bar_slider")
+        val OutputSwitcherButton = ElementKey("output_switcher")
+
+        fun additionalActionButton(index: Int): ElementKey {
+            return ElementKey("additional_action_$index")
+        }
+    }
+}
+
+private fun MediaPresentationStyle.toScene(): SceneKey {
+    return when (this) {
+        MediaPresentationStyle.Default -> Media.Scenes.Default
+        MediaPresentationStyle.Compressed -> Media.Scenes.Compressed
+        MediaPresentationStyle.Compact -> Media.Scenes.Compact
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardGutsViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardGutsViewModel.kt
new file mode 100644
index 0000000..61e3bdc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardGutsViewModel.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.ui.viewmodel
+
+data class MediaCardGutsViewModel(
+    val isVisible: Boolean,
+    val text: String,
+    val primaryAction: MediaGutsButtonViewModel,
+    val secondaryAction: MediaGutsButtonViewModel? = null,
+    val settingsButton: MediaGutsSettingsButtonViewModel,
+    val onLongClick: () -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardViewModel.kt
new file mode 100644
index 0000000..833a04d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardViewModel.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.ui.viewmodel
+
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.graphics.ImageBitmap
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.media.remedia.shared.model.MediaCardActionButtonLayout
+import com.android.systemui.media.remedia.shared.model.MediaColorScheme
+
+/** Models UI state for a media card. */
+@Stable
+interface MediaCardViewModel {
+    /**
+     * Identifier. Must be unique across all media cards currently shown, to help the horizontal
+     * pager in the UI.
+     */
+    val key: Any
+
+    val icon: Icon
+
+    val background: ImageBitmap?
+
+    val colorScheme: MediaColorScheme
+
+    val title: String
+
+    val subtitle: String
+
+    val actionButtonLayout: MediaCardActionButtonLayout
+
+    val playPauseAction: MediaPlayPauseActionViewModel?
+
+    val navigation: MediaNavigationViewModel
+
+    val additionalActions: List<MediaSecondaryActionViewModel>
+
+    val guts: MediaCardGutsViewModel
+
+    val outputSwitcherChips: List<MediaOutputSwitcherChipViewModel>
+
+    /** Simple icon-only version of the output switcher for use in compact UIs. */
+    val outputSwitcherChipButton: MediaSecondaryActionViewModel.Action
+
+    val onClick: () -> Unit
+
+    /** Accessibility string for the click action of the card. */
+    val onClickLabel: String?
+
+    val onLongClick: () -> Unit
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCarouselVisibility.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCarouselVisibility.kt
new file mode 100644
index 0000000..53aa87c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCarouselVisibility.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.ui.viewmodel
+
+/** Enumerates the known rules for media carousel visibility. */
+enum class MediaCarouselVisibility {
+
+    /** The carousel should be shown as long as it has at least one card. */
+    WhenNotEmpty,
+
+    /**
+     * The carousel should be shown as long as it has at least one card that represents an active
+     * media session. In other words: if all cards in the carousel represent _inactive_ sessions,
+     * the carousel should _not_ be visible.
+     */
+    WhenAnyCardIsActive,
+}
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsButtonViewModel.kt
similarity index 74%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsButtonViewModel.kt
index 6b8161c..6ce0a01 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsButtonViewModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package com.android.systemui.media.remedia.ui.viewmodel
 
-parcelable SoundProfileHandle;
+data class MediaGutsButtonViewModel(val text: String, val onClick: () -> Unit)
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsSettingsButtonViewModel.kt
similarity index 68%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsSettingsButtonViewModel.kt
index 6b8161c..fabfe0e 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsSettingsButtonViewModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,6 +14,8 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package com.android.systemui.media.remedia.ui.viewmodel
 
-parcelable SoundProfileHandle;
+import com.android.systemui.common.shared.model.Icon
+
+data class MediaGutsSettingsButtonViewModel(val icon: Icon, val onClick: () -> Unit)
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaNavigationViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaNavigationViewModel.kt
new file mode 100644
index 0000000..c34c733
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaNavigationViewModel.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.ui.viewmodel
+
+import androidx.annotation.FloatRange
+
+/**
+ * Models UI state for the navigation component of the UI (potentially containing the seek bar and
+ * the buttons to its left and right).
+ */
+sealed interface MediaNavigationViewModel {
+
+    /** The seek bar should be showing. */
+    data class Showing(
+        /** The progress to show on the seek bar, between `0` and `1`. */
+        @FloatRange(from = 0.0, to = 1.0) val progress: Float,
+        /**
+         * The action button to the left of the seek bar; or `null` if it should be absent in the
+         * UI.
+         */
+        val left: MediaSecondaryActionViewModel,
+        /**
+         * The action button to the right of the seek bar; or `null` if it should be absent in the
+         * UI.
+         */
+        val right: MediaSecondaryActionViewModel,
+        /**
+         * Whether the portion of the seek bar track before the thumb should show the squiggle
+         * animation.
+         */
+        val isSquiggly: Boolean,
+        /**
+         * Whether the UI should show as "scrubbing" because the user is actively moving the thumb
+         * of the seek bar.
+         */
+        val isScrubbing: Boolean,
+        /**
+         * A callback to invoke while the user is "scrubbing" (e.g. actively moving the thumb of the
+         * seek bar). The position/progress of the actual track should not be changed during this
+         * time.
+         */
+        val onScrubChange: (progress: Float) -> Unit,
+        /**
+         * A callback to invoke once the user finishes "scrubbing" (e.g. stopped moving the thumb of
+         * the seek bar). The position/progress should be committed.
+         */
+        val onScrubFinished: () -> Unit,
+    ) : MediaNavigationViewModel
+
+    /** The seek bar should be hidden. */
+    data object Hidden : MediaNavigationViewModel
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaPlayPauseActionViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaPlayPauseActionViewModel.kt
index 4cb11bc..ecc92d7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaPlayPauseActionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaPlayPauseActionViewModel.kt
@@ -21,8 +21,7 @@
 
 /** Models UI state for the play/pause action button within media controls. */
 data class MediaPlayPauseActionViewModel(
-    val isVisible: Boolean,
     val state: MediaSessionState,
-    val icon: Icon.Resource?,
-    val onClick: () -> Unit,
+    val icon: Icon?,
+    val onClick: (() -> Unit)?,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSecondaryActionViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSecondaryActionViewModel.kt
index a480680..d28ca7a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSecondaryActionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSecondaryActionViewModel.kt
@@ -19,8 +19,10 @@
 import com.android.systemui.common.shared.model.Icon
 
 /** Models UI state for a secondary action button within media controls. */
-data class MediaSecondaryActionViewModel(
-    val icon: Icon,
-    val isEnabled: Boolean,
-    val onClick: () -> Unit,
-)
+sealed interface MediaSecondaryActionViewModel {
+    data class Action(val icon: Icon, val onClick: (() -> Unit)?) : MediaSecondaryActionViewModel
+
+    data object ReserveSpace : MediaSecondaryActionViewModel
+
+    data object None : MediaSecondaryActionViewModel
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaViewModel.kt
new file mode 100644
index 0000000..b4f3d27
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaViewModel.kt
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.remedia.ui.viewmodel
+
+import android.content.Context
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.graphics.ImageBitmap
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.media.remedia.domain.interactor.MediaInteractor
+import com.android.systemui.media.remedia.domain.model.MediaActionModel
+import com.android.systemui.media.remedia.shared.model.MediaColorScheme
+import com.android.systemui.media.remedia.shared.model.MediaSessionState
+import com.android.systemui.res.R
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlin.math.roundToLong
+import kotlinx.coroutines.awaitCancellation
+
+/** Models UI state for a media element. */
+class MediaViewModel
+@AssistedInject
+constructor(
+    private val interactor: MediaInteractor,
+    @Assisted private val context: Context,
+    @Assisted private val carouselVisibility: MediaCarouselVisibility,
+) : ExclusiveActivatable() {
+
+    /** Whether the user is actively moving the thumb of the seek bar. */
+    private var isScrubbing: Boolean by mutableStateOf(false)
+    /** The position of the thumb of the seek bar as the user is scrubbing it. */
+    private var seekProgress: Float by mutableFloatStateOf(0f)
+    /** Whether the internal "guts" are visible. */
+    private var isGutsVisible: Boolean by mutableStateOf(false)
+    /** The index of the currently-selected card. */
+    private var selectedCardIndex: Int by mutableIntStateOf(0)
+        private set
+
+    /** The current list of cards to show in the UI. */
+    val cards: List<MediaCardViewModel> by derivedStateOf {
+        interactor.sessions.mapIndexed { sessionIndex, session ->
+            val isCurrentSessionAndScrubbing = isScrubbing && sessionIndex == selectedCardIndex
+            object : MediaCardViewModel {
+                override val key = session.key
+                override val icon = session.appIcon
+                override val background: ImageBitmap?
+                    get() = session.background
+
+                override val colorScheme: MediaColorScheme
+                    get() = session.colorScheme
+
+                override val title = session.title
+                override val subtitle = session.subtitle
+                override val actionButtonLayout = session.actionButtonLayout
+                override val playPauseAction =
+                    session.playPauseAction.toPlayPauseActionViewModel(session.state)
+                override val additionalActions: List<MediaSecondaryActionViewModel>
+                    get() {
+                        return session.additionalActions.map { action ->
+                            action.toSecondaryActionViewModel()
+                        }
+                    }
+
+                override val navigation: MediaNavigationViewModel
+                    get() {
+                        return if (session.canBeScrubbed) {
+                            MediaNavigationViewModel.Showing(
+                                progress =
+                                    if (!isCurrentSessionAndScrubbing) {
+                                        session.positionMs.toFloat() / session.durationMs
+                                    } else {
+                                        seekProgress
+                                    },
+                                left = session.leftAction.toSecondaryActionViewModel(),
+                                right = session.rightAction.toSecondaryActionViewModel(),
+                                isSquiggly =
+                                    session.state != MediaSessionState.Paused &&
+                                        !isCurrentSessionAndScrubbing,
+                                isScrubbing = isCurrentSessionAndScrubbing,
+                                onScrubChange = { progress ->
+                                    check(selectedCardIndex == sessionIndex) {
+                                        "Can't seek on a card that's not the selected card!"
+                                    }
+                                    isScrubbing = true
+                                    seekProgress = progress
+                                },
+                                onScrubFinished = {
+                                    interactor.seek(
+                                        sessionKey = session.key,
+                                        to = (seekProgress * session.durationMs).roundToLong(),
+                                    )
+                                    isScrubbing = false
+                                },
+                            )
+                        } else {
+                            MediaNavigationViewModel.Hidden
+                        }
+                    }
+
+                override val guts: MediaCardGutsViewModel
+                    get() {
+                        return MediaCardGutsViewModel(
+                            isVisible = isGutsVisible,
+                            text =
+                                if (session.canBeHidden) {
+                                    context.getString(
+                                        R.string.controls_media_close_session,
+                                        session.appName,
+                                    )
+                                } else {
+                                    context.getString(R.string.controls_media_active_session)
+                                },
+                            primaryAction =
+                                if (session.canBeHidden) {
+                                    MediaGutsButtonViewModel(
+                                        text =
+                                            context.getString(
+                                                R.string.controls_media_dismiss_button
+                                            ),
+                                        onClick = {
+                                            interactor.hide(session.key)
+                                            isGutsVisible = false
+                                        },
+                                    )
+                                } else {
+                                    MediaGutsButtonViewModel(
+                                        text = context.getString(R.string.cancel),
+                                        onClick = { isGutsVisible = false },
+                                    )
+                                },
+                            secondaryAction =
+                                MediaGutsButtonViewModel(
+                                        text = context.getString(R.string.cancel),
+                                        onClick = { isGutsVisible = false },
+                                    )
+                                    .takeIf { session.canBeHidden },
+                            settingsButton =
+                                MediaGutsSettingsButtonViewModel(
+                                    icon =
+                                        Icon.Resource(
+                                            res = R.drawable.ic_settings,
+                                            contentDescription =
+                                                ContentDescription.Resource(
+                                                    res = R.string.controls_media_settings_button
+                                                ),
+                                        ),
+                                    onClick = { interactor.openMediaSettings() },
+                                ),
+                            onLongClick = { isGutsVisible = false },
+                        )
+                    }
+
+                override val outputSwitcherChips: List<MediaOutputSwitcherChipViewModel>
+                    get() {
+                        return listOf(
+                            MediaOutputSwitcherChipViewModel(
+                                icon = session.outputDevice.icon,
+                                text = session.outputDevice.name,
+                                onClick = {
+                                    // TODO(b/397989775): tell the UI to show the output switcher.
+                                },
+                            )
+                        )
+                    }
+
+                override val outputSwitcherChipButton: MediaSecondaryActionViewModel.Action
+                    get() {
+                        return MediaSecondaryActionViewModel.Action(
+                            icon = session.outputDevice.icon,
+                            onClick = {
+                                // TODO(b/397989775): tell the UI to show the output switcher.
+                            },
+                        )
+                    }
+
+                override val onClick = session.onClick
+                override val onClickLabel =
+                    context.getString(R.string.controls_media_playing_item_description)
+                override val onLongClick = { isGutsVisible = true }
+            }
+        }
+    }
+
+    /** Whether the carousel should be visible. */
+    val isCarouselVisible: Boolean
+        get() =
+            when (carouselVisibility) {
+                MediaCarouselVisibility.WhenNotEmpty -> interactor.sessions.isNotEmpty()
+
+                MediaCarouselVisibility.WhenAnyCardIsActive ->
+                    interactor.sessions.any { session -> session.isActive }
+            }
+
+    /** Notifies that the card at [cardIndex] has been selected in the UI. */
+    fun onCardSelected(cardIndex: Int) {
+        check(cardIndex >= 0 && cardIndex < cards.size)
+        selectedCardIndex = cardIndex
+    }
+
+    override suspend fun onActivated(): Nothing {
+        awaitCancellation()
+    }
+
+    private fun MediaActionModel.toPlayPauseActionViewModel(
+        mediaSessionState: MediaSessionState
+    ): MediaPlayPauseActionViewModel? {
+        return when (this) {
+            is MediaActionModel.Action ->
+                MediaPlayPauseActionViewModel(
+                    state = mediaSessionState,
+                    icon = icon,
+                    onClick = onClick ?: {},
+                )
+            is MediaActionModel.None,
+            is MediaActionModel.ReserveSpace -> null
+        }
+    }
+
+    private fun MediaActionModel.toSecondaryActionViewModel(): MediaSecondaryActionViewModel {
+        return when (this) {
+            is MediaActionModel.Action ->
+                MediaSecondaryActionViewModel.Action(icon = icon, onClick = onClick)
+            is MediaActionModel.ReserveSpace -> MediaSecondaryActionViewModel.ReserveSpace
+            is MediaActionModel.None -> MediaSecondaryActionViewModel.None
+        }
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(context: Context, carouselVisibility: MediaCarouselVisibility): MediaViewModel
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUIStateDispatcher.kt b/packages/SystemUI/src/com/android/systemui/model/SysUIStateDispatcher.kt
index f95ae25..2bdd9a8 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUIStateDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUIStateDispatcher.kt
@@ -55,7 +55,7 @@
 
     /** Called from each [SysUiState] to propagate new state changes. */
     fun dispatchSysUIStateChange(sysUiFlags: Long, displayId: Int) {
-        if (displayId != Display.DEFAULT_DISPLAY && !ShadeWindowGoesAround.isEnabled) return;
+        if (displayId != Display.DEFAULT_DISPLAY && !ShadeWindowGoesAround.isEnabled) return
         listeners.forEach { listener ->
             listener.onSystemUiStateChanged(sysUiFlags = sysUiFlags, displayId = displayId)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUIStateOverride.kt b/packages/SystemUI/src/com/android/systemui/model/SysUIStateOverride.kt
new file mode 100644
index 0000000..89e06e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUIStateOverride.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 android.view.Display
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/**
+ * This class is used to provide per-display overrides for only certain flags.
+ *
+ * While some of the [SystemUiStateFlags] are per display (e.g. shade expansion, dialog visible),
+ * some of them are device specific (e.g. whether it's awake or not). A [SysUIStateOverride] is
+ * created for each display that is not [Display.DEFAULT_DISPLAY], and if some flags are set on it,
+ * they will override whatever the default display state had in those.
+ */
+class SysUIStateOverride
+@AssistedInject
+constructor(
+    @Assisted override val displayId: Int,
+    private val sceneContainerPlugin: SceneContainerPlugin?,
+    dumpManager: DumpManager,
+    private val defaultDisplayState: SysUiState,
+    private val stateDispatcher: SysUIStateDispatcher,
+) : SysUiStateImpl(displayId, sceneContainerPlugin, dumpManager, stateDispatcher) {
+
+    private val override = StateChange()
+    private var lastSentFlags = defaultDisplayState.flags
+
+    private val defaultFlagsChangedCallback = { _: Long, otherDisplayId: Int ->
+        if (otherDisplayId == Display.DEFAULT_DISPLAY) {
+            commitUpdate()
+        }
+    }
+
+    override fun start() {
+        super.start()
+        stateDispatcher.registerListener(defaultFlagsChangedCallback)
+    }
+
+    override fun destroy() {
+        super.destroy()
+        stateDispatcher.unregisterListener(defaultFlagsChangedCallback)
+    }
+
+    override fun commitUpdate() {
+        if (flags != lastSentFlags) {
+            stateDispatcher.dispatchSysUIStateChange(flags, displayId)
+            lastSentFlags = flags
+        }
+    }
+
+    override val flags: Long
+        get() = override.applyTo(defaultDisplayState.flags)
+
+    override fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState {
+        val toSet = flagWithOptionalOverrides(flag, enabled, displayId, sceneContainerPlugin)
+        override.setFlag(flag, toSet)
+        return this
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(displayId: Int): SysUIStateOverride
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt b/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt
index 6633559..e99ee7d 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt
@@ -16,6 +16,7 @@
 package com.android.systemui.model
 
 import android.util.Log
+import android.view.Display
 import com.android.systemui.Dumpable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.display.data.repository.PerDisplayInstanceProviderWithTeardown
@@ -74,6 +75,9 @@
      */
     fun destroy()
 
+    /** Initializes the state after construction. */
+    fun start()
+
     /** The display ID this instances is associated with */
     val displayId: Int
 
@@ -84,7 +88,7 @@
 
 private const val TAG = "SysUIState"
 
-class SysUiStateImpl
+open class SysUiStateImpl
 @AssistedInject
 constructor(
     @Assisted override val displayId: Int,
@@ -93,9 +97,10 @@
     private val stateDispatcher: SysUIStateDispatcher,
 ) : SysUiState {
 
-    private val debugName = "SysUiStateImpl-ForDisplay=$displayId"
+    private val debugName
+        get() = "SysUiStateImpl-ForDisplay=$displayId"
 
-    init {
+    override fun start() {
         dumpManager.registerNormalDumpable(debugName, this)
     }
 
@@ -222,10 +227,19 @@
 
 /** Creates and destroy instances of [SysUiState] */
 @SysUISingleton
-class SysUIStateInstanceProvider @Inject constructor(private val factory: SysUiStateImpl.Factory) :
-    PerDisplayInstanceProviderWithTeardown<SysUiState> {
+class SysUIStateInstanceProvider
+@Inject
+constructor(
+    private val factory: SysUiStateImpl.Factory,
+    private val overrideFactory: SysUIStateOverride.Factory,
+) : PerDisplayInstanceProviderWithTeardown<SysUiState> {
     override fun createInstance(displayId: Int): SysUiState {
-        return factory.create(displayId)
+        return if (displayId == Display.DEFAULT_DISPLAY) {
+                factory.create(displayId)
+            } else {
+                overrideFactory.create(displayId)
+            }
+            .apply { start() }
     }
 
     override fun destroyInstance(instance: SysUiState) {
diff --git a/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
index a344a5c..3f804f7 100644
--- a/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
@@ -42,7 +42,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, Flags.FLAG_MODES_UI)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, Flags.FLAG_MODES_UI)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index 5fa0095..50d0a45 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
 import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen;
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
 import static com.android.wm.shell.Flags.enableTaskbarOnPhones;
 
@@ -37,6 +36,7 @@
 import android.view.IWindowManager;
 import android.view.View;
 import android.view.WindowManagerGlobal;
+import android.window.DesktopExperienceFlags;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -285,7 +285,7 @@
 
         @Override
         public void onDisplayAddSystemDecorations(int displayId) {
-            if (enableDisplayContentModeManagement()) {
+            if (DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
                 mHasNavBar.put(displayId, true);
             }
             Display display = mDisplayManager.getDisplay(displayId);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index c4d847f..efed260 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -44,7 +44,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
-import android.inputmethodservice.InputMethodService;
 import android.inputmethodservice.InputMethodService.BackDispositionMode;
 import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
 import android.os.Handler;
@@ -503,9 +502,7 @@
     @Override
     public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
             @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
-        // Count imperceptible changes as visible so we transition taskbar out quickly.
-        final boolean isImeVisible = mNavBarHelper.isImeVisible(vis)
-                || (vis & InputMethodService.IME_VISIBLE_IMPERCEPTIBLE) != 0;
+        final boolean isImeVisible = mNavBarHelper.isImeVisible(vis);
         final int flags = Utilities.updateNavbarFlagsFromIme(mNavbarFlags, backDisposition,
                 isImeVisible, showImeSwitcher);
         if (flags == mNavbarFlags) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 7af5381..237ec7c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -1129,6 +1129,7 @@
                     mGestureBlockingActivityRunning.get(), mIsInPip, mDisplaySize,
                     mEdgeWidthLeft, mLeftInset, mEdgeWidthRight, mRightInset, mExcludeRegion));
         } else if (mAllowGesture || mLogGesture) {
+            boolean mLastFrameThresholdCrossed = mThresholdCrossed;
             if (!mThresholdCrossed) {
                 mEndPoint.x = (int) ev.getX();
                 mEndPoint.y = (int) ev.getY();
@@ -1181,9 +1182,7 @@
                         return;
                     } else if (dx > dy && dx > mTouchSlop) {
                         if (mAllowGesture) {
-                            if (mBackAnimation != null) {
-                                mBackAnimation.onThresholdCrossed();
-                            } else {
+                            if (mBackAnimation == null) {
                                 pilferPointers();
                             }
                             mThresholdCrossed = true;
@@ -1198,6 +1197,9 @@
                 // forward touch
                 mEdgeBackPlugin.onMotionEvent(ev);
                 dispatchToBackAnimation(ev);
+                if (mBackAnimation != null && mThresholdCrossed && !mLastFrameThresholdCrossed) {
+                    mBackAnimation.onThresholdCrossed();
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java b/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
index 694b525..ea2bf6a 100644
--- a/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
@@ -48,7 +48,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 5e7e0c9..ef57978 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -18,6 +18,7 @@
 
 import android.annotation.SuppressLint
 import android.content.Context
+import android.content.res.Configuration
 import android.graphics.PointF
 import android.graphics.Rect
 import android.os.Bundle
@@ -48,6 +49,7 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
@@ -58,16 +60,20 @@
 import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.input.pointer.PointerEventPass
 import androidx.compose.ui.input.pointer.PointerInputChange
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.layout.approachLayout
+import androidx.compose.ui.layout.layout
 import androidx.compose.ui.layout.onPlaced
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.layout.positionInRoot
 import androidx.compose.ui.layout.positionOnScreen
 import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.semantics.CustomAccessibilityAction
@@ -101,6 +107,7 @@
 import com.android.systemui.Dumpable
 import com.android.systemui.Flags
 import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
+import com.android.systemui.brightness.ui.compose.ContainerColors
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyboard.shortcut.ui.composable.InteractionsConfig
@@ -248,12 +255,25 @@
 
     @Composable
     private fun Content() {
-        PlatformTheme(isDarkTheme = true) {
+        PlatformTheme(isDarkTheme = true /* Delete AlwaysDarkMode when removing this */) {
             ProvideShortcutHelperIndication(interactionsConfig = interactionsConfig()) {
-                if (viewModel.isQsVisibleAndAnyShadeExpanded) {
+                // TODO(b/389985793): Make sure that there is no coroutine work or recompositions
+                // happening when alwaysCompose is true but isQsVisibleAndAnyShadeExpanded is false.
+                if (alwaysCompose || viewModel.isQsVisibleAndAnyShadeExpanded) {
                     Box(
                         modifier =
-                            Modifier.graphicsLayer { alpha = viewModel.viewAlpha }
+                            Modifier.thenIf(alwaysCompose) {
+                                    Modifier.layout { measurable, constraints ->
+                                        measurable.measure(constraints).run {
+                                            layout(width, height) {
+                                                if (viewModel.isQsVisibleAndAnyShadeExpanded) {
+                                                    place(0, 0)
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                                .graphicsLayer { alpha = viewModel.viewAlpha }
                                 .thenIf(notificationScrimClippingParams.isEnabled) {
                                     Modifier.notificationScrimClip {
                                         notificationScrimClippingParams.params
@@ -331,12 +351,12 @@
         }
 
         SceneTransitionLayout(state = sceneState, modifier = Modifier.fillMaxSize()) {
-            scene(QuickSettings) {
+            scene(QuickSettings, alwaysCompose = alwaysCompose) {
                 LaunchedEffect(Unit) { viewModel.onQSOpen() }
                 Element(QuickSettings.rootElementKey, Modifier) { QuickSettingsElement() }
             }
 
-            scene(QuickQuickSettings) {
+            scene(QuickQuickSettings, alwaysCompose = alwaysCompose) {
                 LaunchedEffect(Unit) { viewModel.onQQSOpen() }
                 // Cannot pass the element modifier in because the top element has a `testTag`
                 // and this would overwrite it.
@@ -626,7 +646,20 @@
             ) {
                 val Tiles =
                     @Composable {
-                        QuickQuickSettings(viewModel = viewModel.quickQuickSettingsViewModel)
+                        QuickQuickSettings(
+                            viewModel = viewModel.quickQuickSettingsViewModel,
+                            listening = {
+                                /*
+                                 *  When always compose is false, this will always be true, and we'll be
+                                 *  listening whenever this is composed.
+                                 *  When always compose is true, we listen if we are visible and not
+                                 *  fully expanded
+                                 */
+                                !alwaysCompose ||
+                                    (viewModel.isQsVisibleAndAnyShadeExpanded &&
+                                        viewModel.expansionState.progress < 1f)
+                            },
+                        )
                     }
                 val Media =
                     @Composable {
@@ -713,11 +746,24 @@
                         )
                         val BrightnessSlider =
                             @Composable {
-                                BrightnessSliderContainer(
-                                    viewModel = containerViewModel.brightnessSliderViewModel,
-                                    modifier =
-                                        Modifier.systemGestureExclusionInShade().fillMaxWidth(),
-                                )
+                                AlwaysDarkMode {
+                                    BrightnessSliderContainer(
+                                        viewModel = containerViewModel.brightnessSliderViewModel,
+                                        containerColors =
+                                            ContainerColors(
+                                                Color.Transparent,
+                                                ContainerColors.defaultContainerColor,
+                                            ),
+                                        modifier =
+                                            Modifier.systemGestureExclusionInShade(
+                                                    enabled = {
+                                                        layoutState.transitionState is
+                                                            TransitionState.Idle
+                                                    }
+                                                )
+                                                .fillMaxWidth(),
+                                    )
+                                }
                             }
                         val TileGrid =
                             @Composable {
@@ -726,6 +772,18 @@
                                     TileGrid(
                                         viewModel = containerViewModel.tileGridViewModel,
                                         modifier = Modifier.fillMaxWidth(),
+                                        listening = {
+                                            /*
+                                             *  When always compose is false, this will always be true,
+                                             *  and we'll be listening whenever this is composed.
+                                             *  When always compose is true, we look a the second
+                                             *  condition and we'll listen if QS is visible AND we are
+                                             *  not fully collapsed.
+                                             */
+                                            !alwaysCompose ||
+                                                (viewModel.isQsVisibleAndAnyShadeExpanded &&
+                                                    viewModel.expansionState.progress > 0f)
+                                        },
                                     )
                                 }
                             }
@@ -830,6 +888,7 @@
                 println("qqsPositionOnScreen", rect)
             }
             println("QQS visible", qqsVisible.value)
+            println("Always composed", alwaysCompose)
             if (::viewModel.isInitialized) {
                 printSection("View Model") { viewModel.dump(this@run, args) }
             }
@@ -1177,3 +1236,31 @@
         // we are OK using this as our content is clipped and all corner radius are larger than this
         surfaceCornerRadius = 28.dp,
     )
+
+private inline val alwaysCompose
+    get() = Flags.alwaysComposeQsUiFragment()
+
+/**
+ * Forces the configuration and themes to be dark theme. This is needed in order to have
+ * [colorResource] retrieve the dark mode colors.
+ *
+ * This should be removed when we remove the force dark mode in [PlatformTheme] at the root of the
+ * compose hierarchy.
+ */
+@Composable
+private fun AlwaysDarkMode(content: @Composable () -> Unit) {
+    val currentConfig = LocalConfiguration.current
+    val darkConfig =
+        Configuration(currentConfig).apply {
+            uiMode =
+                (uiMode and (Configuration.UI_MODE_NIGHT_MASK.inv())) or
+                    Configuration.UI_MODE_NIGHT_YES
+        }
+    val newContext = LocalContext.current.createConfigurationContext(darkConfig)
+    CompositionLocalProvider(
+        LocalConfiguration provides darkConfig,
+        LocalContext provides newContext,
+    ) {
+        content()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/ui/dialog/TileRequestDialogComposeDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/external/ui/dialog/TileRequestDialogComposeDelegate.kt
index 446be9b..59844c7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/ui/dialog/TileRequestDialogComposeDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/ui/dialog/TileRequestDialogComposeDelegate.kt
@@ -85,6 +85,7 @@
 
                         LargeStaticTile(
                             uiState = viewModel.uiState,
+                            iconProvider = viewModel.iconProvider,
                             modifier =
                                 Modifier.width(
                                     dimensionResource(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/ui/viewmodel/TileRequestDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/external/ui/viewmodel/TileRequestDialogViewModel.kt
index c756adc..dd281cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/ui/viewmodel/TileRequestDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/ui/viewmodel/TileRequestDialogViewModel.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.qs.external.TileData
+import com.android.systemui.qs.panels.ui.viewmodel.toIconProvider
 import com.android.systemui.qs.panels.ui.viewmodel.toUiState
 import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon
 import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
@@ -58,6 +59,8 @@
 
     val uiState by derivedStateOf { state.toUiState(dialogContext.resources) }
 
+    val iconProvider by derivedStateOf { state.toIconProvider() }
+
     override suspend fun onActivated(): Nothing {
         withContext(backgroundDispatcher) {
             tileData.icon
diff --git a/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt b/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
index 2eba36a..6865e0e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
@@ -81,7 +81,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /** Returns a developer-readable string that describes the current requirement list. */
     @JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
index 185ea93..1fb884d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
@@ -27,7 +27,17 @@
 
 /** A layout of tiles, indicating how they should be composed when showing in QS or in edit mode. */
 interface GridLayout {
-    @Composable fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier)
+
+    /**
+     * [listening] can be used to compose the grid but limit when tiles should be listening. It
+     * should be a function tracking a snapshot state.
+     */
+    @Composable
+    fun ContentScope.TileGrid(
+        tiles: List<TileViewModel>,
+        modifier: Modifier,
+        listening: () -> Boolean,
+    )
 
     @Composable
     fun EditTileGrid(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index a071206..865ae9a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -32,7 +32,6 @@
 import androidx.compose.foundation.shape.CornerSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.snapshotFlow
@@ -43,6 +42,7 @@
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ContentScope
 import com.android.compose.modifiers.padding
+import com.android.systemui.common.ui.compose.PagerDots
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.development.ui.compose.BuildNumber
 import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel
@@ -65,17 +65,16 @@
     @PaginatedBaseLayoutType private val delegateGridLayout: PaginatableGridLayout,
 ) : GridLayout by delegateGridLayout {
     @Composable
-    override fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
+    override fun ContentScope.TileGrid(
+        tiles: List<TileViewModel>,
+        modifier: Modifier,
+        listening: () -> Boolean,
+    ) {
         val viewModel =
             rememberViewModel(traceName = "PaginatedGridLayout-TileGrid") {
                 viewModelFactory.create()
             }
 
-        DisposableEffect(tiles) {
-            val token = Any()
-            tiles.forEach { it.startListening(token) }
-            onDispose { tiles.forEach { it.stopListening(token) } }
-        }
         val columns = viewModel.columns
         val rows = integerResource(R.integer.quick_settings_paginated_grid_num_rows)
 
@@ -122,7 +121,7 @@
             ) {
                 val page = pages[it]
 
-                with(delegateGridLayout) { TileGrid(tiles = page, modifier = Modifier) }
+                with(delegateGridLayout) { TileGrid(tiles = page, modifier = Modifier, listening) }
             }
             FooterBar(
                 buildNumberViewModelFactory = viewModel.buildNumberViewModelFactory,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index cdc03bb..d20b360 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
@@ -41,6 +40,7 @@
 fun ContentScope.QuickQuickSettings(
     viewModel: QuickQuickSettingsViewModel,
     modifier: Modifier = Modifier,
+    listening: () -> Boolean,
 ) {
 
     val sizedTiles = viewModel.tileViewModels
@@ -51,11 +51,6 @@
 
     val spans by remember(sizedTiles) { derivedStateOf { sizedTiles.fastMap { it.width } } }
 
-    DisposableEffect(tiles) {
-        val token = Any()
-        tiles.forEach { it.startListening(token) }
-        onDispose { tiles.forEach { it.stopListening(token) } }
-    }
     val columns = viewModel.columns
     Box(modifier = modifier) {
         GridAnchor()
@@ -91,4 +86,6 @@
             }
         }
     }
+
+    TileListener(tiles, listening)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
index fd10f91..1858825 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
@@ -22,9 +22,13 @@
 import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
 
 @Composable
-fun ContentScope.TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
+fun ContentScope.TileGrid(
+    viewModel: TileGridViewModel,
+    modifier: Modifier = Modifier,
+    listening: () -> Boolean = { true },
+) {
     val gridLayout = viewModel.gridLayout
     val tiles = viewModel.tileViewModels
 
-    with(gridLayout) { TileGrid(tiles, modifier) }
+    with(gridLayout) { TileGrid(tiles, modifier, listening) }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt
new file mode 100644
index 0000000..6fb8f1b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.ui.compose
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.snapshotFlow
+import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+
+/**
+ * Use to have tiles start/stop listening when this is composed. Additionally, the listening state
+ * will be gated by [listeningEnabled].
+ */
+@Composable
+fun TileListener(tiles: List<TileViewModel>, listeningEnabled: () -> Boolean) {
+    LaunchedEffect(tiles) {
+        val token = Any()
+        try {
+            snapshotFlow { listeningEnabled() }
+                .collect { listening ->
+                    tiles.forEach {
+                        if (listening) {
+                            it.startListening(token)
+                        } else {
+                            it.stopListening(token)
+                        }
+                    }
+                }
+        } finally {
+            tiles.forEach { it.stopListening(token) }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 0503049..6236ada 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.qs.panels.ui.compose.infinitegrid
 
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
@@ -34,6 +33,7 @@
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS
 import com.android.systemui.qs.panels.shared.model.SizedTileImpl
 import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
+import com.android.systemui.qs.panels.ui.compose.TileListener
 import com.android.systemui.qs.panels.ui.compose.bounceableInfo
 import com.android.systemui.qs.panels.ui.compose.rememberEditListState
 import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
@@ -59,12 +59,11 @@
 ) : PaginatableGridLayout {
 
     @Composable
-    override fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
-        DisposableEffect(tiles) {
-            val token = Any()
-            tiles.forEach { it.startListening(token) }
-            onDispose { tiles.forEach { it.stopListening(token) } }
-        }
+    override fun ContentScope.TileGrid(
+        tiles: List<TileViewModel>,
+        modifier: Modifier,
+        listening: () -> Boolean,
+    ) {
         val viewModel =
             rememberViewModel(traceName = "InfiniteGridLayout.TileGrid") {
                 viewModelFactory.create()
@@ -116,6 +115,8 @@
                 )
             }
         }
+
+        TileListener(tiles, listening)
     }
 
     @Composable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index a56fabc..bf63c3858 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -20,6 +20,7 @@
 
 import android.content.Context
 import android.content.res.Resources
+import android.os.Trace
 import android.service.quicksettings.Tile.STATE_ACTIVE
 import android.service.quicksettings.Tile.STATE_INACTIVE
 import androidx.compose.animation.animateColorAsState
@@ -47,8 +48,8 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.State
-import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.produceState
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberUpdatedState
@@ -59,7 +60,7 @@
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.platform.LocalConfiguration
-import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalResources
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.semantics.contentDescription
 import androidx.compose.ui.semantics.role
@@ -69,6 +70,7 @@
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.trace
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.Expandable
 import com.android.compose.animation.bounceable
@@ -80,7 +82,6 @@
 import com.android.systemui.haptics.msdl.qs.TileHapticsViewModel
 import com.android.systemui.haptics.msdl.qs.TileHapticsViewModelFactoryProvider
 import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.qs.flags.QsDetailedView
 import com.android.systemui.qs.panels.ui.compose.BounceableInfo
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
@@ -88,9 +89,12 @@
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileHeight
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileStartPadding
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
+import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState
 import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.IconProvider
 import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
 import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.toIconProvider
 import com.android.systemui.qs.panels.ui.viewmodel.toUiState
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.qs.ui.compose.borderOnFocus
@@ -119,6 +123,9 @@
     )
 }
 
+private val TileViewModel.traceName
+    get() = spec.toString().takeLast(Trace.MAX_SECTION_NAME_LEN)
+
 @Composable
 fun Tile(
     tile: TileViewModel,
@@ -130,105 +137,114 @@
     modifier: Modifier = Modifier,
     detailsViewModel: DetailsViewModel?,
 ) {
-    val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
-    val resources = resources()
+    trace(tile.traceName) {
+        val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
+        val resources = resources()
 
-    /*
-     * Use produce state because [QSTile.State] doesn't have well defined equals (due to
-     * inheritance). This way, even if tile.state changes, uiState may not change and lead to
-     * recomposition.
-     */
-    val uiState by
-        produceState(tile.currentState.toUiState(resources), tile, resources) {
-            tile.state.collect { value = it.toUiState(resources) }
-        }
+        /*
+         * Use produce state because [QSTile.State] doesn't have well defined equals (due to
+         * inheritance). This way, even if tile.state changes, uiState may not change and lead to
+         * recomposition.
+         */
+        val uiState by
+            produceState(tile.currentState.toUiState(resources), tile, resources) {
+                tile.state.collect { value = it.toUiState(resources) }
+            }
 
-    val colors = TileDefaults.getColorForState(uiState, iconOnly)
-    val hapticsViewModel: TileHapticsViewModel? =
-        rememberViewModel(traceName = "TileHapticsViewModel") {
-            tileHapticsViewModelFactoryProvider.getHapticsViewModelFactory()?.create(tile)
-        }
+        val icon by
+            produceState(tile.currentState.toIconProvider(), tile) {
+                tile.state.collect { value = it.toIconProvider() }
+            }
 
-    // TODO(b/361789146): Draw the shapes instead of clipping
-    val tileShape by TileDefaults.animateTileShapeAsState(uiState.state)
-    val animatedColor by animateColorAsState(colors.background, label = "QSTileBackgroundColor")
+        val colors = TileDefaults.getColorForState(uiState, iconOnly)
+        val hapticsViewModel: TileHapticsViewModel? =
+            rememberViewModel(traceName = "TileHapticsViewModel") {
+                tileHapticsViewModelFactoryProvider.getHapticsViewModelFactory()?.create(tile)
+            }
 
-    TileExpandable(
-        color = { animatedColor },
-        shape = tileShape,
-        squishiness = squishiness,
-        hapticsViewModel = hapticsViewModel,
-        modifier =
-            modifier
-                .borderOnFocus(color = MaterialTheme.colorScheme.secondary, tileShape.topEnd)
-                .fillMaxWidth()
-                .bounceable(
-                    bounceable = currentBounceableInfo.bounceable,
-                    previousBounceable = currentBounceableInfo.previousTile,
-                    nextBounceable = currentBounceableInfo.nextTile,
-                    orientation = Orientation.Horizontal,
-                    bounceEnd = currentBounceableInfo.bounceEnd,
-                ),
-    ) { expandable ->
-        val longClick: (() -> Unit)? =
-            {
-                    hapticsViewModel?.setTileInteractionState(
-                        TileHapticsViewModel.TileInteractionState.LONG_CLICKED
-                    )
-                    tile.onLongClick(expandable)
-                }
-                .takeIf { uiState.handlesLongClick }
-        TileContainer(
-            onClick = {
-                var hasDetails = false
-                if (QsDetailedView.isEnabled) {
-                    hasDetails = detailsViewModel?.onTileClicked(tile.spec) == true
-                }
-                if (!hasDetails) {
-                    // For those tile's who doesn't have a detailed view, process with their
-                    // `onClick` behavior.
-                    tile.onClick(expandable)
-                    hapticsViewModel?.setTileInteractionState(
-                        TileHapticsViewModel.TileInteractionState.CLICKED
-                    )
-                    if (uiState.accessibilityUiState.toggleableState != null) {
-                        coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() }
+        // TODO(b/361789146): Draw the shapes instead of clipping
+        val tileShape by TileDefaults.animateTileShapeAsState(uiState.state)
+        val animatedColor by animateColorAsState(colors.background, label = "QSTileBackgroundColor")
+
+        TileExpandable(
+            color = { animatedColor },
+            shape = tileShape,
+            squishiness = squishiness,
+            hapticsViewModel = hapticsViewModel,
+            modifier =
+                modifier
+                    .borderOnFocus(color = MaterialTheme.colorScheme.secondary, tileShape.topEnd)
+                    .fillMaxWidth()
+                    .bounceable(
+                        bounceable = currentBounceableInfo.bounceable,
+                        previousBounceable = currentBounceableInfo.previousTile,
+                        nextBounceable = currentBounceableInfo.nextTile,
+                        orientation = Orientation.Horizontal,
+                        bounceEnd = currentBounceableInfo.bounceEnd,
+                    ),
+        ) { expandable ->
+            val longClick: (() -> Unit)? =
+                {
+                        hapticsViewModel?.setTileInteractionState(
+                            TileHapticsViewModel.TileInteractionState.LONG_CLICKED
+                        )
+                        tile.onLongClick(expandable)
                     }
-                }
-            },
-            onLongClick = longClick,
-            uiState = uiState,
-            iconOnly = iconOnly,
-        ) {
-            val iconProvider: Context.() -> Icon = { getTileIcon(icon = uiState.icon) }
-            if (iconOnly) {
-                SmallTileContent(
-                    iconProvider = iconProvider,
-                    color = colors.icon,
-                    modifier = Modifier.align(Alignment.Center),
-                )
-            } else {
-                val iconShape by TileDefaults.animateIconShapeAsState(uiState.state)
-                val secondaryClick: (() -> Unit)? =
-                    {
-                            hapticsViewModel?.setTileInteractionState(
-                                TileHapticsViewModel.TileInteractionState.CLICKED
-                            )
-                            tile.onSecondaryClick()
+                    .takeIf { uiState.handlesLongClick }
+            TileContainer(
+                onClick = {
+                    var hasDetails = false
+                    if (QsDetailedView.isEnabled) {
+                        hasDetails = detailsViewModel?.onTileClicked(tile.spec) == true
+                    }
+                    if (!hasDetails) {
+                        // For those tile's who doesn't have a detailed view, process with their
+                        // `onClick` behavior.
+                        tile.onClick(expandable)
+                        hapticsViewModel?.setTileInteractionState(
+                            TileHapticsViewModel.TileInteractionState.CLICKED
+                        )
+                        if (uiState.accessibilityUiState.toggleableState != null) {
+                            coroutineScope.launch {
+                                currentBounceableInfo.bounceable.animateBounce()
+                            }
                         }
-                        .takeIf { uiState.handlesSecondaryClick }
-                LargeTileContent(
-                    label = uiState.label,
-                    secondaryLabel = uiState.secondaryLabel,
-                    iconProvider = iconProvider,
-                    sideDrawable = uiState.sideDrawable,
-                    colors = colors,
-                    iconShape = iconShape,
-                    toggleClick = secondaryClick,
-                    onLongClick = longClick,
-                    accessibilityUiState = uiState.accessibilityUiState,
-                    squishiness = squishiness,
-                )
+                    }
+                },
+                onLongClick = longClick,
+                accessibilityUiState = uiState.accessibilityUiState,
+                iconOnly = iconOnly,
+            ) {
+                val iconProvider: Context.() -> Icon = { getTileIcon(icon = icon) }
+                if (iconOnly) {
+                    SmallTileContent(
+                        iconProvider = iconProvider,
+                        color = colors.icon,
+                        modifier = Modifier.align(Alignment.Center),
+                    )
+                } else {
+                    val iconShape by TileDefaults.animateIconShapeAsState(uiState.state)
+                    val secondaryClick: (() -> Unit)? =
+                        {
+                                hapticsViewModel?.setTileInteractionState(
+                                    TileHapticsViewModel.TileInteractionState.CLICKED
+                                )
+                                tile.onSecondaryClick()
+                            }
+                            .takeIf { uiState.handlesSecondaryClick }
+                    LargeTileContent(
+                        label = uiState.label,
+                        secondaryLabel = uiState.secondaryLabel,
+                        iconProvider = iconProvider,
+                        sideDrawable = uiState.sideDrawable,
+                        colors = colors,
+                        iconShape = iconShape,
+                        toggleClick = secondaryClick,
+                        onLongClick = longClick,
+                        accessibilityUiState = uiState.accessibilityUiState,
+                        squishiness = squishiness,
+                    )
+                }
             }
         }
     }
@@ -257,7 +273,7 @@
 fun TileContainer(
     onClick: () -> Unit,
     onLongClick: (() -> Unit)?,
-    uiState: TileUiState,
+    accessibilityUiState: AccessibilityUiState,
     iconOnly: Boolean,
     content: @Composable BoxScope.() -> Unit,
 ) {
@@ -268,7 +284,7 @@
                 .tileCombinedClickable(
                     onClick = onClick,
                     onLongClick = onLongClick,
-                    uiState = uiState,
+                    accessibilityUiState = accessibilityUiState,
                     iconOnly = iconOnly,
                 )
                 .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE)
@@ -278,7 +294,11 @@
 }
 
 @Composable
-fun LargeStaticTile(uiState: TileUiState, modifier: Modifier = Modifier) {
+fun LargeStaticTile(
+    uiState: TileUiState,
+    iconProvider: IconProvider,
+    modifier: Modifier = Modifier,
+) {
     val colors = TileDefaults.getColorForState(uiState = uiState, iconOnly = false)
 
     Box(
@@ -291,7 +311,7 @@
         LargeTileContent(
             label = uiState.label,
             secondaryLabel = "",
-            iconProvider = { getTileIcon(icon = uiState.icon) },
+            iconProvider = { getTileIcon(icon = iconProvider) },
             sideDrawable = null,
             colors = colors,
             squishiness = { 1f },
@@ -299,8 +319,8 @@
     }
 }
 
-private fun Context.getTileIcon(icon: QSTile.Icon?): Icon {
-    return icon?.let {
+private fun Context.getTileIcon(icon: IconProvider): Icon {
+    return icon.icon?.let {
         if (it is QSTileImpl.ResourceIcon) {
             Icon.Resource(it.resId, null)
         } else {
@@ -321,28 +341,26 @@
 fun Modifier.tileCombinedClickable(
     onClick: () -> Unit,
     onLongClick: (() -> Unit)?,
-    uiState: TileUiState,
+    accessibilityUiState: AccessibilityUiState,
     iconOnly: Boolean,
 ): Modifier {
     val longPressLabel = longPressLabel()
     return combinedClickable(
             onClick = onClick,
             onLongClick = onLongClick,
-            onClickLabel = uiState.accessibilityUiState.clickLabel,
+            onClickLabel = accessibilityUiState.clickLabel,
             onLongClickLabel = longPressLabel,
             hapticFeedbackEnabled = !Flags.msdlFeedback(),
         )
         .semantics {
-            role = uiState.accessibilityUiState.accessibilityRole
-            if (uiState.accessibilityUiState.accessibilityRole == Role.Switch) {
-                uiState.accessibilityUiState.toggleableState?.let { toggleableState = it }
+            role = accessibilityUiState.accessibilityRole
+            if (accessibilityUiState.accessibilityRole == Role.Switch) {
+                accessibilityUiState.toggleableState?.let { toggleableState = it }
             }
-            stateDescription = uiState.accessibilityUiState.stateDescription
+            stateDescription = accessibilityUiState.stateDescription
         }
         .thenIf(iconOnly) {
-            Modifier.semantics {
-                contentDescription = uiState.accessibilityUiState.contentDescription
-            }
+            Modifier.semantics { contentDescription = accessibilityUiState.contentDescription }
         }
 }
 
@@ -474,14 +492,15 @@
                 label = label,
             )
 
-        val corner = remember {
-            object : CornerSize {
-                override fun toPx(shapeSize: Size, density: Density): Float {
-                    return with(density) { animatedCornerRadius.toPx() }
+        return remember {
+            val corner =
+                object : CornerSize {
+                    override fun toPx(shapeSize: Size, density: Density): Float {
+                        return with(density) { animatedCornerRadius.toPx() }
+                    }
                 }
-            }
+            mutableStateOf(RoundedCornerShape(corner))
         }
-        return remember { derivedStateOf { RoundedCornerShape(corner) } }
     }
 }
 
@@ -493,5 +512,5 @@
 @ReadOnlyComposable
 private fun resources(): Resources {
     LocalConfiguration.current
-    return LocalContext.current.resources
+    return LocalResources.current
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
index 03f0297..3287443 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.panels.ui.viewmodel
 
+import androidx.compose.runtime.Stable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import com.android.systemui.dagger.SysUISingleton
@@ -25,6 +26,7 @@
 import javax.inject.Inject
 
 @SysUISingleton
+@Stable
 class DetailsViewModel @Inject constructor(val currentTilesInteractor: CurrentTilesInteractor) {
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
index 19e542e..15e71c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
@@ -22,12 +22,18 @@
 import android.text.TextUtils
 import android.widget.Switch
 import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.state.ToggleableState
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.qs.tileimpl.SubtitleArrayMapping
 import com.android.systemui.res.R
+import java.util.function.Supplier
 
+/**
+ * Ui State for the tiles. It doesn't contain the icon to be able to invalidate the icon part
+ * separately. For the icon, use [IconProvider].
+ */
 @Immutable
 data class TileUiState(
     val label: String,
@@ -35,7 +41,6 @@
     val state: Int,
     val handlesLongClick: Boolean,
     val handlesSecondaryClick: Boolean,
-    val icon: QSTile.Icon?,
     val sideDrawable: Drawable?,
     val accessibilityUiState: AccessibilityUiState,
 )
@@ -90,7 +95,6 @@
         state = if (disabledByPolicy) Tile.STATE_UNAVAILABLE else state,
         handlesLongClick = handlesLongClick,
         handlesSecondaryClick = handlesSecondaryClick,
-        icon = icon ?: iconSupplier?.get(),
         sideDrawable = sideViewCustomDrawable,
         AccessibilityUiState(
             contentDescription?.toString() ?: "",
@@ -104,6 +108,14 @@
     )
 }
 
+fun QSTile.State.toIconProvider(): IconProvider {
+    return when {
+        icon != null -> IconProvider.ConstantIcon(icon)
+        iconSupplier != null -> IconProvider.IconSupplier(iconSupplier)
+        else -> IconProvider.Empty
+    }
+}
+
 private fun QSTile.State.getStateText(resources: Resources): CharSequence {
     val arrayResId = SubtitleArrayMapping.getSubtitleId(spec)
     val array = resources.getStringArray(arrayResId)
@@ -114,3 +126,21 @@
     val arrayResId = SubtitleArrayMapping.getSubtitleId(spec)
     return resources.getStringArray(arrayResId)[Tile.STATE_UNAVAILABLE]
 }
+
+@Stable
+sealed interface IconProvider {
+
+    val icon: QSTile.Icon?
+
+    data class ConstantIcon(override val icon: QSTile.Icon) : IconProvider
+
+    data class IconSupplier(val supplier: Supplier<QSTile.Icon?>) : IconProvider {
+        override val icon: QSTile.Icon?
+            get() = supplier.get()
+    }
+
+    data object Empty : IconProvider {
+        override val icon: QSTile.Icon?
+            get() = null
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileUserActionInteractor.kt
index 5e7172e..268efce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileUserActionInteractor.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager
 import com.android.systemui.accessibility.hearingaid.HearingDevicesUiEventLogger.Companion.LAUNCH_SOURCE_QS_TILE
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
 import com.android.systemui.qs.tiles.base.interactor.QSTileInput
 import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
@@ -37,6 +38,7 @@
     @Main private val mainContext: CoroutineContext,
     private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
     private val hearingDevicesDialogManager: HearingDevicesDialogManager,
+    private val settingsPackageRepository: QSSettingsPackageRepository,
 ) : QSTileUserActionInteractor<HearingDevicesTileModel> {
 
     override suspend fun handleInput(input: QSTileInput<HearingDevicesTileModel>) =
@@ -53,7 +55,8 @@
                 is QSTileUserAction.LongClick -> {
                     qsTileIntentUserActionHandler.handle(
                         action.expandable,
-                        Intent(Settings.ACTION_HEARING_DEVICES_SETTINGS),
+                        Intent(Settings.ACTION_HEARING_DEVICES_SETTINGS)
+                            .setPackage(settingsPackageRepository.getSettingsPackageName()),
                     )
                 }
                 is QSTileUserAction.ToggleClick -> {}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java
index 7a6426c..4be35f1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java
@@ -830,7 +830,8 @@
     private void notifySystemUiStateFlags(@SystemUiStateFlags long flags, int displayId) {
         if (SysUiState.DEBUG) {
             Log.d(TAG_OPS, "Notifying sysui state change to launcher service: proxy="
-                    + mLauncherProxy + " flags=" + flags + " displayId=" + displayId);
+                    + mLauncherProxy + " display=" + displayId + " flags="
+                    + QuickStepContract.getSystemUiStateString(flags) + " displayId=" + displayId);
         }
         try {
             if (mLauncherProxy != null) {
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 4753b9a..7bb831b 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
@@ -687,7 +687,7 @@
                 if (!isDeviceEntered) {
                     coroutineScope {
                         launch {
-                            deviceEntryHapticsInteractor.playSuccessHaptic
+                            deviceEntryHapticsInteractor.playSuccessHapticOnDeviceEntry
                                 .sample(sceneInteractor.currentScene)
                                 .collect { currentScene ->
                                     if (Flags.msdlFeedback()) {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
index b0fb619..634323c 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
@@ -83,7 +83,9 @@
      * testing.
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, DESCRIPTION)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, DESCRIPTION)
 
     /** Returns a developer-readable string that describes the current requirement list. */
     @JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index eae0ba6..ade62a9 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -164,16 +164,17 @@
         container.setVisibility(View.VISIBLE);
         ViewGroup.MarginLayoutParams lp =
                 (ViewGroup.MarginLayoutParams) container.getLayoutParams();
-        int horizontalMargin =
-                getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
-        lp.leftMargin = horizontalMargin;
-        lp.rightMargin = horizontalMargin;
-
-        int verticalMargin =
-                getResources().getDimensionPixelSize(
-                        R.dimen.notification_guts_option_vertical_padding);
-
-        lp.topMargin = verticalMargin;
+        // Remove the margin. Have the container take all the space. Instead, insert padding.
+        // This allows for the background to be visible around the slider.
+        int margin = 0;
+        lp.topMargin = margin;
+        lp.bottomMargin = margin;
+        lp.leftMargin = margin;
+        lp.rightMargin = margin;
+        int padding = getResources().getDimensionPixelSize(
+                R.dimen.rounded_slider_background_padding
+        );
+        container.setPadding(padding, padding, padding, padding);
         // If in multi-window or freeform, increase the top margin so the brightness dialog
         // doesn't get cut off.
         final int windowingMode = configuration.windowConfiguration.getWindowingMode();
@@ -182,17 +183,15 @@
             lp.topMargin += 50;
         }
 
-        lp.bottomMargin = verticalMargin;
-
         int orientation = configuration.orientation;
         int windowWidth = getWindowAvailableWidth();
 
         if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
             boolean shouldBeFullWidth = getIntent()
                     .getBooleanExtra(EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH, false);
-            lp.width = (shouldBeFullWidth ? windowWidth : windowWidth / 2) - horizontalMargin * 2;
+            lp.width = (shouldBeFullWidth ? windowWidth : windowWidth / 2) - margin * 2;
         } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-            lp.width = windowWidth - horizontalMargin * 2;
+            lp.width = windowWidth - margin * 2;
         }
 
         container.setLayoutParams(lp);
@@ -202,7 +201,7 @@
                     // Exclude this view (and its horizontal margins) from triggering gestures.
                     // This prevents back gesture from being triggered by dragging close to the
                     // edge of the slider (0% or 100%).
-                    bounds.set(-horizontalMargin, 0, right - left + horizontalMargin, bottom - top);
+                    bounds.set(-margin, 0, right - left + margin, bottom - top);
                     v.setSystemGestureExclusionRects(List.of(bounds));
                 });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt
index 9e20055..962a3bd 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt
@@ -17,12 +17,15 @@
 package com.android.systemui.settings.brightness
 
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.compose.ui.unit.dp
 import com.android.compose.theme.PlatformTheme
 import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
+import com.android.systemui.brightness.ui.compose.ContainerColors
 import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
 import com.android.systemui.lifecycle.rememberViewModel
 
@@ -44,7 +47,11 @@
         rememberViewModel(traceName = "BrightnessDialog.viewModel") {
             brightnessSliderViewModelFactory.create(false)
         }
-    BrightnessSliderContainer(viewModel = viewModel, Modifier.fillMaxWidth())
+    BrightnessSliderContainer(
+        viewModel = viewModel,
+        containerColors = ContainerColors.singleColor(ContainerColors.defaultContainerColor),
+        modifier = Modifier.fillMaxWidth().padding(8.dp),
+    )
 }
 
 class ComposableProvider(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 17fb50a..24e7976 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -140,6 +140,7 @@
 import com.android.systemui.settings.brightness.data.repository.BrightnessMirrorShowingRepository;
 import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractor;
 import com.android.systemui.shade.data.repository.FlingInfo;
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository;
 import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround;
@@ -204,6 +205,7 @@
 import com.google.android.msdl.data.model.MSDLToken;
 import com.google.android.msdl.domain.MSDLPlayer;
 
+import dagger.Lazy;
 import kotlin.Unit;
 
 import kotlinx.coroutines.CoroutineDispatcher;
@@ -394,7 +396,7 @@
     /** Whether the notifications are displayed full width (no margins on the side). */
     private boolean mIsFullWidth;
     private boolean mBlockingExpansionForCurrentTouch;
-     // Following variables maintain state of events when input focus transfer may occur.
+    // Following variables maintain state of events when input focus transfer may occur.
     private boolean mExpectingSynthesizedDown;
     private boolean mLastEventSynthesizedDown;
 
@@ -456,6 +458,7 @@
     @Deprecated // Use SysUIStateInteractor instead
     private final SysUiState mSysUiState;
     private final SysUIStateDisplaysInteractor mSysUIStateDisplaysInteractor;
+    private final Lazy<ShadeDisplaysRepository> mShadeDisplaysRepository;
     private final NotificationShadeDepthController mDepthController;
     private final NavigationBarController mNavigationBarController;
     private final int mDisplayId;
@@ -637,7 +640,8 @@
             KeyguardClockPositionAlgorithm keyguardClockPositionAlgorithm,
             MSDLPlayer msdlPlayer,
             BrightnessMirrorShowingRepository brightnessMirrorShowingRepository,
-            BlurConfig blurConfig) {
+            BlurConfig blurConfig,
+            Lazy<ShadeDisplaysRepository> shadeDisplaysRepository) {
         mBlurConfig = blurConfig;
         SceneContainerFlag.assertInLegacyMode();
         keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@@ -745,6 +749,7 @@
         mTapAgainViewController = tapAgainViewController;
         mSysUiState = sysUiState;
         mSysUIStateDisplaysInteractor = sysUIStateDisplaysInteractor;
+        mShadeDisplaysRepository = shadeDisplaysRepository;
         mKeyguardBypassController = bypassController;
         mUpdateMonitor = keyguardUpdateMonitor;
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
@@ -2716,8 +2721,17 @@
     }
 
     private int getShadeDisplayId() {
-        if (mView != null && mView.getDisplay() != null) return mView.getDisplay().getDisplayId();
-        return Display.DEFAULT_DISPLAY;
+        if (ShadeWindowGoesAround.isEnabled()) {
+            var pendingDisplayId =
+                    mShadeDisplaysRepository.get().getPendingDisplayId().getValue();
+            // Use the pendingDisplayId from the repository, *not* the Shade's context.
+            // This ensures correct UI state updates also if this method is called just *before*
+            // the Shade window moves to another display.
+            // The pendingDisplayId is guaranteed to be updated before this method is called.
+            return pendingDisplayId;
+        } else {
+            return Display.DEFAULT_DISPLAY;
+        }
     }
 
     private void setPerDisplaySysUIStateFlags() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 305444f..fa17b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -30,8 +30,6 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Trace;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
 import android.view.Display;
 import android.view.IWindow;
@@ -75,7 +73,6 @@
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
-import com.android.systemui.util.settings.SecureSettings;
 
 import dagger.Lazy;
 
@@ -134,7 +131,6 @@
 
     private final SysuiColorExtractor mColorExtractor;
     private final NotificationShadeWindowModel mNotificationShadeWindowModel;
-    private final SecureSettings mSecureSettings;
     /**
      * Layout params would be aggregated and dispatched all at once if this is > 0.
      *
@@ -168,7 +164,6 @@
             Lazy<SelectedUserInteractor> userInteractor,
             UserTracker userTracker,
             NotificationShadeWindowModel notificationShadeWindowModel,
-            SecureSettings secureSettings,
             Lazy<CommunalInteractor> communalInteractor,
             @ShadeDisplayAware LayoutParams shadeWindowLayoutParams) {
         mContext = context;
@@ -186,7 +181,6 @@
         mBackgroundExecutor = backgroundExecutor;
         mColorExtractor = colorExtractor;
         mNotificationShadeWindowModel = notificationShadeWindowModel;
-        mSecureSettings = secureSettings;
         // prefix with {slow} to make sure this dumps at the END of the critical section.
         dumpManager.registerCriticalDumpable("{slow}NotificationShadeWindowControllerImpl", this);
         mAuthController = authController;
@@ -424,7 +418,7 @@
                     (long) mLpChanged.preferredMaxDisplayRefreshRate);
         }
 
-        if (state.bouncerShowing && !isSecureWindowsDisabled()) {
+        if (state.bouncerShowing) {
             mLpChanged.flags |= LayoutParams.FLAG_SECURE;
         } else {
             mLpChanged.flags &= ~LayoutParams.FLAG_SECURE;
@@ -437,13 +431,6 @@
         }
     }
 
-    private boolean isSecureWindowsDisabled() {
-        return mSecureSettings.getIntForUser(
-            Settings.Secure.DISABLE_SECURE_WINDOWS,
-            0,
-            UserHandle.USER_CURRENT) == 1;
-    }
-
     private void adjustScreenOrientation(NotificationShadeWindowState state) {
         if (state.bouncerShowing || state.isKeyguardShowingAndNotOccluded() || state.dozing) {
             if (mKeyguardStateController.isKeyguardScreenRotationAllowed()) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index 96b224f..cd22473 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.res.R
 import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl
 import com.android.systemui.shade.display.ShadeDisplayPolicyModule
@@ -205,7 +206,18 @@
 
     @SysUISingleton
     @Provides
-    fun provideShadePositionRepository(impl: ShadeDisplaysRepositoryImpl): ShadeDisplaysRepository {
+    fun provideShadePositionRepository(
+        impl: MutableShadeDisplaysRepository
+    ): ShadeDisplaysRepository {
+        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
+        return impl
+    }
+
+    @SysUISingleton
+    @Provides
+    fun provideMutableShadePositionRepository(
+        impl: ShadeDisplaysRepositoryImpl
+    ): MutableShadeDisplaysRepository {
         ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
         return impl
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpandsOnStatusBarLongPress.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpandsOnStatusBarLongPress.kt
index 79e6333..63b618f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpandsOnStatusBarLongPress.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpandsOnStatusBarLongPress.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
index 3513334..e18ed83 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
@@ -22,16 +22,28 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 
-class FakeShadeDisplayRepository : ShadeDisplaysRepository {
+class FakeShadeDisplayRepository : MutableShadeDisplaysRepository {
     private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
+    private val _pendingDisplayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
 
     fun setDisplayId(displayId: Int) {
         _displayId.value = displayId
     }
 
+    fun setPendingDisplayId(displayId: Int) {
+        _pendingDisplayId.value = displayId
+    }
+
+    override fun onDisplayChangedSucceeded(displayId: Int) {
+        setDisplayId(displayId)
+    }
+
     override val displayId: StateFlow<Int>
         get() = _displayId
 
+    override val pendingDisplayId: StateFlow<Int>
+        get() = _pendingDisplayId
+
     override val currentPolicy: ShadeDisplayPolicy
         get() = FakeShadeDisplayPolicy
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
index 2a14ca4..7117a23 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
@@ -29,6 +29,7 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
@@ -40,10 +41,28 @@
 
 /** Source of truth for the display currently holding the shade. */
 interface ShadeDisplaysRepository {
-    /** ID of the display which currently hosts the shade */
+    /** ID of the display which currently hosts the shade. */
     val displayId: StateFlow<Int>
     /** The current policy set. */
     val currentPolicy: ShadeDisplayPolicy
+
+    /**
+     * Id of the display that should host the shade.
+     *
+     * If this differs from [displayId], it means there is a shade movement in progress. Classes
+     * that rely on the shade being already moved (and its context/resources updated) should rely on
+     * [displayId]. Classes that need to do work associated with the shade move, should listen at
+     * this.
+     */
+    val pendingDisplayId: StateFlow<Int>
+}
+
+/** Provides a way to set whether the display changed succeeded. */
+interface MutableShadeDisplaysRepository : ShadeDisplaysRepository {
+    /**
+     * To be called when the shade changed window, and its resources have been completely updated.
+     */
+    fun onDisplayChangedSucceeded(displayId: Int)
 }
 
 /**
@@ -63,7 +82,7 @@
     @ShadeOnDefaultDisplayWhenLocked private val shadeOnDefaultDisplayWhenLocked: Boolean,
     keyguardRepository: KeyguardRepository,
     displayRepository: DisplayRepository,
-) : ShadeDisplaysRepository {
+) : MutableShadeDisplaysRepository {
 
     private val policy: StateFlow<ShadeDisplayPolicy> =
         globalSettings
@@ -105,10 +124,16 @@
     override val currentPolicy: ShadeDisplayPolicy
         get() = policy.value
 
-    override val displayId: StateFlow<Int> =
+    override val pendingDisplayId: StateFlow<Int> =
         keyguardAwareDisplayPolicy.stateIn(
             bgScope,
             SharingStarted.WhileSubscribed(),
             Display.DEFAULT_DISPLAY,
         )
+    private val _committedDisplayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
+    override val displayId: StateFlow<Int> = _committedDisplayId
+
+    override fun onDisplayChangedSucceeded(displayId: Int) {
+        _committedDisplayId.value = displayId
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
index 930b1cb..0e0f58d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo
 import com.android.systemui.shade.ShadeTraceLogger.t
 import com.android.systemui.shade.ShadeTraceLogger.traceReparenting
+import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
 import com.android.systemui.shade.display.ShadeExpansionIntent
 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
@@ -44,6 +45,7 @@
 import kotlin.coroutines.CoroutineContext
 import kotlin.time.Duration.Companion.seconds
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.first
@@ -55,7 +57,7 @@
 class ShadeDisplaysInteractor
 @Inject
 constructor(
-    private val shadePositionRepository: ShadeDisplaysRepository,
+    private val shadePositionRepository: MutableShadeDisplaysRepository,
     @ShadeDisplayAware private val shadeContext: WindowContext,
     @ShadeDisplayAware private val configurationRepository: ConfigurationRepository,
     @Background private val bgScope: CoroutineScope,
@@ -72,11 +74,14 @@
     private val hasActiveNotifications: Boolean
         get() = activeNotificationsInteractor.areAnyNotificationsPresentValue
 
+    /** Current display id of the shade window. */
+    val displayId: StateFlow<Int> = shadePositionRepository.displayId
+
     override fun start() {
         ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
         listenForWindowContextConfigChanges()
         bgScope.launchTraced(TAG) {
-            shadePositionRepository.displayId.collectLatest { displayId ->
+            shadePositionRepository.pendingDisplayId.collectLatest { displayId ->
                 moveShadeWindowTo(displayId)
             }
         }
@@ -119,6 +124,7 @@
                         reparentToDisplayId(id = destinationId)
                     }
                     checkContextDisplayMatchesExpected(destinationId)
+                    shadePositionRepository.onDisplayChangedSucceeded(destinationId)
                 }
             }
         } catch (e: IllegalStateException) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
index 016f50f..81824f6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
@@ -67,7 +67,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index c9b96e9..ec04edb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -76,6 +76,7 @@
 import com.android.systemui.recents.LauncherProxyService;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -810,6 +811,10 @@
      *    lock time.
      */
     private boolean shouldShowSensitiveContentRedactedView(NotificationEntry ent) {
+        if (android.app.Flags.redactionOnLockscreenMetrics()) {
+            return shouldShowSensitiveContentRedactedViewWithLog(ent);
+        }
+
         if (!LockscreenOtpRedaction.isEnabled()) {
             return false;
         }
@@ -846,6 +851,71 @@
         return true;
     }
 
+    /*
+     * We show the sensitive content redaction view if
+     * 1. The feature is enabled
+     * 2. The notification has the `hasSensitiveContent` ranking variable set to true
+     * 3. The device is locked
+     * 4. The device is NOT connected to Wifi
+     * 5. The device has not connected to Wifi since receiving the notification
+     * 6. The notification arrived at least LOCK_TIME_FOR_SENSITIVE_REDACTION_MS after the last
+     *    lock time.
+     *
+     * This version of the method logs a metric about the request.
+     */
+    private boolean shouldShowSensitiveContentRedactedViewWithLog(NotificationEntry ent) {
+        if (!LockscreenOtpRedaction.isEnabled()) {
+            return false;
+        }
+
+        if (ent.getRanking() == null || !ent.getRanking().hasSensitiveContent()) {
+            return false;
+        }
+
+        long notificationWhen = ent.getSbn().getNotification().getWhen();
+        long notificationTime = getEarliestNotificationTime(ent);
+        boolean locked = mLocked.get();
+        long lockTime = mLastLockTime.get();
+        boolean wifiConnected = mConnectedToWifi.get();
+        long wifiConnectionTime = mLastWifiConnectionTime.get();
+
+        boolean shouldRedact = true;
+        if (!locked) {
+            shouldRedact = false;
+        }
+
+        if (!mRedactOtpOnWifi.get()) {
+            if (wifiConnected) {
+                shouldRedact = false;
+            }
+
+            // If the device has connected to wifi since receiving the notification, do not redact
+            if (notificationTime < wifiConnectionTime) {
+                shouldRedact = false;
+            }
+        }
+
+        // If the lock screen was not already locked for at least mOtpRedactionRequiredLockTimeMs
+        // when this notification arrived, do not redact
+        long latestTimeForRedaction = lockTime + mOtpRedactionRequiredLockTimeMs.get();
+
+        if (notificationTime < latestTimeForRedaction) {
+            shouldRedact = false;
+        }
+
+        int whenAndEarliestDiff = clampLongToIntRange(notificationWhen - notificationTime);
+        int earliestAndLockDiff = clampLongToIntRange(lockTime - notificationTime);
+        int earliestAndWifiDiff = clampLongToIntRange(wifiConnectionTime - notificationTime);
+        SysUiStatsLog.write(SysUiStatsLog.OTP_NOTIFICATION_DISPLAYED, shouldRedact,
+                whenAndEarliestDiff, locked, earliestAndLockDiff, wifiConnected,
+                earliestAndWifiDiff);
+        return shouldRedact;
+    }
+
+    private int clampLongToIntRange(long toConvert) {
+        return (int) Math.min(Integer.MAX_VALUE, Math.max(Integer.MIN_VALUE, toConvert));
+    }
+
     // Get the earliest time the user might have seen this notification. This is either the
     // notification's "when" time, or the notification entry creation time
     private long getEarliestNotificationTime(NotificationEntry notif) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 84266e8..bdfdb81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -38,13 +38,13 @@
 import com.android.systemui.Flags.spatialModelAppPushback
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionListener
+import com.android.systemui.shared.Flags.ambientAod
 import com.android.systemui.statusbar.phone.BiometricUnlockController
 import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
 import com.android.systemui.statusbar.phone.DozeParameters
@@ -53,16 +53,15 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.policy.SplitShadeStateController
 import com.android.systemui.util.WallpaperController
-import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor
 import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor
 import com.android.wm.shell.appzoomout.AppZoomOut
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
 import java.io.PrintWriter
 import java.util.Optional
 import javax.inject.Inject
 import kotlin.math.max
 import kotlin.math.sign
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 /**
  * Responsible for blurring the notification shade window, and applying a zoom effect to the
@@ -79,14 +78,12 @@
     private val keyguardInteractor: KeyguardInteractor,
     private val choreographer: Choreographer,
     private val wallpaperController: WallpaperController,
-    private val wallpaperInteractor: WallpaperInteractor,
     private val notificationShadeWindowController: NotificationShadeWindowController,
     private val dozeParameters: DozeParameters,
     @ShadeDisplayAware private val context: Context,
     private val splitShadeStateController: SplitShadeStateController,
     private val windowRootViewBlurInteractor: WindowRootViewBlurInteractor,
     private val appZoomOutOptional: Optional<AppZoomOut>,
-    @Application private val applicationScope: CoroutineScope,
     dumpManager: DumpManager,
     configurationController: ConfigurationController,
 ) : ShadeExpansionListener, Dumpable {
@@ -97,6 +94,7 @@
         private const val MIN_VELOCITY = -MAX_VELOCITY
         private const val INTERACTION_BLUR_FRACTION = 0.8f
         private const val ANIMATION_BLUR_FRACTION = 1f - INTERACTION_BLUR_FRACTION
+        private const val TRANSITION_THRESHOLD = 0.98f
         private const val TAG = "DepthController"
     }
 
@@ -115,8 +113,6 @@
     private var prevTimestamp: Long = -1
     private var prevShadeDirection = 0
     private var prevShadeVelocity = 0f
-    private var prevDozeAmount: Float = 0f
-    @VisibleForTesting var wallpaperSupportsAmbientMode: Boolean = false
     // tracks whether app launch transition is in progress. This involves two independent factors
     // that control blur, shade expansion and app launch animation from outside sysui.
     // They can complete out of order, this flag will be reset by the animation that finishes later.
@@ -163,6 +159,9 @@
     /**
      * When launching an app from the shade, the animations progress should affect how blurry the
      * shade is, overriding the expansion amount.
+     *
+     * TODO(b/399617511): remove this once [Flags.notificationShadeBlur] is launched and the Shade
+     *   closing is actually instantaneous.
      */
     var blursDisabledForAppLaunch: Boolean = false
         set(value) {
@@ -192,8 +191,12 @@
                 return
             }
 
-            shadeAnimation.animateTo(0)
-            shadeAnimation.finishIfRunning()
+            if (Flags.notificationShadeBlur()) {
+                shadeAnimation.skipTo(0)
+            } else {
+                shadeAnimation.animateTo(0)
+                shadeAnimation.finishIfRunning()
+            }
         }
         @Deprecated(
             message =
@@ -226,15 +229,7 @@
         }
 
     /** Blur radius of the wake-up animation on this frame. */
-    private var wakeBlurRadius = 0f
-        set(value) {
-            if (field == value) return
-            field = value
-            scheduleUpdate()
-        }
-
-    /** Blur radius of the unlock animation on this frame. */
-    private var unlockBlurRadius = 0f
+    private var wakeAndUnlockBlurRadius = 0f
         set(value) {
             if (field == value) return
             field = value
@@ -261,16 +256,14 @@
             ShadeInterpolation.getNotificationScrimAlpha(qsPanelExpansion) * shadeExpansion
         combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
         combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
-        var shadeRadius = max(combinedBlur, max(wakeBlurRadius, unlockBlurRadius))
+        var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius)
 
         if (areBlursDisabledForAppLaunch || blursDisabledForUnlock) {
             shadeRadius = 0f
         }
 
         var blur = shadeRadius.toInt()
-        // If the blur comes from waking up, we don't want to zoom out the background
-        val zoomOut =
-            if (shadeRadius != wakeBlurRadius) blurRadiusToZoomOut(blurRadius = shadeRadius) else 0f
+        val zoomOut = blurRadiusToZoomOut(blurRadius = shadeRadius)
         // Make blur be 0 if it is necessary to stop blur effect.
         if (scrimsVisible) {
             if (!Flags.notificationShadeBlur()) {
@@ -355,14 +348,14 @@
                         startDelay = keyguardStateController.keyguardFadingAwayDelay
                         interpolator = Interpolators.FAST_OUT_SLOW_IN
                         addUpdateListener { animation: ValueAnimator ->
-                            unlockBlurRadius =
+                            wakeAndUnlockBlurRadius =
                                 blurUtils.blurRadiusOfRatio(animation.animatedValue as Float)
                         }
                         addListener(
                             object : AnimatorListenerAdapter() {
                                 override fun onAnimationEnd(animation: Animator) {
                                     keyguardAnimator = null
-                                    unlockBlurRadius = 0f
+                                    wakeAndUnlockBlurRadius = 0f
                                 }
                             }
                         )
@@ -398,20 +391,15 @@
             }
 
             override fun onDozeAmountChanged(linear: Float, eased: Float) {
-                prevDozeAmount = eased
-                updateWakeBlurRadius(prevDozeAmount)
+                wakeAndUnlockBlurRadius =
+                    if (ambientAod()) {
+                        0f
+                    } else {
+                        blurUtils.blurRadiusOfRatio(eased)
+                    }
             }
         }
 
-    private fun updateWakeBlurRadius(ratio: Float) {
-        wakeBlurRadius =
-            if (!wallpaperSupportsAmbientMode) {
-                0f
-            } else {
-                blurUtils.blurRadiusOfRatio(ratio)
-            }
-    }
-
     init {
         dumpManager.registerCriticalDumpable(javaClass.name, this)
         if (WAKE_UP_ANIMATION_ENABLED) {
@@ -433,12 +421,6 @@
                 }
             }
         )
-        applicationScope.launch {
-            wallpaperInteractor.wallpaperSupportsAmbientMode.collect { supported ->
-                wallpaperSupportsAmbientMode = supported
-                updateWakeBlurRadius(prevDozeAmount)
-            }
-        }
         initBlurListeners()
     }
 
@@ -515,6 +497,22 @@
         scheduleUpdate()
     }
 
+    fun onTransitionAnimationProgress(progress: Float) {
+        if (!Flags.notificationShadeBlur() || !Flags.moveTransitionAnimationLayer()) return
+        // Because the Shade takes a few frames to actually trigger the unblur after a transition
+        // has ended, we need to disable it manually, or the opening window itself will be blurred
+        // for a few frames due to relative ordering. We do this towards the end, so that the
+        // window is already covering the background and the unblur is not visible.
+        if (progress >= TRANSITION_THRESHOLD && shadeAnimation.radius > 0) {
+            blursDisabledForAppLaunch = true
+        }
+    }
+
+    fun onTransitionAnimationEnd() {
+        if (!Flags.notificationShadeBlur() || !Flags.moveTransitionAnimationLayer()) return
+        blursDisabledForAppLaunch = false
+    }
+
     private fun updateShadeAnimationBlur(
         expansion: Float,
         tracking: Boolean,
@@ -613,8 +611,7 @@
             it.println("shouldApplyShadeBlur: ${shouldApplyShadeBlur()}")
             it.println("shadeAnimation: ${shadeAnimation.radius}")
             it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
-            it.println("wakeBlur: $wakeBlurRadius")
-            it.println("unlockBlur: $wakeBlurRadius")
+            it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
             it.println("blursDisabledForAppLaunch: $blursDisabledForAppLaunch")
             it.println("appLaunchTransitionIsInProgress: $appLaunchTransitionIsInProgress")
             it.println("qsPanelExpansion: $qsPanelExpansion")
@@ -660,6 +657,20 @@
             springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 }
         }
 
+        /**
+         * Starts an animation to [newRadius], or updates the current one if already ongoing.
+         * IMPORTANT: do NOT use this method + [finishIfRunning] to instantaneously change the value
+         * of the animation. The change will NOT be instantaneous. Use [skipTo] instead.
+         *
+         * Explanation:
+         * 1. If idle, [SpringAnimation.animateToFinalPosition] requests a start to the animation.
+         * 2. On the first frame after an idle animation is requested to start, the animation simply
+         *    acquires the starting value and does nothing else.
+         * 3. [SpringAnimation.skipToEnd] requests a fast-forward to the end value, but this happens
+         *    during calculation of the next animation value. Because on the first frame no such
+         *    calculation happens (point #2), there is one lagging frame where we still see the old
+         *    value.
+         */
         fun animateTo(newRadius: Int) {
             if (pendingRadius == newRadius) {
                 return
@@ -668,6 +679,19 @@
             springAnimation.animateToFinalPosition(newRadius.toFloat())
         }
 
+        /**
+         * Instantaneously set a new blur radius to this animation. Always use this instead of
+         * [animateTo] and [finishIfRunning] to make sure that the change takes effect in the next
+         * frame. See the doc for [animateTo] for an explanation.
+         */
+        fun skipTo(newRadius: Int) {
+            if (pendingRadius == newRadius) return
+            pendingRadius = newRadius
+            springAnimation.cancel()
+            springAnimation.setStartValue(newRadius.toFloat())
+            springAnimation.animateToFinalPosition(newRadius.toFloat())
+        }
+
         fun finishIfRunning() {
             if (springAnimation.isRunning) {
                 springAnimation.skipToEnd()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index be3afad..16bf43b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.chips.call.ui.viewmodel
 
+import android.app.PendingIntent
 import android.content.Context
 import android.view.View
 import com.android.internal.jank.Cuj
@@ -63,63 +64,69 @@
         interactor.ongoingCallState
             .map { state ->
                 when (state) {
-                    is OngoingCallModel.NoCall,
-                    is OngoingCallModel.InCallWithVisibleApp -> OngoingActivityChipModel.Inactive()
-                    is OngoingCallModel.InCall -> {
-                        val key = state.notificationKey
-                        val contentDescription = getContentDescription(state.appName)
-                        val icon =
-                            if (state.notificationIconView != null) {
-                                StatusBarConnectedDisplays.assertInLegacyMode()
-                                OngoingActivityChipModel.ChipIcon.StatusBarView(
-                                    state.notificationIconView,
-                                    contentDescription,
-                                )
-                            } else if (StatusBarConnectedDisplays.isEnabled) {
-                                OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon(
-                                    state.notificationKey,
-                                    contentDescription,
-                                )
-                            } else {
-                                OngoingActivityChipModel.ChipIcon.SingleColorIcon(phoneIcon)
-                            }
-
-                        val colors = ColorsModel.AccentThemed
-
-                        // This block mimics OngoingCallController#updateChip.
-                        if (state.startTimeMs <= 0L) {
-                            // If the start time is invalid, don't show a timer and show just an
-                            // icon. See b/192379214.
-                            OngoingActivityChipModel.Active.IconOnly(
-                                key = key,
-                                icon = icon,
-                                colors = colors,
-                                onClickListenerLegacy = getOnClickListener(state),
-                                clickBehavior = getClickBehavior(state),
-                            )
+                    is OngoingCallModel.NoCall -> OngoingActivityChipModel.Inactive()
+                    is OngoingCallModel.InCall ->
+                        if (state.isAppVisible) {
+                            OngoingActivityChipModel.Inactive()
                         } else {
-                            val startTimeInElapsedRealtime =
-                                state.startTimeMs - systemClock.currentTimeMillis() +
-                                    systemClock.elapsedRealtime()
-                            OngoingActivityChipModel.Active.Timer(
-                                key = key,
-                                icon = icon,
-                                colors = colors,
-                                startTimeMs = startTimeInElapsedRealtime,
-                                onClickListenerLegacy = getOnClickListener(state),
-                                clickBehavior = getClickBehavior(state),
-                            )
+                            prepareChip(state, systemClock)
                         }
-                    }
                 }
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Inactive())
 
-    private fun getOnClickListener(state: OngoingCallModel.InCall): View.OnClickListener? {
-        if (state.intent == null) {
-            return null
-        }
+    /** Builds an [OngoingActivityChipModel.Active] from all the relevant information. */
+    private fun prepareChip(
+        state: OngoingCallModel.InCall,
+        systemClock: SystemClock,
+    ): OngoingActivityChipModel.Active {
+        val key = state.notificationKey
+        val contentDescription = getContentDescription(state.appName)
+        val icon =
+            if (state.notificationIconView != null) {
+                StatusBarConnectedDisplays.assertInLegacyMode()
+                OngoingActivityChipModel.ChipIcon.StatusBarView(
+                    state.notificationIconView,
+                    contentDescription,
+                )
+            } else if (StatusBarConnectedDisplays.isEnabled) {
+                OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon(
+                    state.notificationKey,
+                    contentDescription,
+                )
+            } else {
+                OngoingActivityChipModel.ChipIcon.SingleColorIcon(phoneIcon)
+            }
 
+        val colors = ColorsModel.AccentThemed
+
+        // This block mimics OngoingCallController#updateChip.
+        if (state.startTimeMs <= 0L) {
+            // If the start time is invalid, don't show a timer and show just an icon.
+            // See b/192379214.
+            return OngoingActivityChipModel.Active.IconOnly(
+                key = key,
+                icon = icon,
+                colors = colors,
+                onClickListenerLegacy = getOnClickListener(state.intent),
+                clickBehavior = getClickBehavior(state.intent),
+            )
+        } else {
+            val startTimeInElapsedRealtime =
+                state.startTimeMs - systemClock.currentTimeMillis() + systemClock.elapsedRealtime()
+            return OngoingActivityChipModel.Active.Timer(
+                key = key,
+                icon = icon,
+                colors = colors,
+                startTimeMs = startTimeInElapsedRealtime,
+                onClickListenerLegacy = getOnClickListener(state.intent),
+                clickBehavior = getClickBehavior(state.intent),
+            )
+        }
+    }
+
+    private fun getOnClickListener(intent: PendingIntent?): View.OnClickListener? {
+        if (intent == null) return null
         return View.OnClickListener { view ->
             StatusBarChipsModernization.assertInLegacyMode()
             logger.log(TAG, LogLevel.INFO, {}, { "Chip clicked" })
@@ -127,7 +134,7 @@
                 view.requireViewById<ChipBackgroundContainer>(R.id.ongoing_activity_chip_background)
             // This mimics OngoingCallController#updateChipClickListener.
             activityStarter.postStartActivityDismissingKeyguard(
-                state.intent,
+                intent,
                 ActivityTransitionAnimator.Controller.fromView(
                     backgroundView,
                     Cuj.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
@@ -136,10 +143,8 @@
         }
     }
 
-    private fun getClickBehavior(
-        state: OngoingCallModel.InCall
-    ): OngoingActivityChipModel.ClickBehavior =
-        if (state.intent == null) {
+    private fun getClickBehavior(intent: PendingIntent?): OngoingActivityChipModel.ClickBehavior =
+        if (intent == null) {
             OngoingActivityChipModel.ClickBehavior.None
         } else {
             OngoingActivityChipModel.ClickBehavior.ExpandAction(
@@ -149,10 +154,7 @@
                         expandable.activityTransitionController(
                             Cuj.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP
                         )
-                    activityStarter.postStartActivityDismissingKeyguard(
-                        state.intent,
-                        animationController,
-                    )
+                    activityStarter.postStartActivityDismissingKeyguard(intent, animationController)
                 }
             )
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
index d8c3e25..a0de879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
@@ -56,7 +56,7 @@
     private val logger = Logger(logBuffer, "Notif".pad())
     // [StatusBarChipLogTag] recommends a max tag length of 20, so [extraLogTag] should NOT be the
     // top-level tag. It should instead be provided as the first string in each log message.
-    private val extraLogTag = "SingleChipInteractor[key=$key]"
+    private val extraLogTag = "SingleNotifChipInteractor[key=$key][id=${hashCode()}]"
 
     init {
         if (startingModel.promotedContent == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
index 35e622b..9380dfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
@@ -38,6 +38,7 @@
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -45,6 +46,7 @@
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
 
 /** An interactor for the notification chips shown in the status bar. */
 @SysUISingleton
@@ -147,28 +149,42 @@
      */
     val allNotificationChips: Flow<List<NotificationChipModel>> =
         if (StatusBarNotifChips.isEnabled) {
-            // For all our current interactors...
-            // TODO(b/364653005): When a promoted notification is added or removed, each individual
-            // interactor's [notificationChip] flow becomes un-collected then re-collected, which
-            // can cause some flows to remove then add callbacks when they don't need to. Is there a
-            // better structure for this? Maybe Channels or a StateFlow with a short timeout?
-            promotedNotificationInteractors.flatMapLatest { interactors ->
-                if (interactors.isNotEmpty()) {
-                    // Combine each interactor's [notificationChip] flow...
-                    val allNotificationChips: List<Flow<NotificationChipModel?>> =
-                        interactors.map { interactor -> interactor.notificationChip }
-                    combine(allNotificationChips) {
+                // For all our current interactors...
+                promotedNotificationInteractors.flatMapLatest { interactors ->
+                    if (interactors.isNotEmpty()) {
+                        // Combine each interactor's [notificationChip] flow...
+                        val allNotificationChips: List<Flow<NotificationChipModel?>> =
+                            interactors.map { interactor -> interactor.notificationChip }
+                        combine(allNotificationChips) {
                             // ... and emit just the non-null & sorted chips
                             it.filterNotNull().sortedWith(chipComparator)
                         }
-                        .logSort()
-                } else {
-                    flowOf(emptyList())
+                    } else {
+                        flowOf(emptyList())
+                    }
                 }
+            } else {
+                flowOf(emptyList())
             }
-        } else {
-            flowOf(emptyList())
-        }
+            .distinctUntilChanged()
+            .logSort()
+            .stateIn(
+                backgroundScope,
+                SharingStarted.WhileSubscribed(
+                    // When a promoted notification is added or removed, the `.flatMapLatest` above
+                    // will stop collection and then re-start collection on each individual
+                    // interactor's flow. (It will happen even for a chip that didn't change.) We
+                    // don't want the individual interactor flows to stop then re-start because they
+                    // may be maintaining values that would get thrown away when collection stops
+                    // (like an app's last visible time).
+                    // stopTimeoutMillis ensures we maintain those values even during the brief
+                    // moment (1-2ms) when `.flatMapLatest` causes collect to stop then immediately
+                    // restart.
+                    // Note: Channels could also work to solve this.
+                    stopTimeoutMillis = 1000
+                ),
+                initialValue = emptyList(),
+            )
 
     /** Emits the notifications that should actually be *shown* as chips in the status bar. */
     val shownNotificationChips: Flow<List<NotificationChipModel>> =
@@ -199,14 +215,14 @@
         }
 
     private fun Flow<List<NotificationChipModel>>.logSort(): Flow<List<NotificationChipModel>> {
-        return this.distinctUntilChanged().onEach { chips ->
+        return this.onEach { chips ->
             val logString =
                 chips.joinToString {
                     "{key=${it.key}. " +
                         "lastVisibleAppTime=${it.lastAppVisibleTime}. " +
                         "creationTime=${it.creationTime}}"
                 }
-            logger.d({ "Sorted chips: $str1" }) { str1 = logString }
+            logger.d({ "Sorted notif chips: $str1" }) { str1 = logString }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
index 947e93c..6431f30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
index 02e4ba4..6f85527 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -19,6 +19,7 @@
 import android.annotation.IdRes
 import android.content.Context
 import android.content.res.ColorStateList
+import android.graphics.Typeface
 import android.graphics.drawable.GradientDrawable
 import android.view.View
 import android.view.ViewGroup
@@ -27,6 +28,7 @@
 import android.widget.ImageView
 import android.widget.TextView
 import androidx.annotation.UiThread
+import com.android.systemui.FontStyles
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.ui.binder.ContentDescriptionViewBinder
 import com.android.systemui.common.ui.binder.IconViewBinder
@@ -170,6 +172,16 @@
         forceLayout()
     }
 
+    /** Updates the typefaces for any text shown in the chip. */
+    fun updateTypefaces(binding: OngoingActivityChipViewBinding) {
+        binding.timeView.typeface =
+            Typeface.create(FontStyles.GSF_LABEL_LARGE_EMPHASIZED, Typeface.NORMAL)
+        binding.textView.typeface =
+            Typeface.create(FontStyles.GSF_LABEL_LARGE_EMPHASIZED, Typeface.NORMAL)
+        binding.shortTimeDeltaView.typeface =
+            Typeface.create(FontStyles.GSF_LABEL_LARGE_EMPHASIZED, Typeface.NORMAL)
+    }
+
     private fun setChipIcon(
         chipModel: OngoingActivityChipModel.Active,
         backgroundView: ChipBackgroundContainer,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
index 5242fea..55d7536 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.chips.ui.compose
 
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
@@ -27,11 +28,13 @@
 import androidx.compose.ui.node.LayoutModifierNode
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.text.TextMeasurer
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.rememberTextMeasurer
 import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.constrain
 import androidx.compose.ui.unit.dp
@@ -42,14 +45,16 @@
 import com.android.systemui.statusbar.chips.ui.viewmodel.rememberTimeRemainingState
 import kotlin.math.min
 
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
 fun ChipContent(viewModel: OngoingActivityChipModel.Active, modifier: Modifier = Modifier) {
     val context = LocalContext.current
+    val density = LocalDensity.current
     val isTextOnly = viewModel.icon == null
     val hasEmbeddedIcon =
         viewModel.icon is OngoingActivityChipModel.ChipIcon.StatusBarView ||
             viewModel.icon is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon
-    val textStyle = MaterialTheme.typography.labelLarge
+    val textStyle = MaterialTheme.typography.labelLargeEmphasized
     val textColor = Color(viewModel.colors.text(context))
     val maxTextWidth = dimensionResource(id = R.dimen.ongoing_activity_chip_max_text_width)
     val startPadding =
@@ -86,7 +91,7 @@
                             startPadding = startPadding,
                             endPadding = endPadding,
                         )
-                        .neverDecreaseWidth(),
+                        .neverDecreaseWidth(density),
             )
         }
 
@@ -97,7 +102,7 @@
                 style = textStyle,
                 color = textColor,
                 softWrap = false,
-                modifier = modifier.neverDecreaseWidth(),
+                modifier = modifier.neverDecreaseWidth(density),
             )
         }
 
@@ -150,23 +155,31 @@
 }
 
 /** A modifier that ensures the width of the content only increases and never decreases. */
-private fun Modifier.neverDecreaseWidth(): Modifier {
-    return this.then(NeverDecreaseWidthElement)
+private fun Modifier.neverDecreaseWidth(density: Density): Modifier {
+    return this.then(NeverDecreaseWidthElement(density))
 }
 
-private data object NeverDecreaseWidthElement : ModifierNodeElement<NeverDecreaseWidthNode>() {
+private data class NeverDecreaseWidthElement(val density: Density) :
+    ModifierNodeElement<NeverDecreaseWidthNode>() {
     override fun create(): NeverDecreaseWidthNode {
         return NeverDecreaseWidthNode()
     }
 
     override fun update(node: NeverDecreaseWidthNode) {
-        error("This should never be called")
+        node.onDensityUpdated()
     }
 }
 
 private class NeverDecreaseWidthNode : Modifier.Node(), LayoutModifierNode {
     private var minWidth = 0
 
+    fun onDensityUpdated() {
+        // When the font or display size changes, we should re-determine what our minWidth is from
+        // scratch (e.g. if the font size decreased, we may be able to take *less* room).
+        // See b/395607413.
+        minWidth = 0
+    }
+
     override fun MeasureScope.measure(
         measurable: Measurable,
         constraints: Constraints,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
index e8ab396..4edb23d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
@@ -18,24 +18,18 @@
 
 import android.content.res.ColorStateList
 import android.view.ViewGroup
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.clickable
+import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.widthIn
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.dimensionResource
@@ -43,7 +37,6 @@
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.viewinterop.AndroidView
 import com.android.compose.animation.Expandable
-import com.android.compose.modifiers.thenIf
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.ui.compose.Icon
 import com.android.systemui.common.ui.compose.load
@@ -60,27 +53,45 @@
     iconViewStore: NotificationIconContainerViewBinder.IconViewStore?,
     modifier: Modifier = Modifier,
 ) {
-    when (val clickBehavior = model.clickBehavior) {
-        is OngoingActivityChipModel.ClickBehavior.ExpandAction -> {
-            // Wrap the chip in an Expandable so we can animate the expand transition.
-            ExpandableChip(
-                color = { Color.Transparent },
-                shape =
-                    RoundedCornerShape(
-                        dimensionResource(id = R.dimen.ongoing_activity_chip_corner_radius)
-                    ),
-                modifier = modifier,
-            ) { expandable ->
-                ChipBody(model, iconViewStore, onClick = { clickBehavior.onClick(expandable) })
-            }
-        }
-        is OngoingActivityChipModel.ClickBehavior.ShowHeadsUpNotification -> {
-            ChipBody(model, iconViewStore, onClick = { clickBehavior.onClick() })
+    val contentDescription =
+        when (val icon = model.icon) {
+            is OngoingActivityChipModel.ChipIcon.StatusBarView -> icon.contentDescription.load()
+            is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon ->
+                icon.contentDescription.load()
+            is OngoingActivityChipModel.ChipIcon.SingleColorIcon,
+            null -> null
         }
 
-        is OngoingActivityChipModel.ClickBehavior.None -> {
-            ChipBody(model, iconViewStore, modifier = modifier)
+    val borderStroke =
+        model.colors.outline(LocalContext.current)?.let {
+            BorderStroke(dimensionResource(R.dimen.ongoing_activity_chip_outline_width), Color(it))
         }
+
+    val onClick =
+        when (val clickBehavior = model.clickBehavior) {
+            is OngoingActivityChipModel.ClickBehavior.ExpandAction -> { expandable: Expandable ->
+                    clickBehavior.onClick(expandable)
+                }
+            is OngoingActivityChipModel.ClickBehavior.ShowHeadsUpNotification -> { _ ->
+                    clickBehavior.onClick()
+                }
+            is OngoingActivityChipModel.ClickBehavior.None -> null
+        }
+
+    Expandable(
+        color = Color(model.colors.background(LocalContext.current).defaultColor),
+        shape =
+            RoundedCornerShape(dimensionResource(id = R.dimen.ongoing_activity_chip_corner_radius)),
+        modifier =
+            modifier.height(dimensionResource(R.dimen.ongoing_appops_chip_height)).semantics {
+                if (contentDescription != null) {
+                    this.contentDescription = contentDescription
+                }
+            },
+        borderStroke = borderStroke,
+        onClick = onClick,
+    ) {
+        ChipBody(model, iconViewStore, isClickable = onClick != null)
     }
 }
 
@@ -88,22 +99,13 @@
 private fun ChipBody(
     model: OngoingActivityChipModel.Active,
     iconViewStore: NotificationIconContainerViewBinder.IconViewStore?,
+    isClickable: Boolean,
     modifier: Modifier = Modifier,
-    onClick: (() -> Unit)? = null,
 ) {
-    val context = LocalContext.current
-    val isClickable = onClick != null
     val hasEmbeddedIcon =
         model.icon is OngoingActivityChipModel.ChipIcon.StatusBarView ||
             model.icon is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon
-    val contentDescription =
-        when (val icon = model.icon) {
-            is OngoingActivityChipModel.ChipIcon.StatusBarView -> icon.contentDescription.load()
-            is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon ->
-                icon.contentDescription.load()
-            is OngoingActivityChipModel.ChipIcon.SingleColorIcon -> null
-            null -> null
-        }
+
     val chipSidePadding = dimensionResource(id = R.dimen.ongoing_activity_chip_side_padding)
     val minWidth =
         if (isClickable) {
@@ -114,68 +116,38 @@
             dimensionResource(id = R.dimen.ongoing_activity_chip_min_text_width) + chipSidePadding
         }
 
-    val outline = model.colors.outline(context)
-    val outlineWidth = dimensionResource(R.dimen.ongoing_activity_chip_outline_width)
-
-    val shape =
-        RoundedCornerShape(dimensionResource(id = R.dimen.ongoing_activity_chip_corner_radius))
-
-    // Use a Box with `fillMaxHeight` to create a larger click surface for the chip. The visible
-    // height of the chip is determined by the height of the background of the Row below.
-    Box(
-        contentAlignment = Alignment.Center,
+    Row(
+        horizontalArrangement = Arrangement.Center,
+        verticalAlignment = Alignment.CenterVertically,
         modifier =
             modifier
                 .fillMaxHeight()
-                .clickable(enabled = isClickable, onClick = onClick ?: {})
-                .semantics {
-                    if (contentDescription != null) {
-                        this.contentDescription = contentDescription
-                    }
-                },
-    ) {
-        Row(
-            horizontalArrangement = Arrangement.Center,
-            verticalAlignment = Alignment.CenterVertically,
-            modifier =
-                Modifier.height(dimensionResource(R.dimen.ongoing_appops_chip_height))
-                    .thenIf(isClickable) { Modifier.widthIn(min = minWidth) }
-                    .layout { measurable, constraints ->
-                        val placeable = measurable.measure(constraints)
-                        layout(placeable.width, placeable.height) {
-                            if (constraints.maxWidth >= minWidth.roundToPx()) {
-                                placeable.place(0, 0)
-                            }
+                .layout { measurable, constraints ->
+                    val placeable = measurable.measure(constraints)
+                    layout(placeable.width, placeable.height) {
+                        if (constraints.maxWidth >= minWidth.roundToPx()) {
+                            placeable.place(0, 0)
                         }
                     }
-                    .background(Color(model.colors.background(context).defaultColor), shape = shape)
-                    .thenIf(outline != null) {
-                        Modifier.border(
-                            width = outlineWidth,
-                            color = Color(outline!!),
-                            shape = shape,
-                        )
-                    }
-                    .padding(
-                        horizontal =
-                            if (hasEmbeddedIcon) {
-                                dimensionResource(
-                                    R.dimen
-                                        .ongoing_activity_chip_side_padding_for_embedded_padding_icon
-                                )
-                            } else {
-                                dimensionResource(id = R.dimen.ongoing_activity_chip_side_padding)
-                            }
-                    ),
-        ) {
-            model.icon?.let {
-                ChipIcon(viewModel = it, iconViewStore = iconViewStore, colors = model.colors)
-            }
+                }
+                .padding(
+                    horizontal =
+                        if (hasEmbeddedIcon) {
+                            dimensionResource(
+                                R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon
+                            )
+                        } else {
+                            dimensionResource(id = R.dimen.ongoing_activity_chip_side_padding)
+                        }
+                ),
+    ) {
+        model.icon?.let {
+            ChipIcon(viewModel = it, iconViewStore = iconViewStore, colors = model.colors)
+        }
 
-            val isIconOnly = model is OngoingActivityChipModel.Active.IconOnly
-            if (!isIconOnly) {
-                ChipContent(viewModel = model)
-            }
+        val isIconOnly = model is OngoingActivityChipModel.Active.IconOnly
+        if (!isIconOnly) {
+            ChipContent(viewModel = model)
         }
     }
 }
@@ -223,6 +195,7 @@
     iconFactory: () -> StatusBarIconView?,
 ) {
     val context = LocalContext.current
+    val colorTintList = ColorStateList.valueOf(colors.text(context))
 
     val iconSizePx =
         context.resources.getDimensionPixelSize(
@@ -233,18 +206,8 @@
         factory = { _ ->
             iconFactory.invoke()?.apply {
                 layoutParams = ViewGroup.LayoutParams(iconSizePx, iconSizePx)
-                imageTintList = ColorStateList.valueOf(colors.text(context))
             } ?: throw IllegalStateException("Missing StatusBarIconView for $notificationKey")
         },
+        update = { iconView -> iconView.imageTintList = colorTintList },
     )
 }
-
-@Composable
-private fun ExpandableChip(
-    color: () -> Color,
-    shape: Shape,
-    modifier: Modifier = Modifier,
-    content: @Composable (Expandable) -> Unit,
-) {
-    Expandable(color = color(), shape = shape, modifier = modifier.clip(shape)) { content(it) }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
index 3b8c0f4..7080c34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
@@ -25,6 +25,7 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.dimensionResource
+import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
@@ -47,7 +48,13 @@
         chips.active
             .filter { !it.isHidden }
             .forEach {
-                key(it.key) { OngoingActivityChip(model = it, iconViewStore = iconViewStore) }
+                key(it.key) {
+                    OngoingActivityChip(
+                        model = it,
+                        iconViewStore = iconViewStore,
+                        modifier = Modifier.sysuiResTag(it.key),
+                    )
+                }
             }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
index 4954cb0..b268376 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
@@ -19,7 +19,6 @@
 import android.content.Context
 import android.content.res.ColorStateList
 import androidx.annotation.ColorInt
-import com.android.settingslib.Utils
 import com.android.systemui.res.R
 
 /** Model representing how the chip in the status bar should be colored. */
@@ -34,14 +33,14 @@
     @ColorInt fun outline(context: Context): Int?
 
     /** The chip should match the theme's primary accent color. */
-    // TODO(b/347717946): The chip's color isn't getting updated when the user switches theme, it
-    // only gets updated when a different configuration change happens, like a rotation.
     data object AccentThemed : ColorsModel {
         override fun background(context: Context): ColorStateList =
-            Utils.getColorAttr(context, com.android.internal.R.attr.colorAccent)
+            ColorStateList.valueOf(
+                context.getColor(com.android.internal.R.color.materialColorPrimaryFixedDim)
+            )
 
         override fun text(context: Context) =
-            Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)
+            context.getColor(com.android.internal.R.color.materialColorOnPrimaryFixed)
 
         override fun outline(context: Context) = null
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
index 0cfc321..8e47074 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.chips.ui.model
 
+import android.annotation.CurrentTimeMillisLong
+import android.annotation.ElapsedRealtimeLong
 import android.view.View
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription
@@ -102,7 +104,7 @@
              * [ChipChronometer] is based off of elapsed realtime. See
              * [android.widget.Chronometer.setBase].
              */
-            val startTimeMs: Long,
+            @ElapsedRealtimeLong val startTimeMs: Long,
             override val onClickListenerLegacy: View.OnClickListener?,
             override val clickBehavior: ClickBehavior,
             override val isHidden: Boolean = false,
@@ -129,10 +131,15 @@
             override val icon: ChipIcon,
             override val colors: ColorsModel,
             /**
-             * The time of the event that this chip represents, relative to
-             * [com.android.systemui.util.time.SystemClock.currentTimeMillis].
+             * The time of the event that this chip represents. Relative to
+             * [com.android.systemui.util.time.SystemClock.currentTimeMillis] because that's what's
+             * required by [android.widget.DateTimeView].
+             *
+             * TODO(b/372657935): When the Compose chips are launched, we should convert this to be
+             *   relative to [com.android.systemui.util.time.SystemClock.elapsedRealtime] so that
+             *   this model and the [Timer] model use the same units.
              */
-            val time: Long,
+            @CurrentTimeMillisLong val time: Long,
             override val onClickListenerLegacy: View.OnClickListener?,
             override val clickBehavior: ClickBehavior,
             override val isHidden: Boolean = false,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index eae2c25..8228b55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -555,7 +555,6 @@
                 secondary = DEFAULT_INTERNAL_INACTIVE_MODEL,
             )
 
-        // TODO(b/392886257): Support 3 chips if there's space available.
-        private const val MAX_VISIBLE_CHIPS = 2
+        private const val MAX_VISIBLE_CHIPS = 3
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingState.kt
index eb6ebca..803d422 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingState.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.chips.ui.viewmodel
 
-import android.os.SystemClock
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.derivedStateOf
@@ -39,7 +38,14 @@
  * Manages state and updates for the duration remaining between now and a given time in the future.
  */
 class TimeRemainingState(private val timeSource: TimeSource, private val futureTimeMillis: Long) {
-    private var durationRemaining by mutableStateOf(Duration.ZERO)
+    // Start with the right duration from the outset so we don't use "now" as an initial value.
+    private var durationRemaining by
+        mutableStateOf(
+            calculateDurationRemaining(
+                currentTimeMillis = timeSource.getCurrentTime(),
+                futureTimeMillis = futureTimeMillis,
+            )
+        )
     private var startTimeMillis: Long = 0
 
     /**
@@ -56,7 +62,11 @@
         while (true) {
             val currentTime = timeSource.getCurrentTime()
             durationRemaining =
-                (futureTimeMillis - currentTime).toDuration(DurationUnit.MILLISECONDS)
+                calculateDurationRemaining(
+                    currentTimeMillis = currentTime,
+                    futureTimeMillis = futureTimeMillis,
+                )
+
             // No need to update if duration is more than 1 minute in the past. Because, we will
             // stop displaying anything.
             if (durationRemaining.inWholeMilliseconds < -1.minutes.inWholeMilliseconds) {
@@ -67,6 +77,13 @@
         }
     }
 
+    private fun calculateDurationRemaining(
+        currentTimeMillis: Long,
+        futureTimeMillis: Long,
+    ): Duration {
+        return (futureTimeMillis - currentTimeMillis).toDuration(DurationUnit.MILLISECONDS)
+    }
+
     private fun calculateNextUpdateDelay(duration: Duration): Long {
         val durationAbsolute = duration.absoluteValue
         return when {
@@ -85,7 +102,7 @@
 @Composable
 fun rememberTimeRemainingState(
     futureTimeMillis: Long,
-    timeSource: TimeSource = remember { TimeSource { SystemClock.elapsedRealtime() } },
+    timeSource: TimeSource = remember { TimeSource { System.currentTimeMillis() } },
 ): TimeRemainingState {
 
     val state =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt
index 9e1686a..03316d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt
@@ -49,7 +49,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt
index cb1827d..a58e00c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
index 4ee49d8..25dace3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
@@ -52,7 +52,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 434eb7d..a7929ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -33,6 +33,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpHandler;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
@@ -44,7 +45,6 @@
 import com.android.systemui.shade.carrier.ShadeCarrierGroupController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationClickNotifier;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
index 27d8151..9db2f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerModule
 import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStoreModule
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryModule
+import com.android.systemui.statusbar.data.repository.StatusBarPerDisplayConfigurationStateModule
 import com.android.systemui.statusbar.data.repository.SystemEventChipAnimationControllerStoreModule
 import com.android.systemui.statusbar.phone.data.StatusBarPhoneDataLayerModule
 import dagger.Module
@@ -34,6 +35,7 @@
             LightBarControllerStoreModule::class,
             RemoteInputRepositoryModule::class,
             StatusBarConfigurationControllerModule::class,
+            StatusBarPerDisplayConfigurationStateModule::class,
             StatusBarContentInsetsProviderStoreModule::class,
             StatusBarModeRepositoryModule::class,
             StatusBarPhoneDataLayerModule::class,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
index 7fa9f0e..a658e1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
@@ -267,7 +267,8 @@
                         if (StatusBarChipsModernization.isEnabled) {
                             ongoingProcessRequiresStatusBarVisible
                         } else {
-                            ongoingCallStateLegacy is OngoingCallModel.InCall
+                            ongoingCallStateLegacy is OngoingCallModel.InCall &&
+                                !ongoingCallStateLegacy.isAppVisible
                         }
                     val statusBarMode =
                         toBarMode(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayConfigurationStateRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayConfigurationStateRepository.kt
new file mode 100644
index 0000000..3168a22
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayConfigurationStateRepository.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.data.repository
+
+import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
+import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.common.ui.ConfigurationStateImpl
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.data.repository.PerDisplayInstanceProvider
+import com.android.systemui.display.data.repository.PerDisplayInstanceRepositoryImpl
+import com.android.systemui.display.data.repository.PerDisplayRepository
+import com.android.systemui.display.data.repository.SingleInstanceRepositoryImpl
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import dagger.Lazy
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+
+@SysUISingleton
+class StatusBarPerDisplayConfigurationStateProvider
+@Inject
+constructor(
+    private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
+    private val statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore,
+    private val factory: ConfigurationStateImpl.Factory,
+) : PerDisplayInstanceProvider<ConfigurationState> {
+
+    override fun createInstance(displayId: Int): ConfigurationState? {
+        val displayWindowProperties =
+            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
+        val configController =
+            statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
+        return factory.create(displayWindowProperties.context, configController)
+    }
+}
+
+@Module
+object StatusBarPerDisplayConfigurationStateModule {
+
+    @Provides
+    @SysUISingleton
+    fun store(
+        instanceProvider: Lazy<StatusBarPerDisplayConfigurationStateProvider>,
+        factory: PerDisplayInstanceRepositoryImpl.Factory<ConfigurationState>,
+        defaultInstance: ConfigurationState,
+    ): PerDisplayRepository<ConfigurationState> {
+        val name = "ConfigurationState"
+        return if (StatusBarConnectedDisplays.isEnabled) {
+            factory.create(name, instanceProvider.get())
+        } else {
+            SingleInstanceRepositoryImpl(name, defaultInstance)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt
index 08a8960..d1307aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt b/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt
index 7a985e7..7b1024c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 4053d06..8be9e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -124,8 +124,14 @@
         Notification notification = sbn.getNotification();
         if (notification.contentIntent != null || notification.fullScreenIntent != null
                 || row.getEntry().isBubble()) {
-            row.setBubbleClickListener(v ->
-                    mNotificationActivityStarter.onNotificationBubbleIconClicked(row.getEntry()));
+            if (NotificationBundleUi.isEnabled()) {
+                row.setBubbleClickListener(
+                        v -> row.getEntryAdapter().onNotificationBubbleIconClicked());
+            } else {
+                row.setBubbleClickListener(v ->
+                        mNotificationActivityStarter.onNotificationBubbleIconClicked(
+                                row.getEntry()));
+            }
             row.setOnClickListener(this);
             row.setOnDragSuccessListener(mOnDragSuccessListener);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
index 6dd44a1..41353b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
@@ -45,8 +45,6 @@
  */
 public class BundleEntry extends PipelineEntry {
 
-    private final BundleEntryAdapter mEntryAdapter;
-
     // TODO(b/394483200): move NotificationEntry's implementation to PipelineEntry?
     private final MutableStateFlow<Boolean> mSensitive = StateFlowKt.MutableStateFlow(false);
 
@@ -55,7 +53,6 @@
 
     public BundleEntry(String key) {
         super(key);
-        mEntryAdapter = new BundleEntryAdapter();
     }
 
     @Nullable
@@ -86,126 +83,9 @@
         return false;
     }
 
-    @VisibleForTesting
-    public BundleEntryAdapter getEntryAdapter() {
-        return mEntryAdapter;
-    }
-
-    public class BundleEntryAdapter implements EntryAdapter {
-
-        /**
-         * TODO (b/394483200): convert to PipelineEntry.ROOT_ENTRY when pipeline is migrated?
-         */
-        @Override
-        public GroupEntry getParent() {
-            return GroupEntry.ROOT_ENTRY;
-        }
-
-        @Override
-        public boolean isTopLevelEntry() {
-            return true;
-        }
-
-        @NonNull
-        @Override
-        public String getKey() {
-            return mKey;
-        }
-
-        @Override
-        @Nullable
-        public ExpandableNotificationRow getRow() {
-            return mRow;
-        }
-
-        @Override
-        public boolean isGroupRoot() {
-            return true;
-        }
-
-        @Override
-        public StateFlow<Boolean> isSensitive() {
-            return BundleEntry.this.mSensitive;
-        }
-
-        @Override
-        public boolean isClearable() {
-            // TODO(b/394483200): check whether all of the children are clearable, when implemented
-            return true;
-        }
-
-        @Override
-        public int getTargetSdk() {
-            return Build.VERSION_CODES.CUR_DEVELOPMENT;
-        }
-
-        @Override
-        public String getSummarization() {
-            return null;
-        }
-
-        @Override
-        public int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor) {
-            return Notification.COLOR_DEFAULT;
-        }
-
-        @Override
-        public boolean canPeek() {
-            return false;
-        }
-
-        @Override
-        public long getWhen() {
-            return 0;
-        }
-
-        @Override
-        public IconPack getIcons() {
-            // TODO(b/396446620): implement bundle icons
-            return null;
-        }
-
-        @Override
-        public boolean isColorized() {
-            return false;
-        }
-
-        @Override
-        @Nullable
-        public StatusBarNotification getSbn() {
-            return null;
-        }
-
-        @Override
-        public boolean canDragAndDrop() {
-            return false;
-        }
-
-        @Override
-        public boolean isBubbleCapable() {
-            return false;
-        }
-
-        @Override
-        @Nullable
-        public String getStyle() {
-            return null;
-        }
-
-        @Override
-        public int getSectionBucket() {
-            return mBucket;
-        }
-
-        @Override
-        public boolean isAmbient() {
-            return false;
-        }
-
-        @Override
-        public boolean isFullScreenCapable() {
-            return false;
-        }
+    @Nullable
+    public ExpandableNotificationRow getRow() {
+        return mRow;
     }
 
     public static final List<BundleEntry> ROOT_BUNDLES = List.of(
@@ -213,4 +93,8 @@
             new BundleEntry(SOCIAL_MEDIA_ID),
             new BundleEntry(NEWS_ID),
             new BundleEntry(RECS_ID));
+
+    public MutableStateFlow<Boolean> isSensitive() {
+        return mSensitive;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
new file mode 100644
index 0000000..64db9df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.collection
+
+import android.app.Notification
+import android.content.Context
+import android.os.Build
+import android.service.notification.StatusBarNotification
+import com.android.systemui.statusbar.notification.icon.IconPack
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import kotlinx.coroutines.flow.StateFlow
+
+class BundleEntryAdapter(val entry: BundleEntry) : EntryAdapter {
+    /** TODO (b/394483200): convert to PipelineEntry.ROOT_ENTRY when pipeline is migrated? */
+    override fun getParent(): GroupEntry {
+        return GroupEntry.ROOT_ENTRY
+    }
+
+    override fun isTopLevelEntry(): Boolean {
+        return true
+    }
+
+    override fun getKey(): String {
+        return entry.key
+    }
+
+    override fun getRow(): ExpandableNotificationRow? {
+        return entry.row
+    }
+
+    override fun isGroupRoot(): Boolean {
+        return true
+    }
+
+    override fun isSensitive(): StateFlow<Boolean> {
+        return entry.isSensitive
+    }
+
+    override fun isClearable(): Boolean {
+        // TODO(b/394483200): check whether all of the children are clearable, when implemented
+        return true
+    }
+
+    override fun getTargetSdk(): Int {
+        return Build.VERSION_CODES.CUR_DEVELOPMENT
+    }
+
+    override fun getSummarization(): String? {
+        return null
+    }
+
+    override fun getContrastedColor(
+        context: Context?,
+        isLowPriority: Boolean,
+        backgroundColor: Int,
+    ): Int {
+        return Notification.COLOR_DEFAULT
+    }
+
+    override fun canPeek(): Boolean {
+        return false
+    }
+
+    override fun getWhen(): Long {
+        return 0
+    }
+
+    override fun getIcons(): IconPack? {
+        // TODO(b/396446620): implement bundle icons
+        return null
+    }
+
+    override fun isColorized(): Boolean {
+        return false
+    }
+
+    override fun getSbn(): StatusBarNotification? {
+        return null
+    }
+
+    override fun canDragAndDrop(): Boolean {
+        return false
+    }
+
+    override fun isBubbleCapable(): Boolean {
+        return false
+    }
+
+    override fun getStyle(): String? {
+        return null
+    }
+
+    override fun getSectionBucket(): Int {
+        return entry.bucket
+    }
+
+    override fun isAmbient(): Boolean {
+        return false
+    }
+
+    override fun isFullScreenCapable(): Boolean {
+        return false
+    }
+
+    override fun onNotificationBubbleIconClicked() {
+        // do nothing. these cannot be a bubble
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
index 307a957..0e75b60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
@@ -50,7 +50,7 @@
     /**
      * Gets the view that this entry is backing.
      */
-    @NonNull
+    @Nullable
     ExpandableNotificationRow getRow();
 
     /**
@@ -135,5 +135,10 @@
     default boolean isFullScreenCapable() {
         return false;
     }
+
+    /**
+     * Process a click on a notification bubble icon
+     */
+    void onNotificationBubbleIconClicked();
 }
 
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactory.kt
similarity index 67%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactory.kt
index 6b8161c..b7a84dd 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactory.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,6 +14,9 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package com.android.systemui.statusbar.notification.collection
 
-parcelable SoundProfileHandle;
+/** Creates an appropriate EntryAdapter for the entry type given */
+interface EntryAdapterFactory {
+    fun create(entry: PipelineEntry): EntryAdapter
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
new file mode 100644
index 0000000..779c25a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.collection
+
+import androidx.annotation.VisibleForTesting
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
+import javax.inject.Inject
+
+/** Creates an appropriate EntryAdapter for the entry type given */
+class EntryAdapterFactoryImpl
+@Inject
+constructor(
+    private val notificationActivityStarter: NotificationActivityStarter,
+    private val metricsLogger: MetricsLogger,
+    private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
+    private val iconStyleProvider: NotificationIconStyleProvider,
+    private val visualStabilityCoordinator: VisualStabilityCoordinator,
+) : EntryAdapterFactory {
+    override fun create(entry: PipelineEntry): EntryAdapter {
+        return if (entry is NotificationEntry) {
+            NotificationEntryAdapter(
+                notificationActivityStarter,
+                metricsLogger,
+                peopleNotificationIdentifier,
+                iconStyleProvider,
+                visualStabilityCoordinator,
+                entry,
+            )
+        } else {
+            BundleEntryAdapter((entry as BundleEntry))
+        }
+    }
+
+    @VisibleForTesting
+    fun getNotificationActivityStarter() : NotificationActivityStarter {
+        return notificationActivityStarter
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index b19ba3a..3d8ba7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -109,7 +109,6 @@
     private final String mKey;
     private StatusBarNotification mSbn;
     private Ranking mRanking;
-    private final NotifEntryAdapter mEntryAdapter;
 
     /*
      * Bookkeeping members
@@ -270,141 +269,6 @@
         mKey = sbn.getKey();
         setSbn(sbn);
         setRanking(ranking);
-        mEntryAdapter = new NotifEntryAdapter();
-    }
-
-    public class NotifEntryAdapter implements EntryAdapter {
-        @Override
-        public PipelineEntry getParent() {
-            return NotificationEntry.this.getParent();
-        }
-
-        @Override
-        public boolean isTopLevelEntry() {
-            return getParent() != null
-                    && (getParent() == ROOT_ENTRY || ROOT_BUNDLES.contains(getParent()));
-        }
-
-        @Override
-        public String getKey() {
-            return NotificationEntry.this.getKey();
-        }
-
-        @Override
-        public ExpandableNotificationRow getRow() {
-            return NotificationEntry.this.getRow();
-        }
-
-        @Override
-        public boolean isGroupRoot() {
-            if (isTopLevelEntry() || getParent() == null) {
-                return false;
-            }
-            if (NotificationEntry.this.getParent() instanceof GroupEntry parentGroupEntry) {
-                return parentGroupEntry.getSummary() == NotificationEntry.this;
-            }
-            return false;
-        }
-
-        @Override
-        public StateFlow<Boolean> isSensitive() {
-            return NotificationEntry.this.isSensitive();
-        }
-
-        @Override
-        public boolean isClearable() {
-            return NotificationEntry.this.isClearable();
-        }
-
-        @Override
-        public int getTargetSdk() {
-            return NotificationEntry.this.targetSdk;
-        }
-
-        @Override
-        public String getSummarization() {
-            return getRanking().getSummarization();
-        }
-
-        @Override
-        public void prepareForInflation() {
-            getSbn().clearPackageContext();
-        }
-
-        @Override
-        public int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor) {
-            return NotificationEntry.this.getContrastedColor(
-                    context, isLowPriority, backgroundColor);
-        }
-
-        @Override
-        public boolean canPeek() {
-            return isStickyAndNotDemoted();
-        }
-
-        @Override
-        public long getWhen() {
-            return getSbn().getNotification().getWhen();
-        }
-
-        @Override
-        public IconPack getIcons() {
-            return NotificationEntry.this.getIcons();
-        }
-
-        @Override
-        public boolean isColorized() {
-            return getSbn().getNotification().isColorized();
-        }
-
-        @Override
-        @Nullable
-        public StatusBarNotification getSbn() {
-            return NotificationEntry.this.getSbn();
-        }
-
-        @Override
-        public boolean canDragAndDrop() {
-            boolean canBubble = canBubble();
-            Notification notif = getSbn().getNotification();
-            PendingIntent dragIntent = notif.contentIntent != null ? notif.contentIntent
-                    : notif.fullScreenIntent;
-            if (dragIntent != null && dragIntent.isActivity() && !canBubble) {
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public boolean isBubbleCapable() {
-            return NotificationEntry.this.isBubble();
-        }
-
-        @Override
-        @Nullable
-        public String getStyle() {
-            return getNotificationStyle();
-        }
-
-        @Override
-        public int getSectionBucket() {
-            return mBucket;
-        }
-
-        @Override
-        public boolean isAmbient() {
-            return mRanking.isAmbient();
-        }
-
-        @Override
-        public boolean isFullScreenCapable() {
-            return getSbn().getNotification().fullScreenIntent != null;
-        }
-
-    }
-
-    public EntryAdapter getEntryAdapter() {
-        return mEntryAdapter;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
new file mode 100644
index 0000000..0ff2dd7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.collection
+
+import android.content.Context
+import android.service.notification.StatusBarNotification
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.icon.IconPack
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
+import kotlinx.coroutines.flow.StateFlow
+
+class NotificationEntryAdapter(
+    private val notificationActivityStarter: NotificationActivityStarter,
+    private val metricsLogger: MetricsLogger,
+    private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
+    private val iconStyleProvider: NotificationIconStyleProvider,
+    private val visualStabilityCoordinator: VisualStabilityCoordinator,
+    private val entry: NotificationEntry,
+) : EntryAdapter {
+
+    override fun getParent(): PipelineEntry? {
+        return entry.parent
+    }
+
+    override fun isTopLevelEntry(): Boolean {
+        return parent != null &&
+            (parent === GroupEntry.ROOT_ENTRY || BundleEntry.ROOT_BUNDLES.contains(parent))
+    }
+
+    override fun getKey(): String {
+        return entry.key
+    }
+
+    override fun getRow(): ExpandableNotificationRow {
+        return entry.row
+    }
+
+    override fun isGroupRoot(): Boolean {
+        if (isTopLevelEntry || parent == null) {
+            return false
+        }
+        return (entry.parent as? GroupEntry)?.summary == entry
+    }
+
+    override fun isSensitive(): StateFlow<Boolean> {
+        return entry.isSensitive
+    }
+
+    override fun isClearable(): Boolean {
+        return entry.isClearable
+    }
+
+    override fun getTargetSdk(): Int {
+        return entry.targetSdk
+    }
+
+    override fun getSummarization(): String? {
+        return entry.ranking?.summarization
+    }
+
+    override fun prepareForInflation() {
+        entry.sbn.clearPackageContext()
+    }
+
+    override fun getContrastedColor(
+        context: Context?,
+        isLowPriority: Boolean,
+        backgroundColor: Int,
+    ): Int {
+        return entry.getContrastedColor(context, isLowPriority, backgroundColor)
+    }
+
+    override fun canPeek(): Boolean {
+        return entry.isStickyAndNotDemoted
+    }
+
+    override fun getWhen(): Long {
+        return entry.sbn.notification.getWhen()
+    }
+
+    override fun getIcons(): IconPack {
+        return entry.icons
+    }
+
+    override fun isColorized(): Boolean {
+        return entry.sbn.notification.isColorized
+    }
+
+    override fun getSbn(): StatusBarNotification {
+        return entry.sbn
+    }
+
+    override fun canDragAndDrop(): Boolean {
+        val canBubble: Boolean = entry.canBubble()
+        val notif = entry.sbn.notification
+        val dragIntent =
+            if (notif.contentIntent != null) notif.contentIntent else notif.fullScreenIntent
+        if (dragIntent != null && dragIntent.isActivity && !canBubble) {
+            return true
+        }
+        return false
+    }
+
+    override fun isBubbleCapable(): Boolean {
+        return entry.isBubble
+    }
+
+    override fun getStyle(): String? {
+        return entry.notificationStyle
+    }
+
+    override fun getSectionBucket(): Int {
+        return entry.bucket
+    }
+
+    override fun isAmbient(): Boolean {
+        return entry.ranking.isAmbient
+    }
+
+    override fun isFullScreenCapable(): Boolean {
+        return entry.sbn.notification.fullScreenIntent != null
+    }
+
+    override fun onNotificationBubbleIconClicked() {
+        notificationActivityStarter.onNotificationBubbleIconClicked(entry)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt
index 179a87d..cf78812 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 53d5dbc..ef3da94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -37,6 +37,8 @@
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactory;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
 import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl;
@@ -340,4 +342,8 @@
             return MagneticNotificationRowManager.getEmpty();
         }
     }
+
+    /** Provides an instance of {@link EntryAdapterFactory} */
+    @Binds
+    EntryAdapterFactory provideEntryAdapterFactory(EntryAdapterFactoryImpl impl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/shared/ModesEmptyShadeFix.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/shared/ModesEmptyShadeFix.kt
index d3a44f9..52bf894 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/shared/ModesEmptyShadeFix.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/shared/ModesEmptyShadeFix.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt
index dbe046f..90faa4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimator.kt
index b5d7321..2f2d80a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimator.kt
@@ -47,7 +47,7 @@
      * of the animation.
      */
     fun getHeadsUpYTranslation(isHeadsUpFromBottom: Boolean, hasStatusBarChip: Boolean): Int {
-        NotificationsHunSharedAnimationValues.unsafeAssertInNewMode()
+        if (NotificationsHunSharedAnimationValues.isUnexpectedlyInLegacyMode()) return 0
 
         if (isHeadsUpFromBottom) {
             // start from or end at the bottom of the screen
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/NotificationsHunSharedAnimationValues.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/NotificationsHunSharedAnimationValues.kt
index c538316..f52d351 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/NotificationsHunSharedAnimationValues.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/NotificationsHunSharedAnimationValues.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt
index aa81ebf..147a5af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt
@@ -18,11 +18,10 @@
 
 import android.view.Display
 import androidx.lifecycle.lifecycleScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.app.tracing.traceSection
 import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.display.data.repository.PerDisplayRepository
 import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.notification.collection.NotifCollection
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder.IconViewStore
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel
@@ -37,7 +36,8 @@
 @Inject
 constructor(
     private val viewModel: NotificationIconContainerStatusBarViewModel,
-    @ShadeDisplayAware private val configuration: ConfigurationState,
+    private val configurationStateRepository: PerDisplayRepository<ConfigurationState>,
+    private val defaultConfigurationState: ConfigurationState,
     private val systemBarUtilsState: SystemBarUtilsState,
     private val failureTracker: StatusBarIconViewBindingFailureTracker,
     private val defaultDisplayViewStore: StatusBarNotificationIconViewStore,
@@ -56,12 +56,14 @@
                             lifecycleScope.launch { it.activate() }
                         }
                     }
+                val configurationState: ConfigurationState =
+                    configurationStateRepository[displayId] ?: defaultConfigurationState
                 lifecycleScope.launch {
                     NotificationIconContainerViewBinder.bind(
                         displayId = displayId,
                         view = view,
                         viewModel = viewModel,
-                        configuration = configuration,
+                        configuration = configurationState,
                         systemBarUtilsState = systemBarUtilsState,
                         failureTracker = failureTracker,
                         viewStore = viewStore,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index c3266fc..92c87e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -18,10 +18,10 @@
 
 import android.service.notification.StatusBarNotification
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.media.NotificationMediaManager
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
 import com.android.systemui.statusbar.NotificationListener
-import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.NotificationPresenter
 import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
 import com.android.systemui.statusbar.notification.NotificationActivityStarter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUi.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUi.kt
index 5bf5766..da59a40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUi.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiAod.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiAod.kt
index 8679975..c6e3da1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiAod.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiAod.kt
@@ -49,7 +49,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt
index 287e002..adeddde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt
index 1abd48c..a99ca072 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt
@@ -70,9 +70,6 @@
     private fun OngoingCallModel.getNotifData(): NotifAndPromotedContent? =
         when (this) {
             is OngoingCallModel.InCall -> NotifAndPromotedContent(notificationKey, promotedContent)
-            is OngoingCallModel.InCallWithVisibleApp ->
-                // TODO(b/395989259): support InCallWithVisibleApp when it has notif data
-                null
             is OngoingCallModel.NoCall -> null
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 6837cb2..6892226 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -128,9 +128,14 @@
         updateColors();
     }
 
-    private void updateColors() {
-        if (usesTransparentBackground()) {
-            mNormalColor = SurfaceEffectColors.surfaceEffect1(getContext());
+    protected void updateColors() {
+        if (notificationRowTransparency()) {
+            if (mIsBlurSupported) {
+                mNormalColor = SurfaceEffectColors.surfaceEffect1(getContext());
+            } else {
+                mNormalColor = mContext.getColor(
+                        com.android.internal.R.color.materialColorSurfaceContainer);
+            }
         } else {
             mNormalColor = mContext.getColor(
                     com.android.internal.R.color.materialColorSurfaceContainerHigh);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
index 640d364..dccc28f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
@@ -34,11 +34,11 @@
 import android.view.View
 import android.widget.ImageView
 import android.widget.LinearLayout
-import android.widget.Switch
 import android.widget.TextView
 import com.android.settingslib.Utils
 import com.android.systemui.res.R
 import com.android.systemui.util.Assert
+import com.google.android.material.materialswitch.MaterialSwitch
 
 /** Half-shelf for notification channel controls */
 class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) {
@@ -139,12 +139,12 @@
 class AppControlView(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) {
     lateinit var iconView: ImageView
     lateinit var channelName: TextView
-    lateinit var switch: Switch
+    lateinit var switch: MaterialSwitch
 
     override fun onFinishInflate() {
         iconView = requireViewById(R.id.icon)
         channelName = requireViewById(R.id.app_name)
-        switch = requireViewById(R.id.toggle)
+        switch = requireViewById(R.id.material_toggle)
 
         setOnClickListener { switch.toggle() }
     }
@@ -155,7 +155,7 @@
     lateinit var controller: ChannelEditorDialogController
     private lateinit var channelName: TextView
     private lateinit var channelDescription: TextView
-    private lateinit var switch: Switch
+    private lateinit var switch: MaterialSwitch
     private val highlightColor: Int
     var gentle = false
 
@@ -175,7 +175,7 @@
         super.onFinishInflate()
         channelName = requireViewById(R.id.channel_name)
         channelDescription = requireViewById(R.id.channel_description)
-        switch = requireViewById(R.id.toggle)
+        switch = requireViewById(R.id.material_toggle)
         switch.setOnCheckedChangeListener { _, b ->
             channel?.let {
                 controller.proposeEditForChannel(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 987068d..c877bee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -19,9 +19,12 @@
 import static android.app.Flags.notificationsRedesignTemplates;
 import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_EXPANDED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
 
 import static com.android.systemui.Flags.notificationRowTransparency;
 import static com.android.systemui.Flags.notificationsPinnedHunInShade;
+import static com.android.systemui.Flags.notificationRowAccessibilityExpanded;
 import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE;
 import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
 import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
@@ -111,6 +114,8 @@
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.collection.EntryAdapter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryAdapter;
+import com.android.systemui.statusbar.notification.collection.PipelineEntry;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -121,6 +126,7 @@
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.shared.LockscreenOtpRedaction;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModelImpl;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationCompactMessagingTemplateViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss;
@@ -403,10 +409,7 @@
     }
 
     private void toggleExpansionState(View v, boolean shouldLogExpandClickMetric) {
-        boolean isGroupRoot = NotificationBundleUi.isEnabled()
-                ? mGroupMembershipManager.isGroupRoot(mEntryAdapter)
-                : mGroupMembershipManager.isGroupSummary(mEntry);
-        if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) && isGroupRoot) {
+        if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) && isGroupRoot()) {
             mGroupExpansionChanging = true;
             if (NotificationBundleUi.isEnabled()) {
                 final boolean wasExpanded =  mGroupExpansionManager.isGroupExpanded(mEntryAdapter);
@@ -428,7 +431,7 @@
                 onExpansionChanged(true /* userAction */, wasExpanded);
             }
         } else if (mEnableNonGroupedNotificationExpand) {
-            if (v.isAccessibilityFocused()) {
+            if (v != null && v.isAccessibilityFocused()) {
                 mPrivateLayout.setFocusOnVisibilityChange();
             }
             boolean nowExpanded;
@@ -976,7 +979,7 @@
         } else if (isAboveShelf() != wasAboveShelf) {
             mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
         }
-        updateBackgroundOpacity();
+        updateColors();
     }
 
     /**
@@ -1682,13 +1685,11 @@
         }
         if (notificationRowTransparency() && mBackgroundNormal != null) {
             if (NotificationBundleUi.isEnabled() && mEntryAdapter != null) {
-                mBackgroundNormal.setBgIsColorized(
-                        usesTransparentBackground() && mEntryAdapter.isColorized());
+                mBackgroundNormal.setBgIsColorized(mEntryAdapter.isColorized());
             } else {
                 if (mEntry != null) {
                     mBackgroundNormal.setBgIsColorized(
-                            usesTransparentBackground()
-                                    && mEntry.getSbn().getNotification().isColorized());
+                            mEntry.getSbn().getNotification().isColorized());
                 }
             }
         }
@@ -1818,6 +1819,22 @@
         );
     }
 
+    /**
+     * Init the bundle header view. The ComposeView is initialized within with the passed viewModel.
+     * This can only be init once and not in conjunction with any other header view.
+     */
+    public void initBundleHeader(@NonNull BundleHeaderViewModelImpl bundleHeaderViewModel) {
+        if (NotificationBundleUi.isUnexpectedlyInLegacyMode()) return;
+        NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull();
+        bundleHeaderViewModel.setOnExpandClickListener(mExpandClickListener);
+
+        childrenContainer.initBundleHeader(bundleHeaderViewModel);
+
+        if (TransparentHeaderFix.isEnabled()) {
+            updateBackgroundForGroupState();
+        }
+    }
+
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
         boolean wasAboveShelf = isAboveShelf();
         boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
@@ -2124,7 +2141,8 @@
      * Initialize row.
      */
     public void initialize(
-            NotificationEntry entry,
+            EntryAdapter entryAdapter,
+            PipelineEntry entry,
             RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
             String appName,
             @NonNull String notificationKey,
@@ -2152,11 +2170,11 @@
             NotificationRebindingTracker notificationRebindingTracker) {
 
         if (NotificationBundleUi.isEnabled()) {
+            mEntryAdapter = entryAdapter;
             // TODO (b/395857098): remove when all usages are migrated
-            mEntryAdapter = entry.getEntryAdapter();
-            mEntry = entry;
+            mEntry = (NotificationEntry) entry;
         } else {
-            mEntry = entry;
+            mEntry = (NotificationEntry) entry;
         }
         mAppName = appName;
         mRebindingTracker = notificationRebindingTracker;
@@ -2757,7 +2775,6 @@
         return false;
     }
 
-
     public void applyLaunchAnimationParams(LaunchAnimationParameters params) {
         if (params == null) {
             // `null` params indicates the animation is over, which means we can't access
@@ -3048,7 +3065,6 @@
 
         mUserLocked = userLocked;
         mPrivateLayout.setUserExpanding(userLocked);
-        mPublicLayout.setUserExpanding(userLocked);
         // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
         // children but not anymore.
         if (mChildrenContainer != null) {
@@ -3105,7 +3121,7 @@
                     mChildrenContainer.setOnKeyguard(onKeyguard);
                 }
             }
-            updateBackgroundOpacity();
+            updateColors();
         }
     }
 
@@ -3176,6 +3192,12 @@
         return mGroupExpansionManager.isGroupExpanded(mEntry);
     }
 
+    private boolean isGroupRoot() {
+        return NotificationBundleUi.isEnabled()
+                ? mGroupMembershipManager.isGroupRoot(mEntryAdapter)
+                : mGroupMembershipManager.isGroupSummary(mEntry);
+    }
+
     private void onAttachedChildrenCountChanged() {
         final boolean wasSummary = mIsSummaryWithChildren;
         mIsSummaryWithChildren = mChildrenContainer != null
@@ -3254,6 +3276,27 @@
     }
 
     /**
+     * Is this row currently showing an expanded state? This method is different from
+     * {@link #isExpanded()}, because it also handles groups, and pinned notifications.
+     */
+    private boolean isShowingExpanded() {
+        if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) && isGroupRoot()) {
+            // is group and expanded?
+            return isGroupExpanded();
+        } else if (mEnableNonGroupedNotificationExpand) {
+            if (isPinned()) {
+                // is pinned and expanded?
+                return mExpandedWhenPinned;
+            } else {
+                // is regular notification and expanded?
+                return isExpanded();
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
      * Check whether the view state is currently expanded. This is given by the system in {@link
      * #setSystemExpanded(boolean)} and can be overridden by user expansion or
      * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
@@ -3935,9 +3978,7 @@
 
     public void onExpandedByGesture(boolean userExpanded) {
         int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
-        if (NotificationBundleUi.isEnabled()
-                ? mGroupMembershipManager.isGroupRoot(mEntryAdapter)
-                : mGroupMembershipManager.isGroupSummary(mEntry)) {
+        if (isGroupRoot()) {
             event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
         }
         mMetricsLogger.action(event, userExpanded);
@@ -3990,9 +4031,19 @@
             if (mExpansionChangedListener != null) {
                 mExpansionChangedListener.onExpansionChanged(nowExpanded);
             }
+            if (notificationRowAccessibilityExpanded()) {
+                notifyAccessibilityContentExpansionChanged();
+            }
         }
     }
 
+    private void notifyAccessibilityContentExpansionChanged() {
+        AccessibilityEvent event = AccessibilityEvent.obtain(TYPE_WINDOW_CONTENT_CHANGED);
+        onPopulateAccessibilityEvent(event);
+        event.setContentChangeTypes(CONTENT_CHANGE_TYPE_EXPANDED);
+        sendAccessibilityEventUnchecked(event);
+    }
+
     public void setOnExpansionChangedListener(@Nullable OnExpansionChangedListener listener) {
         mExpansionChangedListener = listener;
     }
@@ -4020,33 +4071,50 @@
         super.onInitializeAccessibilityNodeInfoInternal(info);
         final boolean isLongClickable = isNotificationRowLongClickable();
         if (isLongClickable) {
-            info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+            info.addAction(AccessibilityAction.ACTION_LONG_CLICK);
         }
         info.setLongClickable(isLongClickable);
 
         if (canViewBeDismissed() && !mIsSnoozed) {
-            info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
+            info.addAction(AccessibilityAction.ACTION_DISMISS);
         }
-        boolean expandable = shouldShowPublic();
-        boolean isExpanded = false;
-        if (!expandable) {
-            if (mIsSummaryWithChildren) {
-                expandable = true;
-                if (!mIsMinimized || isExpanded()) {
-                    isExpanded = isGroupExpanded();
+
+        if (notificationRowAccessibilityExpanded()) {
+            if (isAccessibilityExpandable()) {
+                if (isShowingExpanded()) {
+                    info.addAction(AccessibilityAction.ACTION_COLLAPSE);
+                    info.setExpandedState(AccessibilityNodeInfo.EXPANDED_STATE_FULL);
+                } else {
+                    info.addAction(AccessibilityAction.ACTION_EXPAND);
+                    info.setExpandedState(AccessibilityNodeInfo.EXPANDED_STATE_COLLAPSED);
                 }
             } else {
-                expandable = mPrivateLayout.isContentExpandable();
-                isExpanded = isExpanded();
+                info.setExpandedState(AccessibilityNodeInfo.EXPANDED_STATE_UNDEFINED);
+            }
+        } else {
+            boolean expandable = shouldShowPublic();
+            boolean isExpanded = false;
+            if (!expandable) {
+                if (mIsSummaryWithChildren) {
+                    expandable = true;
+                    if (!mIsMinimized || isExpanded()) {
+                        isExpanded = isGroupExpanded();
+                    }
+                } else {
+                    expandable = mPrivateLayout.isContentExpandable();
+                    isExpanded = isExpanded();
+                }
+            }
+
+            if (expandable) {
+                if (isExpanded) {
+                    info.addAction(AccessibilityAction.ACTION_COLLAPSE);
+                } else {
+                    info.addAction(AccessibilityAction.ACTION_EXPAND);
+                }
             }
         }
-        if (expandable && !mIsSnoozed) {
-            if (isExpanded) {
-                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
-            } else {
-                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
-            }
-        }
+
         NotificationMenuRowPlugin provider = getProvider();
         if (provider != null) {
             MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
@@ -4059,6 +4127,12 @@
         }
     }
 
+    /** @return whether this row's expansion state can be toggled by an accessibility action. */
+    private boolean isAccessibilityExpandable() {
+        // don't add expand accessibility actions to snoozed notifications
+        return !mIsSnoozed && isContentExpandable();
+    }
+
     @Override
     public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
         if (super.performAccessibilityActionInternal(action, arguments)) {
@@ -4325,6 +4399,10 @@
             if (PromotedNotificationUiForceExpanded.isEnabled()) {
                 pw.print(", isPromotedOngoing: " + isPromotedOngoing());
             }
+            if (notificationRowAccessibilityExpanded()) {
+                pw.print(", isShowingExpanded: " + isShowingExpanded());
+                pw.print(", isAccessibilityExpandable: " + isAccessibilityExpandable());
+            }
             pw.print(", isExpandable: " + isExpandable());
             pw.print(", mExpandable: " + mExpandable);
             pw.print(", isUserExpanded: " + isUserExpanded());
@@ -4552,11 +4630,8 @@
         }
     }
 
-    private void updateBackgroundOpacity() {
-        if (mBackgroundNormal != null) {
-            // Row background should be opaque when it's displayed as a heads-up notification or
-            // displayed on keyguard.
-            mBackgroundNormal.setForceOpaque(mIsHeadsUp || mOnKeyguard);
-        }
+    @Override
+    protected boolean usesTransparentBackground() {
+        return super.usesTransparentBackground() && !mIsHeadsUp && !mOnKeyguard;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 02e8f49..ac55930 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -45,7 +45,11 @@
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FeedbackIcon;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactory;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
+import com.android.systemui.statusbar.notification.collection.PipelineEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -56,6 +60,7 @@
 import com.android.systemui.statusbar.notification.row.dagger.AppName;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationKey;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -118,8 +123,8 @@
     private final IStatusBarService mStatusBarService;
     private final UiEventLogger mUiEventLogger;
     private final MSDLPlayer mMSDLPlayer;
-
     private final NotificationSettingsController mSettingsController;
+    private final EntryAdapterFactory mEntryAdapterFactory;
 
     @VisibleForTesting
     final NotificationSettingsController.Listener mSettingsListener =
@@ -285,7 +290,8 @@
             IStatusBarService statusBarService,
             UiEventLogger uiEventLogger,
             MSDLPlayer msdlPlayer,
-            NotificationRebindingTracker notificationRebindingTracker) {
+            NotificationRebindingTracker notificationRebindingTracker,
+            EntryAdapterFactory entryAdapterFactory) {
         mView = view;
         mListContainer = listContainer;
         mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
@@ -322,14 +328,16 @@
         mStatusBarService = statusBarService;
         mUiEventLogger = uiEventLogger;
         mMSDLPlayer = msdlPlayer;
+        mEntryAdapterFactory = entryAdapterFactory;
     }
 
     /**
      * Initialize the controller.
      */
-    public void init(NotificationEntry entry) {
+    public void init(PipelineEntry entry) {
         mActivatableNotificationViewController.init();
         mView.initialize(
+                mEntryAdapterFactory.create(entry),
                 entry,
                 mRemoteInputViewSubcomponentFactory,
                 mAppName,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
index 7713580..d02f636 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
@@ -42,14 +42,6 @@
 
     private val buttonShape = Path()
     // Color and style
-    private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
-        val bgColor =
-            context.getColor(
-                com.android.internal.R.color.materialColorPrimaryContainer
-            )
-        color = bgColor
-        style = Paint.Style.FILL
-    }
     private val outlinePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
         val outlineColor =
             context.getColor(
@@ -99,7 +91,6 @@
         canvas.save()
         // Draw background
         canvas.clipPath(buttonShape)
-        canvas.drawPath(buttonShape, bgPaint)
         // Apply gradient to outline
         canvas.drawPath(buttonShape, outlinePaint)
         updateGradient(boundsF)
@@ -128,13 +119,11 @@
     }
 
     override fun setAlpha(alpha: Int) {
-        bgPaint.alpha = alpha
         outlinePaint.alpha = alpha
         invalidateSelf()
     }
 
     override fun setColorFilter(colorFilter: ColorFilter?) {
-        bgPaint.colorFilter = colorFilter
         outlinePaint.colorFilter = colorFilter
         invalidateSelf()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index e1219e8..4914e10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -39,7 +39,6 @@
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Dumpable;
-import com.android.systemui.common.shared.colors.SurfaceEffectColors;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss;
 import com.android.systemui.util.DrawableDumpKt;
@@ -156,14 +155,6 @@
         mBgIsColorized = b;
     }
 
-    /** Sets if the background should be opaque. */
-    public void setForceOpaque(boolean forceOpaque) {
-        mForceOpaque = forceOpaque;
-        if (notificationRowTransparency()) {
-            updateBaseLayerColor();
-        }
-    }
-
     private Path calculateDismissButtonCutoutPath(Rect backgroundBounds) {
         // TODO(b/365585705): Adapt to RTL after the UX design is finalized.
 
@@ -327,10 +318,7 @@
         // For colorized notifications, this uses a color that matches the tint color at 90% alpha.
         int color = isColorized()
                 ? ColorUtils.setAlphaComponent(mTintColor, (int) (MAX_ALPHA * 0.9f))
-                : SurfaceEffectColors.surfaceEffect1(getContext());
-        if (mForceOpaque) {
-            color = ColorUtils.setAlphaComponent(color, MAX_ALPHA);
-        }
+                : mNormalColor;
         getBaseBackgroundLayer().setColorFilter(
                 new PorterDuffColorFilter(
                         color,
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 daa598b..51569c1 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
@@ -57,7 +57,6 @@
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.NmSummarizationUiFlag;
 import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.notification.collection.EntryAdapter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor;
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded;
@@ -441,8 +440,12 @@
             NotificationRowContentBinderLogger logger) {
         return TraceUtils.trace("NotificationContentInflater.createRemoteViews", () -> {
             InflationProgress result = new InflationProgress();
+
+            // inflating the contracted view is the legacy invalidation trigger
+            boolean reinflating = (reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0;
             // create an image inflater
-            result.mRowImageInflater = RowImageInflater.newInstance(row.mImageModelIndex);
+            result.mRowImageInflater = RowImageInflater.newInstance(row.mImageModelIndex,
+                    reinflating);
 
             if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
                 logger.logAsyncTaskProgress(row.getLoggingKey(), "creating contracted remote view");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index 3586078..482b315 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -499,7 +499,10 @@
             logger.logAsyncTaskProgress(entry.logKey, "loading RON images")
             inflationProgress.rowImageInflater.loadImagesSynchronously(packageContext)
 
-            logger.logAsyncTaskProgress(entry.logKey, "getting row image resolver (on wrong thread!)")
+            logger.logAsyncTaskProgress(
+                entry.logKey,
+                "getting row image resolver (on wrong thread!)",
+            )
             val imageResolver = row.imageResolver
             // wait for image resolver to finish preloading
             logger.logAsyncTaskProgress(entry.logKey, "waiting for preloaded images")
@@ -685,13 +688,17 @@
             logger: NotificationRowContentBinderLogger,
         ): InflationProgress {
             val rowImageInflater =
-                RowImageInflater.newInstance(previousIndex = row.mImageModelIndex)
+                RowImageInflater.newInstance(
+                    previousIndex = row.mImageModelIndex,
+                    // inflating the contracted view is the legacy invalidation trigger
+                    reinflating = reInflateFlags and FLAG_CONTENT_VIEW_CONTRACTED != 0,
+                )
 
             val promotedContent =
                 if (PromotedNotificationContentModel.featureFlagEnabled()) {
                     logger.logAsyncTaskProgress(
                         entry.logKey,
-                        "extracting promoted notification content"
+                        "extracting promoted notification content",
                     )
                     val imageModelProvider = rowImageInflater.useForContentModel()
                     promotedNotificationContentExtractor
@@ -750,7 +757,7 @@
                 ) {
                     logger.logAsyncTaskProgress(
                         entry.logKey,
-                        "inflating public single line view model"
+                        "inflating public single line view model",
                     )
                     if (bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) {
                         SingleLineViewInflater.inflateSingleLineViewModel(
@@ -852,18 +859,12 @@
                     } else null
                 val expanded =
                     if (reInflateFlags and FLAG_CONTENT_VIEW_EXPANDED != 0) {
-                        logger.logAsyncTaskProgress(
-                            row.loggingKey,
-                            "creating expanded remote view",
-                        )
+                        logger.logAsyncTaskProgress(row.loggingKey, "creating expanded remote view")
                         createExpandedView(builder, bindParams.isMinimized)
                     } else null
                 val headsUp =
                     if (reInflateFlags and FLAG_CONTENT_VIEW_HEADS_UP != 0) {
-                        logger.logAsyncTaskProgress(
-                            row.loggingKey,
-                            "creating heads up remote view",
-                        )
+                        logger.logAsyncTaskProgress(row.loggingKey, "creating heads up remote view")
                         val isHeadsUpCompact = headsUpStyleProvider.shouldApplyCompactStyle()
                         if (isHeadsUpCompact) {
                             builder.createCompactHeadsUpContentView()
@@ -873,10 +874,7 @@
                     } else null
                 val public =
                     if (reInflateFlags and FLAG_CONTENT_VIEW_PUBLIC != 0) {
-                        logger.logAsyncTaskProgress(
-                            row.loggingKey,
-                            "creating public remote view"
-                        )
+                        logger.logAsyncTaskProgress(row.loggingKey, "creating public remote view")
                         if (
                             LockscreenOtpRedaction.isEnabled &&
                                 bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT
@@ -1142,7 +1140,7 @@
                             override fun setResultView(v: View) {
                                 logger.logAsyncTaskProgress(
                                     entry.logKey,
-                                    "group header view applied"
+                                    "group header view applied",
                                 )
                                 result.inflatedGroupHeaderView = v as NotificationHeaderView?
                             }
@@ -1198,7 +1196,7 @@
                         }
                     logger.logAsyncTaskProgress(
                         entry.logKey,
-                        "applying low priority group header view"
+                        "applying low priority group header view",
                     )
                     applyRemoteView(
                         inflationExecutor = inflationExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowImageInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowImageInflater.kt
index 95ef60f..7bac17f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowImageInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowImageInflater.kt
@@ -83,9 +83,9 @@
         inline fun featureFlagEnabled() = PromotedNotificationUiAod.isEnabled
 
         @JvmStatic
-        fun newInstance(previousIndex: ImageModelIndex?): RowImageInflater =
+        fun newInstance(previousIndex: ImageModelIndex?, reinflating: Boolean): RowImageInflater =
             if (featureFlagEnabled()) {
-                RowImageInflaterImpl(previousIndex)
+                RowImageInflaterImpl(previousIndex, reinflating)
             } else {
                 RowImageInflaterStub
             }
@@ -110,7 +110,8 @@
     override fun getNewImageIndex(): ImageModelIndex? = null
 }
 
-class RowImageInflaterImpl(private val previousIndex: ImageModelIndex?) : RowImageInflater {
+class RowImageInflaterImpl(private val previousIndex: ImageModelIndex?, val reinflating: Boolean) :
+    RowImageInflater {
     private val providedImages = mutableListOf<LazyImage>()
 
     /**
@@ -139,10 +140,15 @@
                     // ensure all entries are stored
                     providedImages.add(newImage)
                     // load the image result from the index into our new object
-                    previousIndex?.findImage(iconData, sizeClass, transform)?.let {
-                        // copy the result into our new object
-                        newImage.result = it
-                    }
+                    previousIndex
+                        // skip the cached image when we are "reinflating" to avoid stale content
+                        // being displayed from the same URI after the app updated the notif
+                        ?.takeUnless { reinflating }
+                        ?.findImage(iconData, sizeClass, transform)
+                        ?.let {
+                            // copy the result into our new object
+                            newImage.result = it
+                        }
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
index f00c3ae..d7dd7ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
@@ -17,7 +17,6 @@
 
 import android.app.PendingIntent
 import android.graphics.drawable.Icon
-import android.util.Log
 import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.stack.PriorityBucket
@@ -86,14 +85,6 @@
      */
     val promotedContent: PromotedNotificationContentModel?,
 ) : ActiveNotificationEntryModel() {
-    init {
-        if (!PromotedNotificationContentModel.featureFlagEnabled()) {
-            if (promotedContent != null) {
-                Log.wtf(TAG, "passing non-null promoted content without feature flag enabled")
-            }
-        }
-    }
-
     companion object {
         private const val TAG = "ActiveNotificationEntryModel"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationBundleUi.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationBundleUi.kt
index 11c942c..37212a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationBundleUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationBundleUi.kt
@@ -49,7 +49,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
@@ -57,4 +59,4 @@
      */
     @JvmStatic
     inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
-}
\ No newline at end of file
+}
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 e830d18..315d37e 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
@@ -39,9 +39,11 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.compose.ui.platform.ComposeView;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.NotificationExpandButton;
+import com.android.systemui.notifications.ui.composable.row.BundleHeaderKt;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.statusbar.CrossFadeHelper;
@@ -58,6 +60,7 @@
 import com.android.systemui.statusbar.notification.row.HybridNotificationView;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModelImpl;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
@@ -119,6 +122,13 @@
      */
     private boolean mEnableShadowOnChildNotifications;
 
+    /**
+     * This view is only set when this NCC is a bundle. If this view is set, all other header
+     * view variants have to be null.
+     */
+    private ComposeView mBundleHeaderView;
+    private BundleHeaderViewModelImpl mBundleHeaderViewModel;
+
     private NotificationHeaderView mGroupHeader;
     private NotificationHeaderViewWrapper mGroupHeaderWrapper;
     private NotificationHeaderView mMinimizedGroupHeader;
@@ -189,6 +199,9 @@
                     R.dimen.notification_children_container_top_padding);
             mHeaderHeight = mCollapsedHeaderMargin + mAdditionalExpandedHeaderMargin;
         }
+        if (mBundleHeaderView != null) {
+            initBundleDimens();
+        }
         mCollapsedBottomPadding = res.getDimensionPixelOffset(
                 R.dimen.notification_children_collapsed_bottom_padding);
         mEnableShadowOnChildNotifications =
@@ -244,6 +257,10 @@
                     mMinimizedGroupHeader.getMeasuredWidth(),
                     mMinimizedGroupHeader.getMeasuredHeight());
         }
+        if (mBundleHeaderView != null) {
+            mBundleHeaderView.layout(0, 0, mBundleHeaderView.getMeasuredWidth(),
+                    mBundleHeaderView.getMeasuredHeight());
+        }
     }
 
     @Override
@@ -295,6 +312,9 @@
         if (mMinimizedGroupHeader != null) {
             mMinimizedGroupHeader.measure(widthMeasureSpec, headerHeightSpec);
         }
+        if (mBundleHeaderView != null) {
+            mBundleHeaderView.measure(widthMeasureSpec, headerHeightSpec);
+        }
 
         setMeasuredDimension(width, height);
         Trace.endSection();
@@ -489,6 +509,28 @@
     }
 
     /**
+     * Init the bundle header view. The ComposeView is initialized within with the passed viewModel.
+     * This can only be init once and not in conjunction with any other header view.
+     */
+    public void initBundleHeader(@NonNull BundleHeaderViewModelImpl viewModel) {
+        if (NotificationBundleUi.isUnexpectedlyInLegacyMode()) return;
+        if (mBundleHeaderView != null) return;
+        initBundleDimens();
+
+        mBundleHeaderViewModel = viewModel;
+        mBundleHeaderView = BundleHeaderKt.createComposeView(mBundleHeaderViewModel, getContext());
+        addView(mBundleHeaderView);
+        invalidate();
+    }
+
+    private void initBundleDimens() {
+        NotificationBundleUi.unsafeAssertInNewMode();
+        mCollapsedHeaderMargin = mHeaderHeight;
+        mAdditionalExpandedHeaderMargin = 0;
+        mCollapsedBottomPadding = 0;
+    }
+
+    /**
      * Set the group header view
      * @param headerView view to set
      * @param onClickListener OnClickListener of the header view
@@ -1311,6 +1353,17 @@
                 mGroupHeader.setHeaderBackgroundDrawable(null);
             }
         }
+        if (mBundleHeaderView != null) {
+            if (expanded) {
+                ColorDrawable cd = new ColorDrawable();
+                cd.setColor(mContainingNotification.calculateBgColor());
+                // TODO(b/389839492): The backgroundDrawable needs an outline like in the original:
+                //  setOutlineProvider(mProvider);
+                mBundleHeaderViewModel.setBackgroundDrawable(cd);
+            } else {
+                mBundleHeaderViewModel.setBackgroundDrawable(null);
+            }
+        }
     }
 
     public int getMaxContentHeight() {
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 531baa8d..c2c271b 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
@@ -1290,7 +1290,9 @@
     @Override
     public void setHeadsUpBottom(float headsUpBottom) {
         if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
-        if (mAmbientState.getHeadsUpBottom() != headsUpBottom) {
+        if (NotificationsHunSharedAnimationValues.isEnabled()) {
+            mHeadsUpAnimator.setHeadsUpAppearHeightBottom(Math.round(headsUpBottom));
+        } else if (mAmbientState.getHeadsUpBottom() != headsUpBottom) {
             mAmbientState.setHeadsUpBottom(headsUpBottom);
             mStateAnimator.setHeadsUpAppearHeightBottom(Math.round(headsUpBottom));
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index a277597..c1aa5f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -266,7 +266,7 @@
         combine(shadeModeInteractor.shadeMode, shadeInteractor.qsExpansion) { shadeMode, qsExpansion
                 ->
                 when (shadeMode) {
-                    is ShadeMode.Dual -> false
+                    is ShadeMode.Dual,
                     is ShadeMode.Split -> true
                     is ShadeMode.Single -> qsExpansion < 0.5f
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 9aa4c54..e4e56c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -58,10 +58,10 @@
 import com.android.systemui.keyguard.shared.model.TransitionState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.log.SessionTracker;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.shared.model.Scenes;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
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 face1c7..a4ee4ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -109,6 +109,7 @@
 import com.android.systemui.CoreStartable;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.Flags;
 import com.android.systemui.InitController;
 import com.android.systemui.Prefs;
 import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
@@ -139,6 +140,7 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.views.NavigationBarView;
 import com.android.systemui.notetask.NoteTaskController;
@@ -190,7 +192,6 @@
 import com.android.systemui.statusbar.LightRevealScrim;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -3183,12 +3184,27 @@
             new ActivityTransitionAnimator.Listener() {
                 @Override
                 public void onTransitionAnimationStart() {
-                    mKeyguardViewMediator.setBlursDisabledForAppLaunch(true);
+                    if (!Flags.notificationShadeBlur() || !Flags.moveTransitionAnimationLayer()) {
+                        mKeyguardViewMediator.setBlursDisabledForAppLaunch(true);
+                    }
+                }
+
+                @Override
+                public void onTransitionAnimationProgress(float linearProgress) {
+                    if (Flags.notificationShadeBlur() && Flags.moveTransitionAnimationLayer()) {
+                        mNotificationShadeDepthControllerLazy.get()
+                                .onTransitionAnimationProgress(linearProgress);
+                    }
                 }
 
                 @Override
                 public void onTransitionAnimationEnd() {
-                    mKeyguardViewMediator.setBlursDisabledForAppLaunch(false);
+                    if (Flags.notificationShadeBlur() && Flags.moveTransitionAnimationLayer()) {
+                        mNotificationShadeDepthControllerLazy.get()
+                                .onTransitionAnimationEnd();
+                    } else {
+                        mKeyguardViewMediator.setBlursDisabledForAppLaunch(false);
+                    }
                 }
             };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 74b1c3b..2c8866f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -38,6 +38,7 @@
 import com.android.systemui.InitController;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
@@ -50,7 +51,6 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index b662892..61b7d80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -25,7 +25,6 @@
 import androidx.annotation.VisibleForTesting
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
-import com.android.systemui.Dumpable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
@@ -162,6 +161,10 @@
                 notificationKey = currentInfo.key,
                 appName = currentInfo.appName,
                 promotedContent = currentInfo.promotedContent,
+                // [hasOngoingCall()] filters out the case in which the call is ongoing but the app
+                // is visible (we issue [OngoingCallModel.NoCall] below in that case), so this can
+                // be safely made false.
+                isAppVisible = false,
             )
         } else {
             return OngoingCallModel.NoCall
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
index 6afcd8a..0ac8717 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
@@ -52,7 +52,9 @@
      * the flag is not enabled to ensure that the refactor author catches issues in testing.
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
index d6ca656..bed9e7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
@@ -51,9 +51,7 @@
  * This class monitors call notifications and the visibility of call apps to determine the
  * appropriate chip state. It emits:
  * * - [OngoingCallModel.NoCall] when there is no call notification
- * * - [OngoingCallModel.InCallWithVisibleApp] when there is a call notification but the call app is
- *   visible
- * * - [OngoingCallModel.InCall] when there is a call notification and the call app is not visible
+ * * - [OngoingCallModel.InCall] when there is a call notification
  */
 @SysUISingleton
 class OngoingCallInteractor
@@ -85,12 +83,14 @@
                 initialValue = OngoingCallModel.NoCall,
             )
 
+    // TODO(b/400720280): maybe put this inside [OngoingCallModel].
     @VisibleForTesting
     val isStatusBarRequiredForOngoingCall =
         combine(ongoingCallState, isChipSwipedAway) { callState, chipSwipedAway ->
-            callState is OngoingCallModel.InCall && !chipSwipedAway
+            callState.willCallChipBeVisible() && !chipSwipedAway
         }
 
+    // TODO(b/400720280): maybe put this inside [OngoingCallModel].
     @VisibleForTesting
     val isGestureListeningEnabled =
         combine(
@@ -98,9 +98,12 @@
             statusBarModeRepositoryStore.defaultDisplay.isInFullscreenMode,
             isChipSwipedAway,
         ) { callState, isFullscreen, chipSwipedAway ->
-            callState is OngoingCallModel.InCall && !chipSwipedAway && isFullscreen
+            callState.willCallChipBeVisible() && !chipSwipedAway && isFullscreen
         }
 
+    private fun OngoingCallModel.willCallChipBeVisible() =
+        this is OngoingCallModel.InCall && !isAppVisible
+
     private fun createOngoingCallStateFlow(
         notification: ActiveNotificationModel?
     ): Flow<OngoingCallModel> {
@@ -147,34 +150,23 @@
         model: ActiveNotificationModel,
         isVisible: Boolean,
     ): OngoingCallModel {
-        return when {
-            isVisible -> {
-                logger.d({ "Call app is visible: uid=$int1" }) { int1 = model.uid }
-                OngoingCallModel.InCallWithVisibleApp(
-                    startTimeMs = model.whenTime,
-                    notificationIconView = model.statusBarChipIconView,
-                    intent = model.contentIntent,
-                    notificationKey = model.key,
-                    appName = model.appName,
-                    promotedContent = model.promotedContent,
-                )
-            }
-
-            else -> {
-                logger.d({ "Active call detected: startTime=$long1 hasIcon=$bool1" }) {
-                    long1 = model.whenTime
-                    bool1 = model.statusBarChipIconView != null
-                }
-                OngoingCallModel.InCall(
-                    startTimeMs = model.whenTime,
-                    notificationIconView = model.statusBarChipIconView,
-                    intent = model.contentIntent,
-                    notificationKey = model.key,
-                    appName = model.appName,
-                    promotedContent = model.promotedContent,
-                )
-            }
+        logger.d({
+            "Active call detected: uid=$int1 startTime=$long1 hasIcon=$bool1 isAppVisible=$bool2"
+        }) {
+            int1 = model.uid
+            long1 = model.whenTime
+            bool1 = model.statusBarChipIconView != null
+            bool2 = isVisible
         }
+        return OngoingCallModel.InCall(
+            startTimeMs = model.whenTime,
+            notificationIconView = model.statusBarChipIconView,
+            intent = model.contentIntent,
+            notificationKey = model.key,
+            appName = model.appName,
+            promotedContent = model.promotedContent,
+            isAppVisible = isVisible,
+        )
     }
 
     private fun setStatusBarRequiredForOngoingCall(statusBarRequired: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
index 62f0ba0..322dfff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
@@ -26,25 +26,6 @@
     data object NoCall : OngoingCallModel
 
     /**
-     * There is an ongoing call but the call app is currently visible, so we don't need to show the
-     * chip.
-     *
-     * @property startTimeMs see [InCall.startTimeMs].
-     * @property notificationIconView see [InCall.notificationIconView].
-     * @property intent see [InCall.intent].
-     * @property appName see [InCall.appName].
-     * @property promotedContent see [InCall.promotedContent].
-     */
-    data class InCallWithVisibleApp(
-        val startTimeMs: Long,
-        val notificationIconView: StatusBarIconView?,
-        val intent: PendingIntent?,
-        val notificationKey: String,
-        val appName: String,
-        val promotedContent: PromotedNotificationContentModel?,
-    ) : OngoingCallModel
-
-    /**
      * There *is* an ongoing call.
      *
      * @property startTimeMs the time that the phone call started, based on the notification's
@@ -58,6 +39,7 @@
      * @property appName the user-readable name of the app that posted the call notification.
      * @property promotedContent if the call notification also meets promoted notification criteria,
      *   this field is filled in with the content related to promotion. Otherwise null.
+     * @property isAppVisible whether the app to which the call belongs is currently visible.
      */
     data class InCall(
         val startTimeMs: Long,
@@ -66,5 +48,6 @@
         val notificationKey: String,
         val appName: String,
         val promotedContent: PromotedNotificationContentModel?,
+        val isAppVisible: Boolean,
     ) : OngoingCallModel
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
index d53cbab..342adc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
@@ -65,12 +65,12 @@
      */
     val batteryAttributionType =
         combine(isCharging, powerSave, isBatteryDefenderEnabled) { charging, powerSave, defend ->
-            if (charging) {
-                BatteryAttributionModel.Charging
-            } else if (powerSave) {
+            if (powerSave) {
                 BatteryAttributionModel.PowerSave
             } else if (defend) {
                 BatteryAttributionModel.Defend
+            } else if (charging) {
+                BatteryAttributionModel.Charging
             } else {
                 null
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 2952850..db1977b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -45,6 +45,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryKairosImpl
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorKairosAdapter
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorKairosImpl
 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
@@ -92,8 +93,10 @@
             DemoModeMobileConnectionDataSourceKairosImpl.Module::class,
             MobileRepositorySwitcherKairos.Module::class,
             MobileConnectionsRepositoryKairosImpl.Module::class,
+            MobileIconsInteractorKairosImpl.Module::class,
             MobileConnectionRepositoryKairosFactoryImpl.Module::class,
             MobileConnectionsRepositoryKairosAdapter.Module::class,
+            MobileIconsInteractorKairosAdapter.Module::class,
         ]
 )
 abstract class StatusBarPipelineModule {
@@ -171,7 +174,7 @@
         @Provides
         fun mobileIconsInteractor(
             impl: Provider<MobileIconsInteractorImpl>,
-            kairosImpl: Provider<MobileIconsInteractorKairosImpl>,
+            kairosImpl: Provider<MobileIconsInteractorKairosAdapter>,
         ): MobileIconsInteractor {
             return if (Flags.statusBarMobileIconKairos()) {
                 kairosImpl.get()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/shared/StatusBarSignalPolicyRefactorEthernet.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/shared/StatusBarSignalPolicyRefactorEthernet.kt
index 1d1cfd6..b2d314c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/shared/StatusBarSignalPolicyRefactorEthernet.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/shared/StatusBarSignalPolicyRefactorEthernet.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 2efc057..d6105c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -192,20 +192,16 @@
     override val isDeviceEmergencyCallCapable: StateFlow<Boolean> =
         serviceStateChangedEvent
             .mapLatest {
-                val modems = telephonyManager.activeModemCount
-
-                // Assume false for automotive devices which don't have the calling feature.
-                // TODO: b/398045526 to revisit the below.
-                val isAutomotive: Boolean =
-                    context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
-                val hasFeatureCalling: Boolean =
+                // TODO(b/400460777): check for hasSystemFeature only once
+                val hasRadioAccess: Boolean =
                     context.packageManager.hasSystemFeature(
-                        PackageManager.FEATURE_TELEPHONY_CALLING
+                        PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS
                     )
-                if (isAutomotive && !hasFeatureCalling) {
+                if (!hasRadioAccess) {
                     return@mapLatest false
                 }
 
+                val modems = telephonyManager.activeModemCount
                 // Check the service state for every modem. If any state reports emergency calling
                 // capable, then consider the device to have emergency call capabilities
                 (0..<modems)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairos.kt
index 4580ad9..a939959 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairos.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairos.kt
@@ -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.
@@ -22,38 +22,37 @@
 import com.android.settingslib.graph.SignalDrawable
 import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
 import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
-import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.KairosBuilder
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.flatMap
+import com.android.systemui.kairos.map
+import com.android.systemui.kairosBuilder
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel.DefaultIcon
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel.OverriddenIcon
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
 import com.android.systemui.statusbar.pipeline.satellite.ui.model.SatelliteIconModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
 
+@ExperimentalKairosApi
 interface MobileIconInteractorKairos {
     /** The table log created for this connection */
     val tableLogBuffer: TableLogBuffer
 
     /** The current mobile data activity */
-    val activity: Flow<DataActivityModel>
+    val activity: State<DataActivityModel>
 
     /** See [MobileConnectionsRepository.mobileIsDefault]. */
-    val mobileIsDefault: Flow<Boolean>
+    val mobileIsDefault: State<Boolean>
 
     /**
      * True when telephony tells us that the data state is CONNECTED. See
@@ -61,31 +60,31 @@
      * consider this connection to be serving data, and thus want to show a network type icon, when
      * data is connected. Other data connection states would typically cause us not to show the icon
      */
-    val isDataConnected: StateFlow<Boolean>
+    val isDataConnected: State<Boolean>
 
     /** True if we consider this connection to be in service, i.e. can make calls */
-    val isInService: StateFlow<Boolean>
+    val isInService: State<Boolean>
 
     /** True if this connection is emergency only */
-    val isEmergencyOnly: StateFlow<Boolean>
+    val isEmergencyOnly: State<Boolean>
 
     /** Observable for the data enabled state of this connection */
-    val isDataEnabled: StateFlow<Boolean>
+    val isDataEnabled: State<Boolean>
 
     /** True if the RAT icon should always be displayed and false otherwise. */
-    val alwaysShowDataRatIcon: StateFlow<Boolean>
+    val alwaysShowDataRatIcon: State<Boolean>
 
     /** Canonical representation of the current mobile signal strength as a triangle. */
-    val signalLevelIcon: StateFlow<SignalIconModel>
+    val signalLevelIcon: State<SignalIconModel>
 
     /** Observable for RAT type (network type) indicator */
-    val networkTypeIconGroup: StateFlow<NetworkTypeIconModel>
+    val networkTypeIconGroup: State<NetworkTypeIconModel>
 
     /** Whether or not to show the slice attribution */
-    val showSliceAttribution: StateFlow<Boolean>
+    val showSliceAttribution: State<Boolean>
 
     /** True if this connection is satellite-based */
-    val isNonTerrestrial: StateFlow<Boolean>
+    val isNonTerrestrial: State<Boolean>
 
     /**
      * Provider name for this network connection. The name can be one of 3 values:
@@ -95,7 +94,7 @@
      *    override in [connectionInfo.operatorAlphaShort], a value that is derived from
      *    [ServiceState]
      */
-    val networkName: StateFlow<NetworkNameModel>
+    val networkName: State<NetworkNameModel>
 
     /**
      * Provider name for this network connection. The name can be one of 3 values:
@@ -108,119 +107,110 @@
      * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
      *   provided is identical
      */
-    val carrierName: StateFlow<String>
+    val carrierName: State<String>
 
     /** True if there is only one active subscription. */
-    val isSingleCarrier: StateFlow<Boolean>
+    val isSingleCarrier: State<Boolean>
 
     /**
      * True if this connection is considered roaming. The roaming bit can come from [ServiceState],
      * or directly from the telephony manager's CDMA ERI number value. Note that we don't consider a
      * connection to be roaming while carrier network change is active
      */
-    val isRoaming: StateFlow<Boolean>
+    val isRoaming: State<Boolean>
 
     /** See [MobileIconsInteractor.isForceHidden]. */
-    val isForceHidden: Flow<Boolean>
+    val isForceHidden: State<Boolean>
 
     /** See [MobileConnectionRepository.isAllowedDuringAirplaneMode]. */
-    val isAllowedDuringAirplaneMode: StateFlow<Boolean>
+    val isAllowedDuringAirplaneMode: State<Boolean>
 
     /** True when in carrier network change mode */
-    val carrierNetworkChangeActive: StateFlow<Boolean>
+    val carrierNetworkChangeActive: State<Boolean>
 }
 
 /** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@ExperimentalKairosApi
 class MobileIconInteractorKairosImpl(
-    @Background scope: CoroutineScope,
-    defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
-    override val alwaysShowDataRatIcon: StateFlow<Boolean>,
-    alwaysUseCdmaLevel: StateFlow<Boolean>,
-    override val isSingleCarrier: StateFlow<Boolean>,
-    override val mobileIsDefault: StateFlow<Boolean>,
-    defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
-    defaultMobileIconGroup: StateFlow<MobileIconGroup>,
-    isDefaultConnectionFailed: StateFlow<Boolean>,
-    override val isForceHidden: Flow<Boolean>,
-    connectionRepository: MobileConnectionRepository,
+    defaultSubscriptionHasDataEnabled: State<Boolean>,
+    override val alwaysShowDataRatIcon: State<Boolean>,
+    alwaysUseCdmaLevel: State<Boolean>,
+    override val isSingleCarrier: State<Boolean>,
+    override val mobileIsDefault: State<Boolean>,
+    defaultMobileIconMapping: State<Map<String, MobileIconGroup>>,
+    defaultMobileIconGroup: State<MobileIconGroup>,
+    isDefaultConnectionFailed: State<Boolean>,
+    override val isForceHidden: State<Boolean>,
+    private val connectionRepository: MobileConnectionRepositoryKairos,
     private val context: Context,
-    val carrierIdOverrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl(),
-) : MobileIconInteractor, MobileIconInteractorKairos {
-    override val tableLogBuffer: TableLogBuffer = connectionRepository.tableLogBuffer
+    private val carrierIdOverrides: MobileIconCarrierIdOverrides =
+        MobileIconCarrierIdOverridesImpl(),
+) : MobileIconInteractorKairos, KairosBuilder by kairosBuilder() {
+    override val tableLogBuffer: TableLogBuffer
+        get() = connectionRepository.tableLogBuffer
 
-    override val activity = connectionRepository.dataActivityDirection
+    override val activity: State<DataActivityModel>
+        get() = connectionRepository.dataActivityDirection
 
-    override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled
+    override val isDataEnabled: State<Boolean> = connectionRepository.dataEnabled
 
-    override val carrierNetworkChangeActive: StateFlow<Boolean> =
-        connectionRepository.carrierNetworkChangeActive
+    override val carrierNetworkChangeActive: State<Boolean>
+        get() = connectionRepository.carrierNetworkChangeActive
 
     // True if there exists _any_ icon override for this carrierId. Note that overrides can include
     // any or none of the icon groups defined in MobileMappings, so we still need to check on a
     // per-network-type basis whether or not the given icon group is overridden
-    private val carrierIdIconOverrideExists =
-        connectionRepository.carrierId
-            .map { carrierIdOverrides.carrierIdEntryExists(it) }
-            .distinctUntilChanged()
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+    private val carrierIdIconOverrideExists: State<Boolean> =
+        connectionRepository.carrierId.map { carrierIdOverrides.carrierIdEntryExists(it) }
 
-    override val networkName =
+    override val networkName: State<NetworkNameModel> =
         combine(connectionRepository.operatorAlphaShort, connectionRepository.networkName) {
-                operatorAlphaShort,
-                networkName ->
-                if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
-                    NetworkNameModel.IntentDerived(operatorAlphaShort)
-                } else {
-                    networkName
-                }
+            operatorAlphaShort,
+            networkName ->
+            if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+                NetworkNameModel.IntentDerived(operatorAlphaShort)
+            } else {
+                networkName
             }
-            .stateIn(
-                scope,
-                SharingStarted.WhileSubscribed(),
-                connectionRepository.networkName.value,
-            )
+        }
 
-    override val carrierName =
+    override val carrierName: State<String> =
         combine(connectionRepository.operatorAlphaShort, connectionRepository.carrierName) {
-                operatorAlphaShort,
-                networkName ->
-                if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
-                    operatorAlphaShort
-                } else {
-                    networkName.name
-                }
+            operatorAlphaShort,
+            networkName ->
+            if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+                operatorAlphaShort
+            } else {
+                networkName.name
             }
-            .stateIn(
-                scope,
-                SharingStarted.WhileSubscribed(),
-                connectionRepository.carrierName.value.name,
-            )
+        }
 
     /** What the mobile icon would be before carrierId overrides */
-    private val defaultNetworkType: StateFlow<MobileIconGroup> =
+    private val defaultNetworkType: State<MobileIconGroup> =
         combine(
-                connectionRepository.resolvedNetworkType,
-                defaultMobileIconMapping,
-                defaultMobileIconGroup,
-            ) { resolvedNetworkType, mapping, defaultGroup ->
-                when (resolvedNetworkType) {
-                    is ResolvedNetworkType.CarrierMergedNetworkType ->
-                        resolvedNetworkType.iconGroupOverride
-                    else -> {
-                        mapping[resolvedNetworkType.lookupKey] ?: defaultGroup
-                    }
+            connectionRepository.resolvedNetworkType,
+            defaultMobileIconMapping,
+            defaultMobileIconGroup,
+        ) { resolvedNetworkType, mapping, defaultGroup ->
+            when (resolvedNetworkType) {
+                is ResolvedNetworkType.CarrierMergedNetworkType ->
+                    resolvedNetworkType.iconGroupOverride
+
+                else -> {
+                    mapping[resolvedNetworkType.lookupKey] ?: defaultGroup
                 }
             }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
+        }
 
-    override val networkTypeIconGroup =
-        combine(defaultNetworkType, carrierIdIconOverrideExists) { networkType, overrideExists ->
+    override val networkTypeIconGroup: State<NetworkTypeIconModel> = buildState {
+        combineTransactionally(defaultNetworkType, carrierIdIconOverrideExists) {
+                networkType,
+                overrideExists ->
                 // DefaultIcon comes out of the icongroup lookup, we check for overrides here
                 if (overrideExists) {
                     val iconOverride =
                         carrierIdOverrides.getOverrideFor(
-                            connectionRepository.carrierId.value,
+                            connectionRepository.carrierId.sample(),
                             networkType.name,
                             context.resources,
                         )
@@ -233,106 +223,101 @@
                     DefaultIcon(networkType)
                 }
             }
-            .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLogBuffer = tableLogBuffer,
-                initialValue = DefaultIcon(defaultMobileIconGroup.value),
-            )
-            .stateIn(
-                scope,
-                SharingStarted.WhileSubscribed(),
-                DefaultIcon(defaultMobileIconGroup.value),
-            )
+            .also { logDiffsForTable(it, tableLogBuffer = tableLogBuffer) }
+    }
 
-    override val showSliceAttribution: StateFlow<Boolean> =
+    override val showSliceAttribution: State<Boolean> =
         combine(
-                connectionRepository.allowNetworkSliceIndicator,
-                connectionRepository.hasPrioritizedNetworkCapabilities,
-            ) { allowed, hasPrioritizedNetworkCapabilities ->
-                allowed && hasPrioritizedNetworkCapabilities
-            }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+            connectionRepository.allowNetworkSliceIndicator,
+            connectionRepository.hasPrioritizedNetworkCapabilities,
+        ) { allowed, hasPrioritizedNetworkCapabilities ->
+            allowed && hasPrioritizedNetworkCapabilities
+        }
 
-    override val isNonTerrestrial: StateFlow<Boolean> = connectionRepository.isNonTerrestrial
+    override val isNonTerrestrial: State<Boolean>
+        get() = connectionRepository.isNonTerrestrial
 
-    override val isRoaming: StateFlow<Boolean> =
+    override val isRoaming: State<Boolean> =
         combine(
-                connectionRepository.carrierNetworkChangeActive,
-                connectionRepository.isGsm,
-                connectionRepository.isRoaming,
-                connectionRepository.cdmaRoaming,
-            ) { carrierNetworkChangeActive, isGsm, isRoaming, cdmaRoaming ->
-                if (carrierNetworkChangeActive) {
-                    false
-                } else if (isGsm) {
-                    isRoaming
-                } else {
-                    cdmaRoaming
-                }
+            connectionRepository.carrierNetworkChangeActive,
+            connectionRepository.isGsm,
+            connectionRepository.isRoaming,
+            connectionRepository.cdmaRoaming,
+        ) { carrierNetworkChangeActive, isGsm, isRoaming, cdmaRoaming ->
+            if (carrierNetworkChangeActive) {
+                false
+            } else if (isGsm) {
+                isRoaming
+            } else {
+                cdmaRoaming
             }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+        }
 
-    private val level: StateFlow<Int> =
+    private val level: State<Int> =
         combine(
-                connectionRepository.isGsm,
-                connectionRepository.primaryLevel,
-                connectionRepository.cdmaLevel,
-                alwaysUseCdmaLevel,
-            ) { isGsm, primaryLevel, cdmaLevel, alwaysUseCdmaLevel ->
-                when {
-                    // GSM connections should never use the CDMA level
-                    isGsm -> primaryLevel
-                    alwaysUseCdmaLevel -> cdmaLevel
-                    else -> primaryLevel
-                }
+            connectionRepository.isGsm,
+            connectionRepository.primaryLevel,
+            connectionRepository.cdmaLevel,
+            alwaysUseCdmaLevel,
+        ) { isGsm, primaryLevel, cdmaLevel, alwaysUseCdmaLevel ->
+            when {
+                // GSM connections should never use the CDMA level
+                isGsm -> primaryLevel
+                alwaysUseCdmaLevel -> cdmaLevel
+                else -> primaryLevel
             }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+        }
 
-    private val numberOfLevels: StateFlow<Int> = connectionRepository.numberOfLevels
+    private val numberOfLevels: State<Int>
+        get() = connectionRepository.numberOfLevels
 
-    override val isDataConnected: StateFlow<Boolean> =
+    override val isDataConnected: State<Boolean> =
         connectionRepository.dataConnectionState
             .map { it == Connected }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, "icon", "isDataConnected") }
+            }
 
-    override val isInService = connectionRepository.isInService
+    override val isInService
+        get() = connectionRepository.isInService
 
-    override val isEmergencyOnly: StateFlow<Boolean> = connectionRepository.isEmergencyOnly
+    override val isEmergencyOnly: State<Boolean>
+        get() = connectionRepository.isEmergencyOnly
 
-    override val isAllowedDuringAirplaneMode = connectionRepository.isAllowedDuringAirplaneMode
+    override val isAllowedDuringAirplaneMode: State<Boolean>
+        get() = connectionRepository.isAllowedDuringAirplaneMode
 
     /** Whether or not to show the error state of [SignalDrawable] */
-    private val showExclamationMark: StateFlow<Boolean> =
+    private val showExclamationMark: State<Boolean> =
         combine(defaultSubscriptionHasDataEnabled, isDefaultConnectionFailed, isInService) {
-                isDefaultDataEnabled,
-                isDefaultConnectionFailed,
-                isInService ->
-                !isDefaultDataEnabled || isDefaultConnectionFailed || !isInService
-            }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), true)
+            isDefaultDataEnabled,
+            isDefaultConnectionFailed,
+            isInService ->
+            !isDefaultDataEnabled || isDefaultConnectionFailed || !isInService
+        }
 
-    private val cellularShownLevel: StateFlow<Int> =
+    private val cellularShownLevel: State<Int> =
         combine(level, isInService, connectionRepository.inflateSignalStrength) {
-                level,
-                isInService,
-                inflate ->
-                if (isInService) {
-                    if (inflate) level + 1 else level
-                } else 0
+            level,
+            isInService,
+            inflate ->
+            when {
+                !isInService -> 0
+                inflate -> level + 1
+                else -> level
             }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+        }
 
     // Satellite level is unaffected by the inflateSignalStrength property
     // See b/346904529 for details
-    private val satelliteShownLevel: StateFlow<Int> =
+    private val satelliteShownLevel: State<Int> =
         if (Flags.carrierRoamingNbIotNtn()) {
-                connectionRepository.satelliteLevel
-            } else {
-                combine(level, isInService) { level, isInService -> if (isInService) level else 0 }
-            }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+            connectionRepository.satelliteLevel
+        } else {
+            combine(level, isInService) { level, isInService -> if (isInService) level else 0 }
+        }
 
-    private val cellularIcon: Flow<SignalIconModel.Cellular> =
+    private val cellularIcon: State<SignalIconModel.Cellular> =
         combine(
             cellularShownLevel,
             numberOfLevels,
@@ -347,7 +332,7 @@
             )
         }
 
-    private val satelliteIcon: Flow<SignalIconModel.Satellite> =
+    private val satelliteIcon: State<SignalIconModel.Satellite> =
         satelliteShownLevel.map {
             SignalIconModel.Satellite(
                 level = it,
@@ -357,24 +342,14 @@
             )
         }
 
-    override val signalLevelIcon: StateFlow<SignalIconModel> = run {
-        val initial =
-            SignalIconModel.Cellular(
-                cellularShownLevel.value,
-                numberOfLevels.value,
-                showExclamationMark.value,
-                carrierNetworkChangeActive.value,
-            )
+    override val signalLevelIcon: State<SignalIconModel> =
         isNonTerrestrial
-            .flatMapLatest { ntn ->
+            .flatMap { ntn ->
                 if (ntn) {
                     satelliteIcon
                 } else {
                     cellularIcon
                 }
             }
-            .distinctUntilChanged()
-            .logDiffsForTable(tableLogBuffer, columnPrefix = "icon", initialValue = initial)
-            .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
-    }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnPrefix = "icon") } }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapter.kt
new file mode 100644
index 0000000..a3b9b17
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapter.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.pipeline.mobile.domain.interactor
+
+import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.toColdConflatedFlow
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+@ExperimentalKairosApi
+fun BuildScope.MobileIconInteractorKairosAdapter(
+    kairosImpl: MobileIconInteractorKairos
+): MobileIconInteractor =
+    with(kairosImpl) {
+        MobileIconInteractorKairosAdapter(
+            tableLogBuffer = tableLogBuffer,
+            activity = activity.toColdConflatedFlow(kairosNetwork),
+            mobileIsDefault = mobileIsDefault.toColdConflatedFlow(kairosNetwork),
+            isDataConnected = isDataConnected.toStateFlow(),
+            isInService = isInService.toStateFlow(),
+            isEmergencyOnly = isEmergencyOnly.toStateFlow(),
+            isDataEnabled = isDataEnabled.toStateFlow(),
+            alwaysShowDataRatIcon = alwaysShowDataRatIcon.toStateFlow(),
+            signalLevelIcon = signalLevelIcon.toStateFlow(),
+            networkTypeIconGroup = networkTypeIconGroup.toStateFlow(),
+            showSliceAttribution = showSliceAttribution.toStateFlow(),
+            isNonTerrestrial = isNonTerrestrial.toStateFlow(),
+            networkName = networkName.toStateFlow(),
+            carrierName = carrierName.toStateFlow(),
+            isSingleCarrier = isSingleCarrier.toStateFlow(),
+            isRoaming = isRoaming.toStateFlow(),
+            isForceHidden = isForceHidden.toColdConflatedFlow(kairosNetwork),
+            isAllowedDuringAirplaneMode = isAllowedDuringAirplaneMode.toStateFlow(),
+            carrierNetworkChangeActive = carrierNetworkChangeActive.toStateFlow(),
+        )
+    }
+
+private class MobileIconInteractorKairosAdapter(
+    override val tableLogBuffer: TableLogBuffer,
+    override val activity: Flow<DataActivityModel>,
+    override val mobileIsDefault: Flow<Boolean>,
+    override val isDataConnected: StateFlow<Boolean>,
+    override val isInService: StateFlow<Boolean>,
+    override val isEmergencyOnly: StateFlow<Boolean>,
+    override val isDataEnabled: StateFlow<Boolean>,
+    override val alwaysShowDataRatIcon: StateFlow<Boolean>,
+    override val signalLevelIcon: StateFlow<SignalIconModel>,
+    override val networkTypeIconGroup: StateFlow<NetworkTypeIconModel>,
+    override val showSliceAttribution: StateFlow<Boolean>,
+    override val isNonTerrestrial: StateFlow<Boolean>,
+    override val networkName: StateFlow<NetworkNameModel>,
+    override val carrierName: StateFlow<String>,
+    override val isSingleCarrier: StateFlow<Boolean>,
+    override val isRoaming: StateFlow<Boolean>,
+    override val isForceHidden: Flow<Boolean>,
+    override val isAllowedDuringAirplaneMode: StateFlow<Boolean>,
+    override val carrierNetworkChangeActive: StateFlow<Boolean>,
+) : MobileIconInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairos.kt
index e8e0a83..14a276b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairos.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairos.kt
@@ -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.
@@ -21,41 +21,47 @@
 import android.telephony.SubscriptionManager
 import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
 import com.android.settingslib.SignalIcon.MobileIconGroup
-import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.Flags
+import com.android.systemui.KairosActivatable
+import com.android.systemui.KairosBuilder
+import com.android.systemui.activated
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS
+import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.Incremental
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.asyncEvent
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.filter
+import com.android.systemui.kairos.flatMap
+import com.android.systemui.kairos.flatten
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapValues
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kairosBuilder
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
 import com.android.systemui.statusbar.core.NewStatusBarIcons
 import com.android.systemui.statusbar.core.StatusBarRootModernization
 import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
 import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
 import com.android.systemui.util.CarrierConfigTracker
-import java.lang.ref.WeakReference
+import dagger.Binds
+import dagger.Provides
+import dagger.multibindings.ElementsIntoSet
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import javax.inject.Provider
+import kotlin.time.Duration.Companion.seconds
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.mapLatest
-import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.flow.transformLatest
 
 /**
  * Business layer logic for the set of mobile subscription icons.
@@ -67,98 +73,79 @@
  * represents each RAT (LTE, 3G, etc.), as well as can produce an interactor for each individual
  * icon
  */
+@ExperimentalKairosApi
 interface MobileIconsInteractorKairos {
     /** See [MobileConnectionsRepository.mobileIsDefault]. */
-    val mobileIsDefault: StateFlow<Boolean>
+    val mobileIsDefault: State<Boolean>
 
     /** List of subscriptions, potentially filtered for CBRS */
-    val filteredSubscriptions: Flow<List<SubscriptionModel>>
-
-    /** Subscription ID of the current default data subscription */
-    val defaultDataSubId: Flow<Int?>
+    val filteredSubscriptions: State<List<SubscriptionModel>>
 
     /**
      * The current list of [MobileIconInteractor]s associated with the current list of
      * [filteredSubscriptions]
      */
-    val icons: StateFlow<List<MobileIconInteractor>>
+    val icons: Incremental<Int, MobileIconInteractorKairos>
 
     /** Whether the mobile icons can be stacked vertically. */
-    val isStackable: StateFlow<Boolean>
-
-    /**
-     * Observable for the subscriptionId of the current mobile data connection. Null if we don't
-     * have a valid subscription id
-     */
-    val activeMobileDataSubscriptionId: StateFlow<Int?>
+    val isStackable: State<Boolean>
 
     /** True if the active mobile data subscription has data enabled */
-    val activeDataConnectionHasDataEnabled: StateFlow<Boolean>
+    val activeDataConnectionHasDataEnabled: State<Boolean>
 
     /**
      * Flow providing a reference to the Interactor for the active data subId. This represents the
-     * [MobileIconInteractor] responsible for the active data connection, if any.
+     * [MobileIconInteractorKairos] responsible for the active data connection, if any.
      */
-    val activeDataIconInteractor: StateFlow<MobileIconInteractor?>
+    val activeDataIconInteractor: State<MobileIconInteractorKairos?>
 
     /** True if the RAT icon should always be displayed and false otherwise. */
-    val alwaysShowDataRatIcon: StateFlow<Boolean>
+    val alwaysShowDataRatIcon: State<Boolean>
 
     /** True if the CDMA level should be preferred over the primary level. */
-    val alwaysUseCdmaLevel: StateFlow<Boolean>
+    val alwaysUseCdmaLevel: State<Boolean>
 
     /** True if there is only one active subscription. */
-    val isSingleCarrier: StateFlow<Boolean>
+    val isSingleCarrier: State<Boolean>
 
     /** The icon mapping from network type to [MobileIconGroup] for the default subscription */
-    val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
+    val defaultMobileIconMapping: State<Map<String, MobileIconGroup>>
 
     /** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
-    val defaultMobileIconGroup: StateFlow<MobileIconGroup>
+    val defaultMobileIconGroup: State<MobileIconGroup>
 
     /** True only if the default network is mobile, and validation also failed */
-    val isDefaultConnectionFailed: StateFlow<Boolean>
+    val isDefaultConnectionFailed: State<Boolean>
 
     /** True once the user has been set up */
-    val isUserSetUp: StateFlow<Boolean>
+    val isUserSetUp: State<Boolean>
 
     /** True if we're configured to force-hide the mobile icons and false otherwise. */
-    val isForceHidden: Flow<Boolean>
+    val isForceHidden: State<Boolean>
 
     /**
      * True if the device-level service state (with -1 subscription id) reports emergency calls
      * only. This value is only useful when there are no other subscriptions OR all existing
      * subscriptions report that they are not in service.
      */
-    val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean>
-
-    /**
-     * Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given
-     * subId.
-     */
-    fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor
+    val isDeviceInEmergencyCallsOnlyMode: State<Boolean>
 }
 
-@OptIn(ExperimentalCoroutinesApi::class)
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@ExperimentalKairosApi
 @SysUISingleton
 class MobileIconsInteractorKairosImpl
 @Inject
 constructor(
-    private val mobileConnectionsRepo: MobileConnectionsRepository,
+    private val mobileConnectionsRepo: MobileConnectionsRepositoryKairos,
     private val carrierConfigTracker: CarrierConfigTracker,
     @MobileSummaryLog private val tableLogger: TableLogBuffer,
     connectivityRepository: ConnectivityRepository,
     userSetupRepo: UserSetupRepository,
-    @Background private val scope: CoroutineScope,
     private val context: Context,
     private val featureFlagsClassic: FeatureFlagsClassic,
-) : MobileIconsInteractor, MobileIconsInteractorKairos {
+) : MobileIconsInteractorKairos, KairosBuilder by kairosBuilder() {
 
-    // Weak reference lookup for created interactors
-    private val reuseCache = mutableMapOf<Int, WeakReference<MobileIconInteractor>>()
-
-    override val mobileIsDefault =
+    override val mobileIsDefault: State<Boolean> =
         combine(
                 mobileConnectionsRepo.mobileIsDefault,
                 mobileConnectionsRepo.hasCarrierMergedConnection,
@@ -167,47 +154,36 @@
                 // the `isDefault` calculation. See b/272586234.
                 mobileIsDefault || hasCarrierMergedConnection
             }
-            .logDiffsForTable(
-                tableLogger,
-                LOGGING_PREFIX,
-                columnName = "mobileIsDefault",
-                initialValue = false,
-            )
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
-
-    override val activeMobileDataSubscriptionId: StateFlow<Int?> =
-        mobileConnectionsRepo.activeMobileDataSubscriptionId
-
-    override val activeDataConnectionHasDataEnabled: StateFlow<Boolean> =
-        mobileConnectionsRepo.activeMobileDataRepository
-            .flatMapLatest { it?.dataEnabled ?: flowOf(false) }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
-
-    override val activeDataIconInteractor: StateFlow<MobileIconInteractor?> =
-        mobileConnectionsRepo.activeMobileDataSubscriptionId
-            .mapLatest {
-                if (it != null) {
-                    getMobileConnectionInteractorForSubId(it)
-                } else {
-                    null
+            .also {
+                onActivated {
+                    logDiffsForTable(
+                        it,
+                        tableLogger,
+                        LOGGING_PREFIX,
+                        columnName = "mobileIsDefault",
+                    )
                 }
             }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
 
-    private val unfilteredSubscriptions: Flow<List<SubscriptionModel>> =
-        mobileConnectionsRepo.subscriptions
+    override val activeDataConnectionHasDataEnabled: State<Boolean> =
+        mobileConnectionsRepo.activeMobileDataRepository.flatMap {
+            it?.dataEnabled ?: stateOf(false)
+        }
+
+    private val unfilteredSubscriptions: State<Collection<SubscriptionModel>>
+        get() = mobileConnectionsRepo.subscriptions
 
     /** Any filtering that we can do based purely on the info of each subscription individually. */
-    private val subscriptionsBasedFilteredSubs =
-        unfilteredSubscriptions
-            .map { it.filterBasedOnProvisioning().filterBasedOnNtn() }
-            .distinctUntilChanged()
+    private val subscriptionsBasedFilteredSubs: State<List<SubscriptionModel>> =
+        unfilteredSubscriptions.map {
+            it.asSequence().filterBasedOnProvisioning().filterBasedOnNtn().toList()
+        }
 
-    private fun List<SubscriptionModel>.filterBasedOnProvisioning(): List<SubscriptionModel> =
+    private fun Sequence<SubscriptionModel>.filterBasedOnProvisioning() =
         if (!featureFlagsClassic.isEnabled(FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS)) {
             this
         } else {
-            this.filter { it.profileClass != PROFILE_CLASS_PROVISIONING }
+            filter { it.profileClass != PROFILE_CLASS_PROVISIONING }
         }
 
     /**
@@ -219,9 +195,10 @@
      * need to filter out those subscriptions here so we guarantee the subscription never turns into
      * an icon. See b/336881301.
      */
-    private fun List<SubscriptionModel>.filterBasedOnNtn(): List<SubscriptionModel> {
-        return this.filter { !it.isExclusivelyNonTerrestrial }
-    }
+    private fun Sequence<SubscriptionModel>.filterBasedOnNtn(): Sequence<SubscriptionModel> =
+        filter {
+            !it.isExclusivelyNonTerrestrial
+        }
 
     /**
      * Generally, SystemUI wants to show iconography for each subscription that is listed by
@@ -236,22 +213,23 @@
      * [CarrierConfigManager.KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN],
      * and by checking which subscription is opportunistic, or which one is active.
      */
-    override val filteredSubscriptions: Flow<List<SubscriptionModel>> =
+    override val filteredSubscriptions: State<List<SubscriptionModel>> = buildState {
         combine(
                 subscriptionsBasedFilteredSubs,
                 mobileConnectionsRepo.activeMobileDataSubscriptionId,
-                connectivityRepository.vcnSubId,
+                connectivityRepository.vcnSubId.toState(),
             ) { preFilteredSubs, activeId, vcnSubId ->
                 filterSubsBasedOnOpportunistic(preFilteredSubs, activeId, vcnSubId)
             }
-            .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLogger,
-                LOGGING_PREFIX,
-                columnName = "filteredSubscriptions",
-                initialValue = listOf(),
-            )
-            .stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
+            .also {
+                logDiffsForTable(
+                    it,
+                    tableLogger,
+                    LOGGING_PREFIX,
+                    columnName = "filteredSubscriptions",
+                )
+            }
+    }
 
     private fun filterSubsBasedOnOpportunistic(
         subList: List<SubscriptionModel>,
@@ -298,19 +276,25 @@
         }
     }
 
-    override val defaultDataSubId = mobileConnectionsRepo.defaultDataSubId
-
-    override val icons =
-        filteredSubscriptions
-            .mapLatest { subs ->
-                subs.map { getMobileConnectionInteractorForSubId(it.subscriptionId) }
+    override val icons: Incremental<Int, MobileIconInteractorKairos> = buildIncremental {
+        val filteredSubIds =
+            filteredSubscriptions.map { it.asSequence().map { sub -> sub.subscriptionId }.toSet() }
+        mobileConnectionsRepo.mobileConnectionsBySubId
+            .filterIncrementally { (subId, _) ->
+                // Filter out repo if subId is not present in the filtered set
+                filteredSubIds.map { subId in it }
             }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+            // Just map the repos to interactors
+            .mapValues { (subId, repo) -> buildSpec { mobileConnection(repo) } }
+            .applyLatestSpecForKey()
+    }
 
-    override val isStackable =
+    override val isStackable: State<Boolean> =
         if (NewStatusBarIcons.isEnabled && StatusBarRootModernization.isEnabled) {
-                icons.flatMapLatest { icons ->
-                    combine(icons.map { it.signalLevelIcon }) { signalLevelIcons ->
+            icons.flatMap { iconsBySubId: Map<Int, MobileIconInteractorKairos> ->
+                iconsBySubId.values
+                    .map { it.signalLevelIcon }
+                    .combine { signalLevelIcons ->
                         // These are only stackable if:
                         // - They are cellular
                         // - There's exactly two
@@ -319,11 +303,15 @@
                             it.size == 2 && it[0].numberOfLevels == it[1].numberOfLevels
                         }
                     }
-                }
-            } else {
-                flowOf(false)
             }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+        } else {
+            stateOf(false)
+        }
+
+    override val activeDataIconInteractor: State<MobileIconInteractorKairos?> =
+        combine(mobileConnectionsRepo.activeMobileDataSubscriptionId, icons) { activeSubId, icons ->
+            activeSubId?.let { icons[activeSubId] }
+        }
 
     /**
      * Copied from the old pipeline. We maintain a 2s period of time where we will keep the
@@ -335,67 +323,59 @@
      *
      * The goal of this is to minimize the flickering in the UI of the cellular indicator
      */
-    private val forcingCellularValidation =
+    private val forcingCellularValidation: State<Boolean> = buildState {
         mobileConnectionsRepo.activeSubChangedInGroupEvent
-            .filter { mobileConnectionsRepo.defaultConnectionIsValidated.value }
-            .transformLatest {
-                emit(true)
-                delay(2000)
-                emit(false)
+            .filter(mobileConnectionsRepo.defaultConnectionIsValidated)
+            .mapLatestBuild {
+                asyncEvent {
+                        delay(2.seconds)
+                        false
+                    }
+                    .holdState(true)
             }
-            .logDiffsForTable(
-                tableLogger,
-                LOGGING_PREFIX,
-                columnName = "forcingValidation",
-                initialValue = false,
-            )
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+            .holdState(stateOf(false))
+            .flatten()
+            .also {
+                logDiffsForTable(it, tableLogger, LOGGING_PREFIX, columnName = "forcingValidation")
+            }
+    }
 
     /**
      * Mapping from network type to [MobileIconGroup] using the config generated for the default
      * subscription Id. This mapping is the same for every subscription.
      */
-    override val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> =
-        mobileConnectionsRepo.defaultMobileIconMapping.stateIn(
-            scope,
-            SharingStarted.WhileSubscribed(),
-            initialValue = mapOf(),
-        )
+    override val defaultMobileIconMapping: State<Map<String, MobileIconGroup>>
+        get() = mobileConnectionsRepo.defaultMobileIconMapping
 
-    override val alwaysShowDataRatIcon: StateFlow<Boolean> =
-        mobileConnectionsRepo.defaultDataSubRatConfig
-            .mapLatest { it.alwaysShowDataRatIcon }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+    override val alwaysShowDataRatIcon: State<Boolean> =
+        mobileConnectionsRepo.defaultDataSubRatConfig.map { it.alwaysShowDataRatIcon }
 
-    override val alwaysUseCdmaLevel: StateFlow<Boolean> =
-        mobileConnectionsRepo.defaultDataSubRatConfig
-            .mapLatest { it.alwaysShowCdmaRssi }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+    override val alwaysUseCdmaLevel: State<Boolean> =
+        mobileConnectionsRepo.defaultDataSubRatConfig.map { it.alwaysShowCdmaRssi }
 
-    override val isSingleCarrier: StateFlow<Boolean> =
+    override val isSingleCarrier: State<Boolean> =
         mobileConnectionsRepo.subscriptions
             .map { it.size == 1 }
-            .logDiffsForTable(
-                tableLogger,
-                columnPrefix = LOGGING_PREFIX,
-                columnName = "isSingleCarrier",
-                initialValue = false,
-            )
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+            .also {
+                onActivated {
+                    logDiffsForTable(
+                        it,
+                        tableLogger,
+                        columnPrefix = LOGGING_PREFIX,
+                        columnName = "isSingleCarrier",
+                    )
+                }
+            }
 
     /** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
-    override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
-        mobileConnectionsRepo.defaultMobileIconGroup.stateIn(
-            scope,
-            SharingStarted.WhileSubscribed(),
-            initialValue = TelephonyIcons.G,
-        )
+    override val defaultMobileIconGroup: State<MobileIconGroup>
+        get() = mobileConnectionsRepo.defaultMobileIconGroup
 
     /**
      * We want to show an error state when cellular has actually failed to validate, but not if some
      * other transport type is active, because then we expect there not to be validation.
      */
-    override val isDefaultConnectionFailed: StateFlow<Boolean> =
+    override val isDefaultConnectionFailed: State<Boolean> =
         combine(
                 mobileIsDefault,
                 mobileConnectionsRepo.defaultConnectionIsValidated,
@@ -407,46 +387,63 @@
                     else -> !defaultConnectionIsValidated
                 }
             }
-            .logDiffsForTable(
-                tableLogger,
-                LOGGING_PREFIX,
-                columnName = "isDefaultConnectionFailed",
-                initialValue = false,
-            )
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+            .also {
+                onActivated {
+                    logDiffsForTable(
+                        it,
+                        tableLogger,
+                        LOGGING_PREFIX,
+                        columnName = "isDefaultConnectionFailed",
+                    )
+                }
+            }
 
-    override val isUserSetUp: StateFlow<Boolean> = userSetupRepo.isUserSetUp
+    override val isUserSetUp: State<Boolean> = buildState { userSetupRepo.isUserSetUp.toState() }
 
-    override val isForceHidden: Flow<Boolean> =
-        connectivityRepository.forceHiddenSlots
-            .map { it.contains(ConnectivitySlot.MOBILE) }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+    override val isForceHidden: State<Boolean> = buildState {
+        connectivityRepository.forceHiddenSlots.toState().map {
+            it.contains(ConnectivitySlot.MOBILE)
+        }
+    }
 
-    override val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean> =
-        mobileConnectionsRepo.isDeviceEmergencyCallCapable
+    override val isDeviceInEmergencyCallsOnlyMode: State<Boolean>
+        get() = mobileConnectionsRepo.isDeviceEmergencyCallCapable
 
-    /** Vends out new [MobileIconInteractor] for a particular subId */
-    override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
-        reuseCache[subId]?.get() ?: createMobileConnectionInteractorForSubId(subId)
-
-    private fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
-        MobileIconInteractorImpl(
-                scope,
-                activeDataConnectionHasDataEnabled,
-                alwaysShowDataRatIcon,
-                alwaysUseCdmaLevel,
-                isSingleCarrier,
-                mobileIsDefault,
-                defaultMobileIconMapping,
-                defaultMobileIconGroup,
-                isDefaultConnectionFailed,
-                isForceHidden,
-                mobileConnectionsRepo.getRepoForSubId(subId),
-                context,
-            )
-            .also { reuseCache[subId] = WeakReference(it) }
+    /** Vends out a new [MobileIconInteractorKairos] for a particular subId */
+    private fun BuildScope.mobileConnection(
+        repo: MobileConnectionRepositoryKairos
+    ): MobileIconInteractorKairos = activated {
+        MobileIconInteractorKairosImpl(
+            activeDataConnectionHasDataEnabled,
+            alwaysShowDataRatIcon,
+            alwaysUseCdmaLevel,
+            isSingleCarrier,
+            mobileIsDefault,
+            defaultMobileIconMapping,
+            defaultMobileIconGroup,
+            isDefaultConnectionFailed,
+            isForceHidden,
+            repo,
+            context,
+        )
+    }
 
     companion object {
         private const val LOGGING_PREFIX = "Intr"
     }
+
+    @dagger.Module
+    interface Module {
+
+        @Binds fun bindImpl(impl: MobileIconsInteractorKairosImpl): MobileIconsInteractorKairos
+
+        companion object {
+            @Provides
+            @ElementsIntoSet
+            fun kairosActivatable(
+                impl: Provider<MobileIconsInteractorKairosImpl>
+            ): Set<@JvmSuppressWildcards KairosActivatable> =
+                if (Flags.statusBarMobileIconKairos()) setOf(impl.get()) else emptySet()
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosAdapter.kt
new file mode 100644
index 0000000..87877b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosAdapter.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.pipeline.mobile.domain.interactor
+
+import android.content.Context
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.Flags
+import com.android.systemui.KairosActivatable
+import com.android.systemui.KairosBuilder
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosNetwork
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapValues
+import com.android.systemui.kairos.toColdConflatedFlow
+import com.android.systemui.kairosBuilder
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
+import dagger.Provides
+import dagger.multibindings.ElementsIntoSet
+import javax.inject.Inject
+import javax.inject.Provider
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+@ExperimentalKairosApi
+@SysUISingleton
+class MobileIconsInteractorKairosAdapter
+@Inject
+constructor(
+    private val kairosInteractor: MobileIconsInteractorKairos,
+    private val repo: MobileConnectionsRepository,
+    repoK: MobileConnectionsRepositoryKairos,
+    kairosNetwork: KairosNetwork,
+    @Application scope: CoroutineScope,
+    context: Context,
+    mobileMappingsProxy: MobileMappingsProxy,
+    private val userSetupRepo: UserSetupRepository,
+) : MobileIconsInteractor, KairosBuilder by kairosBuilder() {
+
+    private val interactorsBySubIdK = buildIncremental {
+        kairosInteractor.icons
+            .mapValues { (subId, interactor) ->
+                buildSpec { MobileIconInteractorKairosAdapter(interactor) }
+            }
+            .applyLatestSpecForKey()
+    }
+
+    private val interactorsBySubId =
+        interactorsBySubIdK
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.Eagerly, emptyMap())
+
+    override val defaultDataSubId: Flow<Int?>
+        get() = repo.defaultDataSubId
+
+    override val mobileIsDefault: StateFlow<Boolean> =
+        kairosInteractor.mobileIsDefault
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), repo.mobileIsDefault.value)
+
+    override val filteredSubscriptions: Flow<List<SubscriptionModel>> =
+        kairosInteractor.filteredSubscriptions.toColdConflatedFlow(kairosNetwork)
+
+    override val icons: StateFlow<List<MobileIconInteractor>> =
+        interactorsBySubIdK
+            .map { it.values.toList() }
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+
+    override val isStackable: StateFlow<Boolean> =
+        kairosInteractor.isStackable
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val activeMobileDataSubscriptionId: StateFlow<Int?>
+        get() = repo.activeMobileDataSubscriptionId
+
+    override val activeDataConnectionHasDataEnabled: StateFlow<Boolean> =
+        kairosInteractor.activeDataConnectionHasDataEnabled
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val activeDataIconInteractor: StateFlow<MobileIconInteractor?> =
+        combine(repoK.activeMobileDataSubscriptionId, interactorsBySubIdK) { subId, interactors ->
+                interactors[subId]
+            }
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val alwaysShowDataRatIcon: StateFlow<Boolean> =
+        kairosInteractor.alwaysShowDataRatIcon
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val alwaysUseCdmaLevel: StateFlow<Boolean> =
+        kairosInteractor.alwaysUseCdmaLevel
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isSingleCarrier: StateFlow<Boolean> =
+        kairosInteractor.isSingleCarrier
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val defaultMobileIconMapping: StateFlow<Map<String, SignalIcon.MobileIconGroup>> =
+        kairosInteractor.defaultMobileIconMapping
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), emptyMap())
+
+    override val defaultMobileIconGroup: StateFlow<SignalIcon.MobileIconGroup> =
+        kairosInteractor.defaultMobileIconGroup
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                mobileMappingsProxy.getDefaultIcons(MobileMappings.Config.readConfig(context)),
+            )
+
+    override val isDefaultConnectionFailed: StateFlow<Boolean> =
+        kairosInteractor.isDefaultConnectionFailed
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isUserSetUp: StateFlow<Boolean>
+        get() = userSetupRepo.isUserSetUp
+
+    override val isForceHidden: Flow<Boolean> =
+        kairosInteractor.isForceHidden
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean>
+        get() = repo.isDeviceEmergencyCallCapable
+
+    override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
+        interactorsBySubId.value[subId] ?: error("Unknown subscription id: $subId")
+
+    @dagger.Module
+    object Module {
+        @Provides
+        @ElementsIntoSet
+        fun kairosActivatable(
+            impl: Provider<MobileIconsInteractorKairosAdapter>
+        ): Set<@JvmSuppressWildcards KairosActivatable> =
+            if (Flags.statusBarMobileIconKairos()) setOf(impl.get()) else emptySet()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModelKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModelKairos.kt
new file mode 100644
index 0000000..fce8c85
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModelKairos.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This
+ * allows the mobile icon to change some view parameters at different locations
+ *
+ * @param commonImpl for convenience, this class wraps a base interface that can provides all of the
+ *   common implementations between locations. See [MobileIconViewModel]
+ * @property location the [StatusBarLocation] of this VM.
+ * @property verboseLogger an optional logger to log extremely verbose view updates.
+ */
+abstract class LocationBasedMobileViewModelKairos(
+    val commonImpl: MobileIconViewModelCommonKairos,
+    val location: StatusBarLocation,
+    val verboseLogger: VerboseMobileViewLogger?,
+) : MobileIconViewModelCommonKairos by commonImpl {
+    val defaultColor: Int = Color.WHITE
+
+    companion object {
+        fun viewModelForLocation(
+            commonImpl: MobileIconViewModelCommon,
+            interactor: MobileIconInteractor,
+            verboseMobileViewLogger: VerboseMobileViewLogger,
+            location: StatusBarLocation,
+            scope: CoroutineScope,
+        ): LocationBasedMobileViewModel =
+            when (location) {
+                StatusBarLocation.HOME ->
+                    HomeMobileIconViewModel(commonImpl, verboseMobileViewLogger)
+                StatusBarLocation.KEYGUARD -> KeyguardMobileIconViewModel(commonImpl)
+                StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl)
+                StatusBarLocation.SHADE_CARRIER_GROUP ->
+                    ShadeCarrierGroupMobileIconViewModel(commonImpl, interactor, scope)
+            }
+    }
+}
+
+class HomeMobileIconViewModelKairos(
+    commonImpl: MobileIconViewModelCommonKairos,
+    verboseMobileViewLogger: VerboseMobileViewLogger,
+) :
+    MobileIconViewModelCommonKairos,
+    LocationBasedMobileViewModelKairos(
+        commonImpl,
+        location = StatusBarLocation.HOME,
+        verboseMobileViewLogger,
+    )
+
+class QsMobileIconViewModelKairos(commonImpl: MobileIconViewModelCommonKairos) :
+    MobileIconViewModelCommonKairos,
+    LocationBasedMobileViewModelKairos(
+        commonImpl,
+        location = StatusBarLocation.QS,
+        // Only do verbose logging for the Home location.
+        verboseLogger = null,
+    )
+
+class ShadeCarrierGroupMobileIconViewModelKairos(
+    commonImpl: MobileIconViewModelCommonKairos,
+    interactor: MobileIconInteractor,
+    scope: CoroutineScope,
+) :
+    MobileIconViewModelCommonKairos,
+    LocationBasedMobileViewModelKairos(
+        commonImpl,
+        location = StatusBarLocation.SHADE_CARRIER_GROUP,
+        // Only do verbose logging for the Home location.
+        verboseLogger = null,
+    ) {
+    private val isSingleCarrier = interactor.isSingleCarrier
+    val carrierName = interactor.carrierName
+
+    override val isVisible: StateFlow<Boolean> =
+        combine(super.isVisible, isSingleCarrier) { isVisible, isSingleCarrier ->
+                if (isSingleCarrier) false else isVisible
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), super.isVisible.value)
+}
+
+class KeyguardMobileIconViewModelKairos(commonImpl: MobileIconViewModelCommonKairos) :
+    MobileIconViewModelCommonKairos,
+    LocationBasedMobileViewModelKairos(
+        commonImpl,
+        location = StatusBarLocation.KEYGUARD,
+        // Only do verbose logging for the Home location.
+        verboseLogger = null,
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelKairos.kt
new file mode 100644
index 0000000..cc7fc09
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelKairos.kt
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import com.android.systemui.Flags.statusBarStaticInoutIndicators
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.core.NewStatusBarIcons
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.model.MobileContentDescription
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+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.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/** Common interface for all of the location-based mobile icon view models. */
+interface MobileIconViewModelCommonKairos : MobileIconViewModelCommon {
+    override val subscriptionId: Int
+    /** True if this view should be visible at all. */
+    override val isVisible: StateFlow<Boolean>
+    override val icon: Flow<SignalIconModel>
+    override val contentDescription: Flow<MobileContentDescription?>
+    override val roaming: Flow<Boolean>
+    /** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
+    override val networkTypeIcon: Flow<Icon.Resource?>
+    /** The slice attribution. Drawn as a background layer */
+    override val networkTypeBackground: StateFlow<Icon.Resource?>
+    override val activityInVisible: Flow<Boolean>
+    override val activityOutVisible: Flow<Boolean>
+    override val activityContainerVisible: Flow<Boolean>
+}
+
+/**
+ * View model for the state of a single mobile icon. Each [MobileIconViewModel] will keep watch over
+ * a single line of service via [MobileIconInteractor] and update the UI based on that
+ * subscription's information.
+ *
+ * There will be exactly one [MobileIconViewModel] per filtered subscription offered from
+ * [MobileIconsInteractor.filteredSubscriptions].
+ *
+ * For the sake of keeping log spam in check, every flow funding the [MobileIconViewModelCommon]
+ * interface is implemented as a [StateFlow]. This ensures that each location-based mobile icon view
+ * model gets the exact same information, as well as allows us to log that unified state only once
+ * per icon.
+ */
+class MobileIconViewModelKairos(
+    override val subscriptionId: Int,
+    iconInteractor: MobileIconInteractor,
+    airplaneModeInteractor: AirplaneModeInteractor,
+    constants: ConnectivityConstants,
+    scope: CoroutineScope,
+) : MobileIconViewModelCommonKairos {
+    private val cellProvider by lazy {
+        CellularIconViewModelKairos(
+            subscriptionId,
+            iconInteractor,
+            airplaneModeInteractor,
+            constants,
+            scope,
+        )
+    }
+
+    private val satelliteProvider by lazy {
+        CarrierBasedSatelliteViewModelKairosImpl(
+            subscriptionId,
+            airplaneModeInteractor,
+            iconInteractor,
+            scope,
+        )
+    }
+
+    /**
+     * Similar to repository switching, this allows us to split up the logic of satellite/cellular
+     * states, since they are different by nature
+     */
+    private val vmProvider: Flow<MobileIconViewModelCommon> =
+        iconInteractor.isNonTerrestrial
+            .mapLatest { nonTerrestrial ->
+                if (nonTerrestrial) {
+                    satelliteProvider
+                } else {
+                    cellProvider
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), cellProvider)
+
+    override val isVisible: StateFlow<Boolean> =
+        vmProvider
+            .flatMapLatest { it.isVisible }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val icon: Flow<SignalIconModel> = vmProvider.flatMapLatest { it.icon }
+
+    override val contentDescription: Flow<MobileContentDescription?> =
+        vmProvider.flatMapLatest { it.contentDescription }
+
+    override val roaming: Flow<Boolean> = vmProvider.flatMapLatest { it.roaming }
+
+    override val networkTypeIcon: Flow<Icon.Resource?> =
+        vmProvider.flatMapLatest { it.networkTypeIcon }
+
+    override val networkTypeBackground: StateFlow<Icon.Resource?> =
+        vmProvider
+            .flatMapLatest { it.networkTypeBackground }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val activityInVisible: Flow<Boolean> =
+        vmProvider.flatMapLatest { it.activityInVisible }
+
+    override val activityOutVisible: Flow<Boolean> =
+        vmProvider.flatMapLatest { it.activityOutVisible }
+
+    override val activityContainerVisible: Flow<Boolean> =
+        vmProvider.flatMapLatest { it.activityContainerVisible }
+}
+
+/** Representation of this network when it is non-terrestrial (e.g., satellite) */
+private class CarrierBasedSatelliteViewModelKairosImpl(
+    override val subscriptionId: Int,
+    airplaneModeInteractor: AirplaneModeInteractor,
+    interactor: MobileIconInteractor,
+    scope: CoroutineScope,
+) : MobileIconViewModelCommon, MobileIconViewModelCommonKairos {
+    override val isVisible: StateFlow<Boolean> =
+        airplaneModeInteractor.isAirplaneMode
+            .map { !it }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val icon: Flow<SignalIconModel> = interactor.signalLevelIcon
+
+    override val contentDescription: Flow<MobileContentDescription?> = MutableStateFlow(null)
+
+    /** These fields are not used for satellite icons currently */
+    override val roaming: Flow<Boolean> = flowOf(false)
+    override val networkTypeIcon: Flow<Icon.Resource?> = flowOf(null)
+    override val networkTypeBackground: StateFlow<Icon.Resource?> = MutableStateFlow(null)
+    override val activityInVisible: Flow<Boolean> = flowOf(false)
+    override val activityOutVisible: Flow<Boolean> = flowOf(false)
+    override val activityContainerVisible: Flow<Boolean> = flowOf(false)
+}
+
+/** Terrestrial (cellular) icon. */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+private class CellularIconViewModelKairos(
+    override val subscriptionId: Int,
+    iconInteractor: MobileIconInteractor,
+    airplaneModeInteractor: AirplaneModeInteractor,
+    constants: ConnectivityConstants,
+    scope: CoroutineScope,
+) : MobileIconViewModelCommon, MobileIconViewModelCommonKairos {
+    override val isVisible: StateFlow<Boolean> =
+        if (!constants.hasDataCapabilities) {
+                flowOf(false)
+            } else {
+                combine(
+                    airplaneModeInteractor.isAirplaneMode,
+                    iconInteractor.isAllowedDuringAirplaneMode,
+                    iconInteractor.isForceHidden,
+                ) { isAirplaneMode, isAllowedDuringAirplaneMode, isForceHidden ->
+                    if (isForceHidden) {
+                        false
+                    } else if (isAirplaneMode) {
+                        isAllowedDuringAirplaneMode
+                    } else {
+                        true
+                    }
+                }
+            }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                iconInteractor.tableLogBuffer,
+                columnName = "visible",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val icon: Flow<SignalIconModel> = iconInteractor.signalLevelIcon
+
+    override val contentDescription: Flow<MobileContentDescription?> =
+        combine(iconInteractor.signalLevelIcon, iconInteractor.networkName) { icon, nameModel ->
+                when (icon) {
+                    is SignalIconModel.Cellular ->
+                        MobileContentDescription.Cellular(
+                            nameModel.name,
+                            icon.levelDescriptionRes(),
+                        )
+                    else -> null
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    private fun SignalIconModel.Cellular.levelDescriptionRes() =
+        when (level) {
+            0 -> R.string.accessibility_no_signal
+            1 -> R.string.accessibility_one_bar
+            2 -> R.string.accessibility_two_bars
+            3 -> R.string.accessibility_three_bars
+            4 -> {
+                if (numberOfLevels == 6) {
+                    R.string.accessibility_four_bars
+                } else {
+                    R.string.accessibility_signal_full
+                }
+            }
+            5 -> {
+                if (numberOfLevels == 6) {
+                    R.string.accessibility_signal_full
+                } else {
+                    R.string.accessibility_no_signal
+                }
+            }
+            else -> R.string.accessibility_no_signal
+        }
+
+    private val showNetworkTypeIcon: Flow<Boolean> =
+        combine(
+                iconInteractor.isDataConnected,
+                iconInteractor.isDataEnabled,
+                iconInteractor.alwaysShowDataRatIcon,
+                iconInteractor.mobileIsDefault,
+                iconInteractor.carrierNetworkChangeActive,
+            ) { dataConnected, dataEnabled, alwaysShow, mobileIsDefault, carrierNetworkChange ->
+                alwaysShow ||
+                    (!carrierNetworkChange && (dataEnabled && dataConnected && mobileIsDefault))
+            }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                iconInteractor.tableLogBuffer,
+                columnName = "showNetworkTypeIcon",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val networkTypeIcon: Flow<Icon.Resource?> =
+        combine(iconInteractor.networkTypeIconGroup, showNetworkTypeIcon) {
+                networkTypeIconGroup,
+                shouldShow ->
+                val desc =
+                    if (networkTypeIconGroup.contentDescription != 0)
+                        ContentDescription.Resource(networkTypeIconGroup.contentDescription)
+                    else null
+                val icon =
+                    if (networkTypeIconGroup.iconId != 0)
+                        Icon.Resource(networkTypeIconGroup.iconId, desc)
+                    else null
+                return@combine when {
+                    !shouldShow -> null
+                    else -> icon
+                }
+            }
+            .distinctUntilChanged()
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val networkTypeBackground =
+        iconInteractor.showSliceAttribution
+            .map {
+                when {
+                    it && NewStatusBarIcons.isEnabled ->
+                        Icon.Resource(R.drawable.mobile_network_type_background_updated, null)
+                    it -> Icon.Resource(R.drawable.mobile_network_type_background, null)
+                    else -> null
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val roaming: StateFlow<Boolean> =
+        iconInteractor.isRoaming
+            .logDiffsForTable(
+                iconInteractor.tableLogBuffer,
+                columnName = "roaming",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    private val activity: Flow<DataActivityModel?> =
+        if (!constants.shouldShowActivityConfig) {
+            flowOf(null)
+        } else {
+            iconInteractor.activity
+        }
+
+    override val activityInVisible: Flow<Boolean> =
+        activity
+            .map { it?.hasActivityIn ?: false }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val activityOutVisible: Flow<Boolean> =
+        activity
+            .map { it?.hasActivityOut ?: false }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val activityContainerVisible: Flow<Boolean> =
+        if (statusBarStaticInoutIndicators()) {
+                flowOf(constants.shouldShowActivityConfig)
+            } else {
+                activity.map { it != null && (it.hasActivityIn || it.hasActivityOut) }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelKairos.kt
new file mode 100644
index 0000000..a655407
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelKairos.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.coroutines.newTracingContext
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * View model for describing the system's current mobile cellular connections. The result is a list
+ * of [MobileIconViewModel]s which describe the individual icons and can be bound to
+ * [ModernStatusBarMobileView].
+ */
+@SysUISingleton
+class MobileIconsViewModelKairos
+@Inject
+constructor(
+    val logger: MobileViewLogger,
+    private val verboseLogger: VerboseMobileViewLogger,
+    private val interactor: MobileIconsInteractor,
+    private val airplaneModeInteractor: AirplaneModeInteractor,
+    private val constants: ConnectivityConstants,
+    @Background private val scope: CoroutineScope,
+) {
+    @VisibleForTesting
+    val reuseCache = ConcurrentHashMap<Int, Pair<MobileIconViewModel, CoroutineScope>>()
+
+    val activeMobileDataSubscriptionId: StateFlow<Int?> = interactor.activeMobileDataSubscriptionId
+
+    val subscriptionIdsFlow: StateFlow<List<Int>> =
+        interactor.filteredSubscriptions
+            .mapLatest { subscriptions ->
+                subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
+
+    val mobileSubViewModels: StateFlow<List<MobileIconViewModelCommon>> =
+        subscriptionIdsFlow
+            .map { ids -> ids.map { commonViewModelForSub(it) } }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+
+    private val firstMobileSubViewModel: StateFlow<MobileIconViewModelCommon?> =
+        mobileSubViewModels
+            .map {
+                if (it.isEmpty()) {
+                    null
+                } else {
+                    // Mobile icons get reversed by [StatusBarIconController], so the last element
+                    // in this list will show up visually first.
+                    it.last()
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    /**
+     * A flow that emits `true` if the mobile sub that's displayed first visually is showing its
+     * network type icon and `false` otherwise.
+     */
+    val firstMobileSubShowingNetworkTypeIcon: StateFlow<Boolean> =
+        firstMobileSubViewModel
+            .flatMapLatest { firstMobileSubViewModel ->
+                firstMobileSubViewModel?.networkTypeIcon?.map { it != null } ?: flowOf(false)
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    val isStackable: StateFlow<Boolean> = interactor.isStackable
+
+    init {
+        scope.launch { subscriptionIdsFlow.collect { invalidateCaches(it) } }
+    }
+
+    fun viewModelForSub(subId: Int, location: StatusBarLocation): LocationBasedMobileViewModel {
+        val common = commonViewModelForSub(subId)
+        return LocationBasedMobileViewModel.viewModelForLocation(
+            common,
+            interactor.getMobileConnectionInteractorForSubId(subId),
+            verboseLogger,
+            location,
+            scope,
+        )
+    }
+
+    private fun commonViewModelForSub(subId: Int): MobileIconViewModelCommon {
+        return reuseCache.getOrPut(subId) { createViewModel(subId) }.first
+    }
+
+    private fun createViewModel(subId: Int): Pair<MobileIconViewModel, CoroutineScope> {
+        // Create a child scope so we can cancel it
+        val vmScope = scope.createChildScope(newTracingContext("MobileIconViewModel"))
+        val vm =
+            MobileIconViewModel(
+                subId,
+                interactor.getMobileConnectionInteractorForSubId(subId),
+                airplaneModeInteractor,
+                constants,
+                vmScope,
+            )
+
+        return Pair(vm, vmScope)
+    }
+
+    private fun CoroutineScope.createChildScope(extraContext: CoroutineContext) =
+        CoroutineScope(coroutineContext + Job(coroutineContext[Job]) + extraContext)
+
+    private fun invalidateCaches(subIds: List<Int>) {
+        reuseCache.keys
+            .filter { !subIds.contains(it) }
+            .forEach { id ->
+                reuseCache
+                    .remove(id)
+                    // Cancel the view model's scope after removing it
+                    ?.second
+                    ?.cancel()
+            }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairos.kt
new file mode 100644
index 0000000..2dbb02c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairos.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.pipeline.mobile.ui.viewmodel
+
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class StackedMobileIconViewModelKairos
+@AssistedInject
+constructor(mobileIconsViewModel: MobileIconsViewModel) : ExclusiveActivatable() {
+    private val hydrator = Hydrator("StackedMobileIconViewModel")
+
+    private val isStackable: Boolean by
+        hydrator.hydratedStateOf(
+            traceName = "isStackable",
+            source = mobileIconsViewModel.isStackable,
+            initialValue = false,
+        )
+
+    private val iconViewModelFlow: Flow<List<MobileIconViewModelCommon>> =
+        combine(
+            mobileIconsViewModel.mobileSubViewModels,
+            mobileIconsViewModel.activeMobileDataSubscriptionId,
+        ) { viewModels, activeSubId ->
+            // Sort to get the active subscription first, if it's set
+            viewModels.sortedByDescending { it.subscriptionId == activeSubId }
+        }
+
+    val dualSim: DualSim? by
+        hydrator.hydratedStateOf(
+            traceName = "dualSim",
+            source =
+                iconViewModelFlow.flatMapLatest { viewModels ->
+                    combine(viewModels.map { it.icon }) { icons ->
+                        icons
+                            .toList()
+                            .filterIsInstance<SignalIconModel.Cellular>()
+                            .takeIf { it.size == 2 }
+                            ?.let { DualSim(it[0], it[1]) }
+                    }
+                },
+            initialValue = null,
+        )
+
+    val networkTypeIcon: Icon.Resource? by
+        hydrator.hydratedStateOf(
+            traceName = "networkTypeIcon",
+            source =
+                iconViewModelFlow.flatMapLatest { viewModels ->
+                    viewModels.firstOrNull()?.networkTypeIcon ?: flowOf(null)
+                },
+            initialValue = null,
+        )
+
+    val isIconVisible: Boolean by derivedStateOf { isStackable && dualSim != null }
+
+    override suspend fun onActivated(): Nothing {
+        hydrator.activate()
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(): StackedMobileIconViewModelKairos
+    }
+
+    data class DualSim(
+        val primary: SignalIconModel.Cellular,
+        val secondary: SignalIconModel.Cellular,
+    )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
index cdd0286..6fada26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
@@ -203,6 +203,8 @@
                         OngoingActivityChipBinder.createBinding(
                             view.requireViewById(R.id.ongoing_activity_chip_secondary)
                         )
+                    OngoingActivityChipBinder.updateTypefaces(primaryChipViewBinding)
+                    OngoingActivityChipBinder.updateTypefaces(secondaryChipViewBinding)
                     launch {
                         combine(
                                 viewModel.ongoingActivityChipsLegacy,
@@ -258,7 +260,7 @@
                 if (SceneContainerFlag.isEnabled) {
                     listener?.let { listener ->
                         launch {
-                            viewModel.isHomeStatusBarAllowedByScene.collect {
+                            viewModel.isHomeStatusBarAllowed.collect {
                                 listener.onIsHomeStatusBarAllowedBySceneChanged(it)
                             }
                         }
@@ -503,7 +505,7 @@
 
     /**
      * Called when the scene state has changed such that the home status bar is newly allowed or no
-     * longer allowed. See [HomeStatusBarViewModel.isHomeStatusBarAllowedByScene].
+     * longer allowed. See [HomeStatusBarViewModel.isHomeStatusBarAllowed].
      */
     fun onIsHomeStatusBarAllowedBySceneChanged(isHomeStatusBarAllowedByScene: Boolean)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index 9975aff..3bae91a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -18,6 +18,7 @@
 
 import android.annotation.ColorInt
 import android.graphics.Rect
+import android.view.Display
 import android.view.View
 import androidx.compose.runtime.getValue
 import com.android.app.tracing.coroutines.launchTraced as launch
@@ -41,7 +42,9 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
 import com.android.systemui.statusbar.chips.mediaprojection.domain.model.MediaProjectionStopDialogModel
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.ShareToAppChipViewModel
@@ -73,6 +76,7 @@
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import javax.inject.Provider
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.awaitCancellation
@@ -142,13 +146,12 @@
     val popupChips: List<PopupChipModel.Shown>
 
     /**
-     * True if the current scene can show the home status bar (aka this status bar), and false if
-     * the current scene should never show the home status bar.
+     * True if the status bar should be visible.
      *
      * TODO(b/364360986): Once the is<SomeChildView>Visible flows are fully enabled, we shouldn't
      *   need this flow anymore.
      */
-    val isHomeStatusBarAllowedByScene: StateFlow<Boolean>
+    val isHomeStatusBarAllowed: StateFlow<Boolean>
 
     /** True if the home status bar is showing, and there is no HUN happening */
     val canShowOngoingActivityChips: Flow<Boolean>
@@ -222,6 +225,7 @@
     statusBarContentInsetsViewModelStore: StatusBarContentInsetsViewModelStore,
     @Background bgScope: CoroutineScope,
     @Background bgDispatcher: CoroutineDispatcher,
+    shadeDisplaysInteractor: Provider<ShadeDisplaysInteractor>,
 ) : HomeStatusBarViewModel, ExclusiveActivatable() {
 
     private val hydrator = Hydrator(traceName = "HomeStatusBarViewModel.hydrator")
@@ -258,12 +262,44 @@
     override val popupChips
         get() = statusBarPopupChips.shownPopupChips
 
-    override val isHomeStatusBarAllowedByScene: StateFlow<Boolean> =
+    /**
+     * Whether the display of this statusbar has the shade window (that is hosting shade container
+     * and lockscreen, among other things).
+     */
+    private val isShadeWindowOnThisDisplay =
+        if (ShadeWindowGoesAround.isEnabled) {
+            shadeDisplaysInteractor.get().displayId.map { shadeDisplayId ->
+                thisDisplayId == shadeDisplayId
+            }
+        } else {
+            // Shade doesn't move anywhere, it is always on the default display.
+            flowOf(thisDisplayId == Display.DEFAULT_DISPLAY)
+        }
+
+    private val isShadeVisibleOnAnyDisplay =
+        if (SceneContainerFlag.isEnabled) {
+            sceneInteractor.currentOverlays.map { currentOverlays ->
+                (Overlays.NotificationsShade in currentOverlays ||
+                    Overlays.QuickSettingsShade in currentOverlays)
+            }
+        } else {
+            shadeInteractor.isAnyFullyExpanded
+        }
+
+    private val isShadeVisibleOnThisDisplay: Flow<Boolean> =
+        combine(isShadeWindowOnThisDisplay, isShadeVisibleOnAnyDisplay) {
+            hasShade,
+            isShadeVisibleOnAnyDisplay ->
+            hasShade && isShadeVisibleOnAnyDisplay
+        }
+
+    private val isHomeStatusBarAllowedByScene: Flow<Boolean> =
         combine(
                 sceneInteractor.currentScene,
-                sceneInteractor.currentOverlays,
+                isShadeVisibleOnThisDisplay,
                 sceneContainerOcclusionInteractor.invisibleDueToOcclusion,
-            ) { currentScene, currentOverlays, isOccluded ->
+            ) { currentScene, isShadeVisible, isOccluded ->
+
                 // All scenes have their own status bars, so we should only show the home status bar
                 // if we're not in a scene. There are two exceptions:
                 // 1) The shade (notifications or quick settings) is shown, because it has its own
@@ -271,9 +307,7 @@
                 // 2) If the scene is occluded, then the occluding app needs to show the status bar.
                 // (Fullscreen apps actually won't show the status bar but that's handled with the
                 // rest of our fullscreen app logic, which lives elsewhere.)
-                (currentScene == Scenes.Gone &&
-                    Overlays.NotificationsShade !in currentOverlays &&
-                    Overlays.QuickSettingsShade !in currentOverlays) || isOccluded
+                (currentScene == Scenes.Gone && !isShadeVisible) || isOccluded
             }
             .distinctUntilChanged()
             .logDiffsForTable(
@@ -281,7 +315,6 @@
                 columnName = COL_ALLOWED_BY_SCENE,
                 initialValue = false,
             )
-            .stateIn(bgScope, SharingStarted.WhileSubscribed(), initialValue = false)
 
     override val areNotificationsLightsOut: Flow<Boolean> =
         if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) {
@@ -330,21 +363,29 @@
      * if we shouldn't be showing any part of the home status bar.
      */
     private val isHomeScreenStatusBarAllowedLegacy: Flow<Boolean> =
-        combine(
-            keyguardTransitionInteractor.currentKeyguardState,
-            shadeInteractor.isAnyFullyExpanded,
-        ) { currentKeyguardState, isShadeExpanded ->
-            (currentKeyguardState == GONE || currentKeyguardState == OCCLUDED) && !isShadeExpanded
+        combine(keyguardTransitionInteractor.currentKeyguardState, isShadeVisibleOnThisDisplay) {
+            currentKeyguardState,
+            isShadeVisibleOnThisDisplay ->
+            (currentKeyguardState == GONE || currentKeyguardState == OCCLUDED) &&
+                !isShadeVisibleOnThisDisplay
             // TODO(b/364360986): Add edge cases, like secure camera launch.
         }
 
-    private val isHomeStatusBarAllowed: Flow<Boolean> =
+    // "Compat" to cover both legacy and Scene container case in one flow.
+    private val isHomeStatusBarAllowedCompat =
         if (SceneContainerFlag.isEnabled) {
             isHomeStatusBarAllowedByScene
         } else {
             isHomeScreenStatusBarAllowedLegacy
         }
 
+    override val isHomeStatusBarAllowed =
+        isHomeStatusBarAllowedCompat.stateIn(
+            bgScope,
+            SharingStarted.WhileSubscribed(),
+            initialValue = false,
+        )
+
     private val shouldHomeStatusBarBeVisible =
         combine(
                 isHomeStatusBarAllowed,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 2b0bf1a..f1f2b88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -461,6 +461,7 @@
                 }
             }
         }
+        unregisterBackCallback();
 
         if (logClose) {
             mUiEventLogger.logWithInstanceId(
@@ -558,11 +559,6 @@
 
     @Override
     public void onVisibilityAggregated(boolean isVisible) {
-        if (isVisible) {
-            registerBackCallback();
-        } else {
-            unregisterBackCallback();
-        }
         super.onVisibilityAggregated(isVisible);
         mEditText.setEnabled(isVisible && !mSending);
     }
@@ -623,6 +619,7 @@
         setAttachment(mEntry.remoteInputAttachment);
 
         updateSendButton();
+        registerBackCallback();
     }
 
     public void onNotificationUpdateOrReset() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
index 16f24f1..5d7ce91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
@@ -34,7 +34,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.Flags
-import com.android.systemui.qs.panels.ui.compose.PagerDots
+import com.android.systemui.common.ui.compose.PagerDots
 import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModesDialogViewModel
 
 @Composable
diff --git a/packages/SystemUI/src/com/android/systemui/supervision/shared/DeprecateDpmSupervisionApis.kt b/packages/SystemUI/src/com/android/systemui/supervision/shared/DeprecateDpmSupervisionApis.kt
index 59c05c2..a94d51a 100644
--- a/packages/SystemUI/src/com/android/systemui/supervision/shared/DeprecateDpmSupervisionApis.kt
+++ b/packages/SystemUI/src/com/android/systemui/supervision/shared/DeprecateDpmSupervisionApis.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun unsafeAssertInNewMode() = RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/topwindoweffects/TopLevelWindowEffects.kt b/packages/SystemUI/src/com/android/systemui/topwindoweffects/TopLevelWindowEffects.kt
new file mode 100644
index 0000000..7dc6fa8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/topwindoweffects/TopLevelWindowEffects.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.topwindoweffects;
+
+import android.content.Context
+import android.graphics.PixelFormat
+import android.view.Gravity
+import android.view.WindowInsets
+import android.view.WindowManager
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.topwindoweffects.domain.interactor.SqueezeEffectInteractor
+import com.android.systemui.topwindoweffects.ui.compose.EffectsWindowRoot
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@SysUISingleton
+class TopLevelWindowEffects @Inject constructor(
+    @Application private val context: Context,
+    @Application private val applicationScope: CoroutineScope,
+    private val windowManager: ViewCaptureAwareWindowManager,
+    private val squeezeEffectInteractor: SqueezeEffectInteractor
+) : CoreStartable {
+
+    override fun start() {
+        applicationScope.launch {
+            var root: EffectsWindowRoot? = null
+            squeezeEffectInteractor.isSqueezeEffectEnabled.collectLatest { enabled ->
+                // TODO: move window ops to a separate UI thread
+                if (enabled && root == null) {
+                    root = EffectsWindowRoot(context)
+                    root?.let { windowManager.addView(it, getWindowManagerLayoutParams()) }
+                } else if (root?.isAttachedToWindow == true) {
+                    windowManager.removeView(root)
+                    root = null
+                }
+            }
+        }
+    }
+
+    private fun getWindowManagerLayoutParams(): WindowManager.LayoutParams {
+        val lp = WindowManager.LayoutParams(
+            WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
+            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
+            PixelFormat.TRANSPARENT
+        )
+
+        lp.privateFlags = lp.privateFlags or
+                (WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS
+                        or WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
+                        or WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED
+                        or WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
+                        or WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
+
+        lp.layoutInDisplayCutoutMode =
+            WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+
+        lp.title = "TopLevelWindowEffects"
+        lp.fitInsetsTypes = WindowInsets.Type.systemOverlays()
+        lp.gravity = Gravity.TOP
+
+        return lp
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/topwindoweffects/dagger/SqueezeEffectRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/topwindoweffects/dagger/SqueezeEffectRepositoryModule.kt
new file mode 100644
index 0000000..5a2af92
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/topwindoweffects/dagger/SqueezeEffectRepositoryModule.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.topwindoweffects.dagger
+
+import com.android.systemui.topwindoweffects.data.repository.SqueezeEffectRepository
+import com.android.systemui.topwindoweffects.data.repository.SqueezeEffectRepositoryImpl
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface SqueezeEffectRepositoryModule {
+
+    @Binds
+    fun squeezeEffectRepository(
+        squeezeEffectRepositoryImpl: SqueezeEffectRepositoryImpl
+    ) : SqueezeEffectRepository
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/topwindoweffects/dagger/TopLevelWindowEffectsModule.kt b/packages/SystemUI/src/com/android/systemui/topwindoweffects/dagger/TopLevelWindowEffectsModule.kt
new file mode 100644
index 0000000..6fbfedc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/topwindoweffects/dagger/TopLevelWindowEffectsModule.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.topwindoweffects.dagger
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.topwindoweffects.TopLevelWindowEffects
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface TopLevelWindowEffectsModule {
+
+    @Binds
+    @IntoMap
+    @ClassKey(TopLevelWindowEffects::class)
+    fun bindTopLevelWindowEffectsCoreStartable(impl: TopLevelWindowEffects): CoreStartable
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/topwindoweffects/data/repository/SqueezeEffectRepository.kt
similarity index 70%
rename from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
rename to packages/SystemUI/src/com/android/systemui/topwindoweffects/data/repository/SqueezeEffectRepository.kt
index 9b7cd70..9e0b256 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/topwindoweffects/data/repository/SqueezeEffectRepository.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.topwindoweffects.data.repository
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import kotlinx.coroutines.flow.Flow
+
+interface SqueezeEffectRepository {
+    val isSqueezeEffectEnabled: Flow<Boolean>
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/topwindoweffects/data/repository/SqueezeEffectRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/topwindoweffects/data/repository/SqueezeEffectRepositoryImpl.kt
new file mode 100644
index 0000000..9e0feed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/topwindoweffects/data/repository/SqueezeEffectRepositoryImpl.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.topwindoweffects.data.repository
+
+import android.database.ContentObserver
+import android.os.Handler
+import android.provider.Settings.Global.POWER_BUTTON_LONG_PRESS
+import com.android.internal.R
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.shared.Flags
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+
+@SysUISingleton
+class SqueezeEffectRepositoryImpl @Inject constructor(
+    @Background private val bgHandler: Handler?,
+    @Background private val bgCoroutineContext: CoroutineContext,
+    private val globalSettings: GlobalSettings
+) : SqueezeEffectRepository {
+
+    override val isSqueezeEffectEnabled: Flow<Boolean> = conflatedCallbackFlow {
+        val observer = object : ContentObserver(bgHandler) {
+            override fun onChange(selfChange: Boolean) {
+                trySendWithFailureLogging(squeezeEffectEnabled, TAG,
+                    "updated isSqueezeEffectEnabled")
+            }
+        }
+        trySendWithFailureLogging(squeezeEffectEnabled, TAG, "init isSqueezeEffectEnabled")
+        globalSettings.registerContentObserverAsync(POWER_BUTTON_LONG_PRESS, observer)
+        awaitClose { globalSettings.unregisterContentObserverAsync(observer) }
+    }.flowOn(bgCoroutineContext)
+
+    private val squeezeEffectEnabled
+        get() = Flags.enableLppSqueezeEffect() && globalSettings.getInt(
+            POWER_BUTTON_LONG_PRESS, R.integer.config_longPressOnPowerBehavior
+        ) == 5 // 5 corresponds to launch assistant in config_longPressOnPowerBehavior
+
+    companion object {
+        private const val TAG = "SqueezeEffectRepository"
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/topwindoweffects/domain/interactor/SqueezeEffectInteractor.kt b/packages/SystemUI/src/com/android/systemui/topwindoweffects/domain/interactor/SqueezeEffectInteractor.kt
new file mode 100644
index 0000000..879fde7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/topwindoweffects/domain/interactor/SqueezeEffectInteractor.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.topwindoweffects.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.topwindoweffects.data.repository.SqueezeEffectRepository
+import javax.inject.Inject
+
+@SysUISingleton
+class SqueezeEffectInteractor @Inject constructor(
+    squeezeEffectRepository: SqueezeEffectRepository
+) {
+    val isSqueezeEffectEnabled = squeezeEffectRepository.isSqueezeEffectEnabled
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/topwindoweffects/ui/compose/EffectsWindowRoot.kt b/packages/SystemUI/src/com/android/systemui/topwindoweffects/ui/compose/EffectsWindowRoot.kt
new file mode 100644
index 0000000..0826917
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/topwindoweffects/ui/compose/EffectsWindowRoot.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.topwindoweffects.ui.compose
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.AbstractComposeView
+import com.android.systemui.compose.ComposeInitializer
+
+class EffectsWindowRoot : AbstractComposeView {
+    constructor(context: Context) : super(context)
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
+
+    constructor(
+        context: Context,
+        attrs: AttributeSet,
+        defStyleAttr: Int,
+    ) : super(context, attrs, defStyleAttr)
+
+    override fun onAttachedToWindow() {
+        ComposeInitializer.onAttachedToWindow(this)
+        super.onAttachedToWindow()
+    }
+
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        ComposeInitializer.onDetachedFromWindow(this)
+    }
+
+    @Composable
+    override fun Content() {
+        SqueezeEffect()
+    }
+}
\ No newline at end of file
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/packages/SystemUI/src/com/android/systemui/topwindoweffects/ui/compose/SqueezeEffect.kt
similarity index 71%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to packages/SystemUI/src/com/android/systemui/topwindoweffects/ui/compose/SqueezeEffect.kt
index 6b8161c..1247240 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/packages/SystemUI/src/com/android/systemui/topwindoweffects/ui/compose/SqueezeEffect.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,6 +14,11 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package com.android.systemui.topwindoweffects.ui.compose
 
-parcelable SoundProfileHandle;
+import androidx.compose.runtime.Composable
+
+@Composable
+fun SqueezeEffect() {
+    // TODO: add squeeze effect
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index eecea92..2f8da2e 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -84,7 +84,7 @@
                 ),
     ) {
         val isCompactWindow = hasCompactWindowSize()
-        val padding = if (isCompactWindow) 24.dp else 60.dp
+        val padding = if (isCompactWindow) 24.dp else 48.dp
         val configuration = LocalConfiguration.current
         when (configuration.orientation) {
             Configuration.ORIENTATION_LANDSCAPE -> {
@@ -121,7 +121,7 @@
         // because other composables have weight 1, Done button will be positioned first
         DoneButton(
             onDoneButtonClicked = onDoneButtonClicked,
-            modifier = Modifier.padding(horizontal = padding),
+            modifier = Modifier.padding(start = padding, top = 0.dp, end = padding, bottom = 32.dp),
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
index bb8fe46..3ac6c7b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
@@ -28,7 +28,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 import com.android.systemui.volume.Events
-import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import com.android.systemui.volume.dialog.dagger.factory.VolumeDialogComponentFactory
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.awaitCancellation
@@ -37,7 +37,7 @@
 @Inject
 constructor(
     @Application context: Context,
-    private val componentFactory: VolumeDialogComponent.Factory,
+    private val componentFactory: VolumeDialogComponentFactory,
     private val visibilityInteractor: VolumeDialogVisibilityInteractor,
 ) : ComponentDialog(context, R.style.Theme_SystemUI_Dialog_Volume) {
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
index 434f6b5..36b2b48 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.volume.dialog.dagger
 
+import com.android.systemui.volume.dialog.dagger.factory.VolumeDialogComponentFactory
 import com.android.systemui.volume.dialog.dagger.module.VolumeDialogModule
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
@@ -38,9 +39,9 @@
     fun sliderComponentFactory(): VolumeDialogSliderComponent.Factory
 
     @Subcomponent.Factory
-    interface Factory {
+    interface Factory : VolumeDialogComponentFactory {
 
-        fun create(
+        override fun create(
             /**
              * Provides a coroutine scope to use inside [VolumeDialogScope].
              * [com.android.systemui.volume.dialog.VolumeDialogPlugin] manages the lifecycle of this
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/factory/VolumeDialogComponentFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/factory/VolumeDialogComponentFactory.kt
new file mode 100644
index 0000000..d909f26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/factory/VolumeDialogComponentFactory.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.dialog.dagger.factory
+
+import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import kotlinx.coroutines.CoroutineScope
+
+/** Common interface for all dagger Subcomponent.Factory providing [VolumeDialogComponent]. */
+interface VolumeDialogComponentFactory {
+
+    fun create(scope: CoroutineScope): VolumeDialogComponent
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
index 7b08317..fcf4d110 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
@@ -16,10 +16,12 @@
 
 package com.android.systemui.volume.dialog.dagger.module
 
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepository
 import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepositoryImpl
 import com.android.systemui.volume.dialog.ringer.ui.binder.VolumeDialogRingerViewBinder
 import com.android.systemui.volume.dialog.settings.ui.binder.VolumeDialogSettingsButtonViewBinder
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBinder
 import com.android.systemui.volume.dialog.ui.binder.ViewBinder
 import dagger.Binds
@@ -27,7 +29,7 @@
 import dagger.Provides
 
 /** Dagger module for volume dialog code in the volume package */
-@Module
+@Module(subcomponents = [VolumeDialogSliderComponent::class])
 interface VolumeDialogModule {
 
     @Binds
@@ -38,6 +40,7 @@
     companion object {
 
         @Provides
+        @VolumeDialog
         fun provideViewBinders(
             slidersViewBinder: VolumeDialogSlidersViewBinder,
             ringerViewBinder: VolumeDialogRingerViewBinder,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
index 547c51d..35752ae 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.volume.dialog.dagger.module
 
 import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import com.android.systemui.volume.dialog.dagger.factory.VolumeDialogComponentFactory
 import com.android.systemui.volume.dialog.shared.model.CsdWarningConfigModel
 import com.android.systemui.volume.dialog.utils.VolumeTracer
 import com.android.systemui.volume.dialog.utils.VolumeTracerImpl
@@ -27,6 +28,11 @@
 @Module(subcomponents = [VolumeDialogComponent::class])
 interface VolumeDialogPluginModule {
 
+    @Binds
+    fun bindVolumeDialogComponentFactory(
+        factory: VolumeDialogComponent.Factory
+    ): VolumeDialogComponentFactory
+
     @Binds fun bindVolumeTracer(volumeTracer: VolumeTracerImpl): VolumeTracer
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
index 577e47b..d0ed24d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogOverscrollViewBinder
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderViewBinder
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel
 import dagger.BindsInstance
 import dagger.Subcomponent
 
@@ -34,6 +35,8 @@
 
     fun overscrollViewBinder(): VolumeDialogOverscrollViewBinder
 
+    fun sliderViewModel(): VolumeDialogSliderViewModel
+
     @Subcomponent.Factory
     interface Factory {
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
index 5de8fe5..11d9df4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.res.R
 import com.android.systemui.util.kotlin.awaitCancellationThenDispose
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
 import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory
@@ -72,7 +73,7 @@
     private val viewModel: VolumeDialogViewModel,
     private val jankListenerFactory: JankListenerFactory,
     private val tracer: VolumeTracer,
-    private val viewBinders: List<@JvmSuppressWildcards ViewBinder>,
+    @VolumeDialog private val viewBinders: List<@JvmSuppressWildcards ViewBinder>,
 ) {
 
     private val halfOpenedOffsetPx: Float =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt b/packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt
index 720d550..f6582a0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt
@@ -72,10 +72,10 @@
     valueRange: ClosedFloatingPointRange<Float>,
     onValueChanged: (Float) -> Unit,
     onValueChangeFinished: ((Float) -> Unit)?,
-    stepDistance: Float,
     isEnabled: Boolean,
     accessibilityParams: AccessibilityParams,
     modifier: Modifier = Modifier,
+    stepDistance: Float = 0f,
     colors: SliderColors = SliderDefaults.colors(),
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     haptics: Haptics = Haptics.Disabled,
@@ -83,7 +83,7 @@
     isReverseDirection: Boolean = false,
     track: (@Composable (SliderState) -> Unit)? = null,
 ) {
-    require(stepDistance > 0) { "stepDistance must be positive" }
+    require(stepDistance >= 0) { "stepDistance must not be negative" }
     val coroutineScope = rememberCoroutineScope()
     val snappedValue = snapValue(value, valueRange, stepDistance)
     val hapticsViewModel = haptics.createViewModel(snappedValue, valueRange, interactionSource)
@@ -192,16 +192,20 @@
         setProgress { targetValue ->
             val targetDirection =
                 when {
-                    targetValue > value -> 1
-                    targetValue < value -> -1
-                    else -> 0
+                    targetValue > value -> 1f
+                    targetValue < value -> -1f
+                    else -> 0f
+                }
+            val offset =
+                if (stepDistance > 0) {
+                    // advance to the next step when stepDistance is > 0
+                    targetDirection * stepDistance
+                } else {
+                    // advance to the desired value otherwise
+                    targetValue - value
                 }
 
-            val newValue =
-                (value + targetDirection * stepDistance).coerceIn(
-                    valueRange.start,
-                    valueRange.endInclusive,
-                )
+            val newValue = (value + offset).coerceIn(valueRange.start, valueRange.endInclusive)
             onValueChanged(newValue)
             true
         }
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
rename to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
similarity index 93%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
rename to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json
rename to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 98%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withAnimator.json
rename to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index aa80445..41a46df 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withAnimator.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -468,15 +468,15 @@
         238,
         249,
         254,
-        233,
-        191,
-        153,
-        117,
-        85,
-        57,
-        33,
-        14,
-        3,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         0,
         0,
         0,
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json
rename to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withSpring.json
deleted file mode 100644
index 7abff2c..0000000
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withSpring.json
+++ /dev/null
@@ -1,384 +0,0 @@
-{
-  "frame_ids": [
-    0,
-    16,
-    32,
-    48,
-    64,
-    80,
-    96,
-    112,
-    128,
-    144,
-    160,
-    176,
-    192,
-    208,
-    224,
-    240,
-    256,
-    272,
-    288,
-    304
-  ],
-  "features": [
-    {
-      "name": "bounds",
-      "type": "rect",
-      "data_points": [
-        {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
-          "left": 104,
-          "top": 285,
-          "right": 215,
-          "bottom": 414
-        },
-        {
-          "left": 92,
-          "top": 252,
-          "right": 227,
-          "bottom": 447
-        },
-        {
-          "left": 77,
-          "top": 213,
-          "right": 242,
-          "bottom": 486
-        },
-        {
-          "left": 63,
-          "top": 175,
-          "right": 256,
-          "bottom": 524
-        },
-        {
-          "left": 50,
-          "top": 141,
-          "right": 269,
-          "bottom": 558
-        },
-        {
-          "left": 40,
-          "top": 112,
-          "right": 279,
-          "bottom": 587
-        },
-        {
-          "left": 31,
-          "top": 88,
-          "right": 288,
-          "bottom": 611
-        },
-        {
-          "left": 23,
-          "top": 68,
-          "right": 296,
-          "bottom": 631
-        },
-        {
-          "left": 18,
-          "top": 53,
-          "right": 301,
-          "bottom": 646
-        },
-        {
-          "left": 13,
-          "top": 41,
-          "right": 306,
-          "bottom": 658
-        },
-        {
-          "left": 10,
-          "top": 31,
-          "right": 309,
-          "bottom": 667
-        },
-        {
-          "left": 7,
-          "top": 24,
-          "right": 312,
-          "bottom": 673
-        },
-        {
-          "left": 5,
-          "top": 18,
-          "right": 314,
-          "bottom": 678
-        },
-        {
-          "left": 4,
-          "top": 13,
-          "right": 315,
-          "bottom": 681
-        },
-        {
-          "left": 3,
-          "top": 10,
-          "right": 316,
-          "bottom": 684
-        },
-        {
-          "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 685
-        },
-        {
-          "left": 1,
-          "top": 5,
-          "right": 318,
-          "bottom": 687
-        },
-        {
-          "left": 1,
-          "top": 4,
-          "right": 318,
-          "bottom": 688
-        },
-        {
-          "left": 0,
-          "top": 3,
-          "right": 319,
-          "bottom": 688
-        }
-      ]
-    },
-    {
-      "name": "corner_radii",
-      "type": "cornerRadii",
-      "data_points": [
-        null,
-        {
-          "top_left_x": 9.492916,
-          "top_left_y": 9.492916,
-          "top_right_x": 9.492916,
-          "top_right_y": 9.492916,
-          "bottom_right_x": 18.985832,
-          "bottom_right_y": 18.985832,
-          "bottom_left_x": 18.985832,
-          "bottom_left_y": 18.985832
-        },
-        {
-          "top_left_x": 8.381761,
-          "top_left_y": 8.381761,
-          "top_right_x": 8.381761,
-          "top_right_y": 8.381761,
-          "bottom_right_x": 16.763521,
-          "bottom_right_y": 16.763521,
-          "bottom_left_x": 16.763521,
-          "bottom_left_y": 16.763521
-        },
-        {
-          "top_left_x": 7.07397,
-          "top_left_y": 7.07397,
-          "top_right_x": 7.07397,
-          "top_right_y": 7.07397,
-          "bottom_right_x": 14.14794,
-          "bottom_right_y": 14.14794,
-          "bottom_left_x": 14.14794,
-          "bottom_left_y": 14.14794
-        },
-        {
-          "top_left_x": 5.7880254,
-          "top_left_y": 5.7880254,
-          "top_right_x": 5.7880254,
-          "top_right_y": 5.7880254,
-          "bottom_right_x": 11.576051,
-          "bottom_right_y": 11.576051,
-          "bottom_left_x": 11.576051,
-          "bottom_left_y": 11.576051
-        },
-        {
-          "top_left_x": 4.6295347,
-          "top_left_y": 4.6295347,
-          "top_right_x": 4.6295347,
-          "top_right_y": 4.6295347,
-          "bottom_right_x": 9.259069,
-          "bottom_right_y": 9.259069,
-          "bottom_left_x": 9.259069,
-          "bottom_left_y": 9.259069
-        },
-        {
-          "top_left_x": 3.638935,
-          "top_left_y": 3.638935,
-          "top_right_x": 3.638935,
-          "top_right_y": 3.638935,
-          "bottom_right_x": 7.27787,
-          "bottom_right_y": 7.27787,
-          "bottom_left_x": 7.27787,
-          "bottom_left_y": 7.27787
-        },
-        {
-          "top_left_x": 2.8209057,
-          "top_left_y": 2.8209057,
-          "top_right_x": 2.8209057,
-          "top_right_y": 2.8209057,
-          "bottom_right_x": 5.6418114,
-          "bottom_right_y": 5.6418114,
-          "bottom_left_x": 5.6418114,
-          "bottom_left_y": 5.6418114
-        },
-        {
-          "top_left_x": 2.1620893,
-          "top_left_y": 2.1620893,
-          "top_right_x": 2.1620893,
-          "top_right_y": 2.1620893,
-          "bottom_right_x": 4.3241787,
-          "bottom_right_y": 4.3241787,
-          "bottom_left_x": 4.3241787,
-          "bottom_left_y": 4.3241787
-        },
-        {
-          "top_left_x": 1.6414614,
-          "top_left_y": 1.6414614,
-          "top_right_x": 1.6414614,
-          "top_right_y": 1.6414614,
-          "bottom_right_x": 3.2829227,
-          "bottom_right_y": 3.2829227,
-          "bottom_left_x": 3.2829227,
-          "bottom_left_y": 3.2829227
-        },
-        {
-          "top_left_x": 1.2361269,
-          "top_left_y": 1.2361269,
-          "top_right_x": 1.2361269,
-          "top_right_y": 1.2361269,
-          "bottom_right_x": 2.4722538,
-          "bottom_right_y": 2.4722538,
-          "bottom_left_x": 2.4722538,
-          "bottom_left_y": 2.4722538
-        },
-        {
-          "top_left_x": 0.92435074,
-          "top_left_y": 0.92435074,
-          "top_right_x": 0.92435074,
-          "top_right_y": 0.92435074,
-          "bottom_right_x": 1.8487015,
-          "bottom_right_y": 1.8487015,
-          "bottom_left_x": 1.8487015,
-          "bottom_left_y": 1.8487015
-        },
-        {
-          "top_left_x": 0.68693924,
-          "top_left_y": 0.68693924,
-          "top_right_x": 0.68693924,
-          "top_right_y": 0.68693924,
-          "bottom_right_x": 1.3738785,
-          "bottom_right_y": 1.3738785,
-          "bottom_left_x": 1.3738785,
-          "bottom_left_y": 1.3738785
-        },
-        {
-          "top_left_x": 0.5076904,
-          "top_left_y": 0.5076904,
-          "top_right_x": 0.5076904,
-          "top_right_y": 0.5076904,
-          "bottom_right_x": 1.0153809,
-          "bottom_right_y": 1.0153809,
-          "bottom_left_x": 1.0153809,
-          "bottom_left_y": 1.0153809
-        },
-        {
-          "top_left_x": 0.3733511,
-          "top_left_y": 0.3733511,
-          "top_right_x": 0.3733511,
-          "top_right_y": 0.3733511,
-          "bottom_right_x": 0.7467022,
-          "bottom_right_y": 0.7467022,
-          "bottom_left_x": 0.7467022,
-          "bottom_left_y": 0.7467022
-        },
-        {
-          "top_left_x": 0.27331638,
-          "top_left_y": 0.27331638,
-          "top_right_x": 0.27331638,
-          "top_right_y": 0.27331638,
-          "bottom_right_x": 0.54663277,
-          "bottom_right_y": 0.54663277,
-          "bottom_left_x": 0.54663277,
-          "bottom_left_y": 0.54663277
-        },
-        {
-          "top_left_x": 0.19925308,
-          "top_left_y": 0.19925308,
-          "top_right_x": 0.19925308,
-          "top_right_y": 0.19925308,
-          "bottom_right_x": 0.39850616,
-          "bottom_right_y": 0.39850616,
-          "bottom_left_x": 0.39850616,
-          "bottom_left_y": 0.39850616
-        },
-        {
-          "top_left_x": 0.14470005,
-          "top_left_y": 0.14470005,
-          "top_right_x": 0.14470005,
-          "top_right_y": 0.14470005,
-          "bottom_right_x": 0.2894001,
-          "bottom_right_y": 0.2894001,
-          "bottom_left_x": 0.2894001,
-          "bottom_left_y": 0.2894001
-        },
-        {
-          "top_left_x": 0.10470486,
-          "top_left_y": 0.10470486,
-          "top_right_x": 0.10470486,
-          "top_right_y": 0.10470486,
-          "bottom_right_x": 0.20940971,
-          "bottom_right_y": 0.20940971,
-          "bottom_left_x": 0.20940971,
-          "bottom_left_y": 0.20940971
-        },
-        {
-          "top_left_x": 0.07550812,
-          "top_left_y": 0.07550812,
-          "top_right_x": 0.07550812,
-          "top_right_y": 0.07550812,
-          "bottom_right_x": 0.15101624,
-          "bottom_right_y": 0.15101624,
-          "bottom_left_x": 0.15101624,
-          "bottom_left_y": 0.15101624
-        }
-      ]
-    },
-    {
-      "name": "alpha",
-      "type": "int",
-      "data_points": [
-        0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
-        255,
-        255,
-        255,
-        249,
-        226,
-        192,
-        153,
-        112,
-        72,
-        34,
-        0,
-        0,
-        0
-      ]
-    }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenLaunching_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenLaunching_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenLaunching[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenLaunching_withSpring.actual.mp4"
-  }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withSpring.json
deleted file mode 100644
index 825190b..0000000
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withSpring.json
+++ /dev/null
@@ -1,384 +0,0 @@
-{
-  "frame_ids": [
-    0,
-    16,
-    32,
-    48,
-    64,
-    80,
-    96,
-    112,
-    128,
-    144,
-    160,
-    176,
-    192,
-    208,
-    224,
-    240,
-    256,
-    272,
-    288,
-    304
-  ],
-  "features": [
-    {
-      "name": "bounds",
-      "type": "rect",
-      "data_points": [
-        {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
-          "left": 104,
-          "top": 285,
-          "right": 215,
-          "bottom": 414
-        },
-        {
-          "left": 92,
-          "top": 252,
-          "right": 227,
-          "bottom": 447
-        },
-        {
-          "left": 77,
-          "top": 213,
-          "right": 242,
-          "bottom": 486
-        },
-        {
-          "left": 63,
-          "top": 175,
-          "right": 256,
-          "bottom": 524
-        },
-        {
-          "left": 50,
-          "top": 141,
-          "right": 269,
-          "bottom": 558
-        },
-        {
-          "left": 40,
-          "top": 112,
-          "right": 279,
-          "bottom": 587
-        },
-        {
-          "left": 31,
-          "top": 88,
-          "right": 288,
-          "bottom": 611
-        },
-        {
-          "left": 23,
-          "top": 68,
-          "right": 296,
-          "bottom": 631
-        },
-        {
-          "left": 18,
-          "top": 53,
-          "right": 301,
-          "bottom": 646
-        },
-        {
-          "left": 13,
-          "top": 41,
-          "right": 306,
-          "bottom": 658
-        },
-        {
-          "left": 10,
-          "top": 31,
-          "right": 309,
-          "bottom": 667
-        },
-        {
-          "left": 7,
-          "top": 24,
-          "right": 312,
-          "bottom": 673
-        },
-        {
-          "left": 5,
-          "top": 18,
-          "right": 314,
-          "bottom": 678
-        },
-        {
-          "left": 4,
-          "top": 13,
-          "right": 315,
-          "bottom": 681
-        },
-        {
-          "left": 3,
-          "top": 10,
-          "right": 316,
-          "bottom": 684
-        },
-        {
-          "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 685
-        },
-        {
-          "left": 1,
-          "top": 5,
-          "right": 318,
-          "bottom": 687
-        },
-        {
-          "left": 1,
-          "top": 4,
-          "right": 318,
-          "bottom": 688
-        },
-        {
-          "left": 0,
-          "top": 3,
-          "right": 319,
-          "bottom": 688
-        }
-      ]
-    },
-    {
-      "name": "corner_radii",
-      "type": "cornerRadii",
-      "data_points": [
-        null,
-        {
-          "top_left_x": 9.492916,
-          "top_left_y": 9.492916,
-          "top_right_x": 9.492916,
-          "top_right_y": 9.492916,
-          "bottom_right_x": 18.985832,
-          "bottom_right_y": 18.985832,
-          "bottom_left_x": 18.985832,
-          "bottom_left_y": 18.985832
-        },
-        {
-          "top_left_x": 8.381761,
-          "top_left_y": 8.381761,
-          "top_right_x": 8.381761,
-          "top_right_y": 8.381761,
-          "bottom_right_x": 16.763521,
-          "bottom_right_y": 16.763521,
-          "bottom_left_x": 16.763521,
-          "bottom_left_y": 16.763521
-        },
-        {
-          "top_left_x": 7.07397,
-          "top_left_y": 7.07397,
-          "top_right_x": 7.07397,
-          "top_right_y": 7.07397,
-          "bottom_right_x": 14.14794,
-          "bottom_right_y": 14.14794,
-          "bottom_left_x": 14.14794,
-          "bottom_left_y": 14.14794
-        },
-        {
-          "top_left_x": 5.7880254,
-          "top_left_y": 5.7880254,
-          "top_right_x": 5.7880254,
-          "top_right_y": 5.7880254,
-          "bottom_right_x": 11.576051,
-          "bottom_right_y": 11.576051,
-          "bottom_left_x": 11.576051,
-          "bottom_left_y": 11.576051
-        },
-        {
-          "top_left_x": 4.6295347,
-          "top_left_y": 4.6295347,
-          "top_right_x": 4.6295347,
-          "top_right_y": 4.6295347,
-          "bottom_right_x": 9.259069,
-          "bottom_right_y": 9.259069,
-          "bottom_left_x": 9.259069,
-          "bottom_left_y": 9.259069
-        },
-        {
-          "top_left_x": 3.638935,
-          "top_left_y": 3.638935,
-          "top_right_x": 3.638935,
-          "top_right_y": 3.638935,
-          "bottom_right_x": 7.27787,
-          "bottom_right_y": 7.27787,
-          "bottom_left_x": 7.27787,
-          "bottom_left_y": 7.27787
-        },
-        {
-          "top_left_x": 2.8209057,
-          "top_left_y": 2.8209057,
-          "top_right_x": 2.8209057,
-          "top_right_y": 2.8209057,
-          "bottom_right_x": 5.6418114,
-          "bottom_right_y": 5.6418114,
-          "bottom_left_x": 5.6418114,
-          "bottom_left_y": 5.6418114
-        },
-        {
-          "top_left_x": 2.1620893,
-          "top_left_y": 2.1620893,
-          "top_right_x": 2.1620893,
-          "top_right_y": 2.1620893,
-          "bottom_right_x": 4.3241787,
-          "bottom_right_y": 4.3241787,
-          "bottom_left_x": 4.3241787,
-          "bottom_left_y": 4.3241787
-        },
-        {
-          "top_left_x": 1.6414614,
-          "top_left_y": 1.6414614,
-          "top_right_x": 1.6414614,
-          "top_right_y": 1.6414614,
-          "bottom_right_x": 3.2829227,
-          "bottom_right_y": 3.2829227,
-          "bottom_left_x": 3.2829227,
-          "bottom_left_y": 3.2829227
-        },
-        {
-          "top_left_x": 1.2361269,
-          "top_left_y": 1.2361269,
-          "top_right_x": 1.2361269,
-          "top_right_y": 1.2361269,
-          "bottom_right_x": 2.4722538,
-          "bottom_right_y": 2.4722538,
-          "bottom_left_x": 2.4722538,
-          "bottom_left_y": 2.4722538
-        },
-        {
-          "top_left_x": 0.92435074,
-          "top_left_y": 0.92435074,
-          "top_right_x": 0.92435074,
-          "top_right_y": 0.92435074,
-          "bottom_right_x": 1.8487015,
-          "bottom_right_y": 1.8487015,
-          "bottom_left_x": 1.8487015,
-          "bottom_left_y": 1.8487015
-        },
-        {
-          "top_left_x": 0.68693924,
-          "top_left_y": 0.68693924,
-          "top_right_x": 0.68693924,
-          "top_right_y": 0.68693924,
-          "bottom_right_x": 1.3738785,
-          "bottom_right_y": 1.3738785,
-          "bottom_left_x": 1.3738785,
-          "bottom_left_y": 1.3738785
-        },
-        {
-          "top_left_x": 0.5076904,
-          "top_left_y": 0.5076904,
-          "top_right_x": 0.5076904,
-          "top_right_y": 0.5076904,
-          "bottom_right_x": 1.0153809,
-          "bottom_right_y": 1.0153809,
-          "bottom_left_x": 1.0153809,
-          "bottom_left_y": 1.0153809
-        },
-        {
-          "top_left_x": 0.3733511,
-          "top_left_y": 0.3733511,
-          "top_right_x": 0.3733511,
-          "top_right_y": 0.3733511,
-          "bottom_right_x": 0.7467022,
-          "bottom_right_y": 0.7467022,
-          "bottom_left_x": 0.7467022,
-          "bottom_left_y": 0.7467022
-        },
-        {
-          "top_left_x": 0.27331638,
-          "top_left_y": 0.27331638,
-          "top_right_x": 0.27331638,
-          "top_right_y": 0.27331638,
-          "bottom_right_x": 0.54663277,
-          "bottom_right_y": 0.54663277,
-          "bottom_left_x": 0.54663277,
-          "bottom_left_y": 0.54663277
-        },
-        {
-          "top_left_x": 0.19925308,
-          "top_left_y": 0.19925308,
-          "top_right_x": 0.19925308,
-          "top_right_y": 0.19925308,
-          "bottom_right_x": 0.39850616,
-          "bottom_right_y": 0.39850616,
-          "bottom_left_x": 0.39850616,
-          "bottom_left_y": 0.39850616
-        },
-        {
-          "top_left_x": 0.14470005,
-          "top_left_y": 0.14470005,
-          "top_right_x": 0.14470005,
-          "top_right_y": 0.14470005,
-          "bottom_right_x": 0.2894001,
-          "bottom_right_y": 0.2894001,
-          "bottom_left_x": 0.2894001,
-          "bottom_left_y": 0.2894001
-        },
-        {
-          "top_left_x": 0.10470486,
-          "top_left_y": 0.10470486,
-          "top_right_x": 0.10470486,
-          "top_right_y": 0.10470486,
-          "bottom_right_x": 0.20940971,
-          "bottom_right_y": 0.20940971,
-          "bottom_left_x": 0.20940971,
-          "bottom_left_y": 0.20940971
-        },
-        {
-          "top_left_x": 0.07550812,
-          "top_left_y": 0.07550812,
-          "top_right_x": 0.07550812,
-          "top_right_y": 0.07550812,
-          "bottom_right_x": 0.15101624,
-          "bottom_right_y": 0.15101624,
-          "bottom_left_x": 0.15101624,
-          "bottom_left_y": 0.15101624
-        }
-      ]
-    },
-    {
-      "name": "alpha",
-      "type": "int",
-      "data_points": [
-        0,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        249,
-        226,
-        192,
-        153,
-        112,
-        72,
-        34,
-        0,
-        0,
-        0
-      ]
-    }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimationWithoutFade_whenLaunching_withSpring.json",
-    "goldenIdentifier": "backgroundAnimationWithoutFade_whenLaunching_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimationWithoutFade_whenLaunching[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimationWithoutFade_whenLaunching_withSpring.actual.mp4"
-  }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withSpring.json
deleted file mode 100644
index 63c2631..0000000
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withSpring.json
+++ /dev/null
@@ -1,384 +0,0 @@
-{
-  "frame_ids": [
-    0,
-    16,
-    32,
-    48,
-    64,
-    80,
-    96,
-    112,
-    128,
-    144,
-    160,
-    176,
-    192,
-    208,
-    224,
-    240,
-    256,
-    272,
-    288,
-    304
-  ],
-  "features": [
-    {
-      "name": "bounds",
-      "type": "rect",
-      "data_points": [
-        {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
-          "left": 104,
-          "top": 285,
-          "right": 215,
-          "bottom": 414
-        },
-        {
-          "left": 92,
-          "top": 252,
-          "right": 227,
-          "bottom": 447
-        },
-        {
-          "left": 77,
-          "top": 213,
-          "right": 242,
-          "bottom": 486
-        },
-        {
-          "left": 63,
-          "top": 175,
-          "right": 256,
-          "bottom": 524
-        },
-        {
-          "left": 50,
-          "top": 141,
-          "right": 269,
-          "bottom": 558
-        },
-        {
-          "left": 40,
-          "top": 112,
-          "right": 279,
-          "bottom": 587
-        },
-        {
-          "left": 31,
-          "top": 88,
-          "right": 288,
-          "bottom": 611
-        },
-        {
-          "left": 23,
-          "top": 68,
-          "right": 296,
-          "bottom": 631
-        },
-        {
-          "left": 18,
-          "top": 53,
-          "right": 301,
-          "bottom": 646
-        },
-        {
-          "left": 13,
-          "top": 41,
-          "right": 306,
-          "bottom": 658
-        },
-        {
-          "left": 10,
-          "top": 31,
-          "right": 309,
-          "bottom": 667
-        },
-        {
-          "left": 7,
-          "top": 24,
-          "right": 312,
-          "bottom": 673
-        },
-        {
-          "left": 5,
-          "top": 18,
-          "right": 314,
-          "bottom": 678
-        },
-        {
-          "left": 4,
-          "top": 13,
-          "right": 315,
-          "bottom": 681
-        },
-        {
-          "left": 3,
-          "top": 10,
-          "right": 316,
-          "bottom": 684
-        },
-        {
-          "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 685
-        },
-        {
-          "left": 1,
-          "top": 5,
-          "right": 318,
-          "bottom": 687
-        },
-        {
-          "left": 1,
-          "top": 4,
-          "right": 318,
-          "bottom": 688
-        },
-        {
-          "left": 0,
-          "top": 3,
-          "right": 319,
-          "bottom": 688
-        }
-      ]
-    },
-    {
-      "name": "corner_radii",
-      "type": "cornerRadii",
-      "data_points": [
-        null,
-        {
-          "top_left_x": 9.492916,
-          "top_left_y": 9.492916,
-          "top_right_x": 9.492916,
-          "top_right_y": 9.492916,
-          "bottom_right_x": 18.985832,
-          "bottom_right_y": 18.985832,
-          "bottom_left_x": 18.985832,
-          "bottom_left_y": 18.985832
-        },
-        {
-          "top_left_x": 8.381761,
-          "top_left_y": 8.381761,
-          "top_right_x": 8.381761,
-          "top_right_y": 8.381761,
-          "bottom_right_x": 16.763521,
-          "bottom_right_y": 16.763521,
-          "bottom_left_x": 16.763521,
-          "bottom_left_y": 16.763521
-        },
-        {
-          "top_left_x": 7.07397,
-          "top_left_y": 7.07397,
-          "top_right_x": 7.07397,
-          "top_right_y": 7.07397,
-          "bottom_right_x": 14.14794,
-          "bottom_right_y": 14.14794,
-          "bottom_left_x": 14.14794,
-          "bottom_left_y": 14.14794
-        },
-        {
-          "top_left_x": 5.7880254,
-          "top_left_y": 5.7880254,
-          "top_right_x": 5.7880254,
-          "top_right_y": 5.7880254,
-          "bottom_right_x": 11.576051,
-          "bottom_right_y": 11.576051,
-          "bottom_left_x": 11.576051,
-          "bottom_left_y": 11.576051
-        },
-        {
-          "top_left_x": 4.6295347,
-          "top_left_y": 4.6295347,
-          "top_right_x": 4.6295347,
-          "top_right_y": 4.6295347,
-          "bottom_right_x": 9.259069,
-          "bottom_right_y": 9.259069,
-          "bottom_left_x": 9.259069,
-          "bottom_left_y": 9.259069
-        },
-        {
-          "top_left_x": 3.638935,
-          "top_left_y": 3.638935,
-          "top_right_x": 3.638935,
-          "top_right_y": 3.638935,
-          "bottom_right_x": 7.27787,
-          "bottom_right_y": 7.27787,
-          "bottom_left_x": 7.27787,
-          "bottom_left_y": 7.27787
-        },
-        {
-          "top_left_x": 2.8209057,
-          "top_left_y": 2.8209057,
-          "top_right_x": 2.8209057,
-          "top_right_y": 2.8209057,
-          "bottom_right_x": 5.6418114,
-          "bottom_right_y": 5.6418114,
-          "bottom_left_x": 5.6418114,
-          "bottom_left_y": 5.6418114
-        },
-        {
-          "top_left_x": 2.1620893,
-          "top_left_y": 2.1620893,
-          "top_right_x": 2.1620893,
-          "top_right_y": 2.1620893,
-          "bottom_right_x": 4.3241787,
-          "bottom_right_y": 4.3241787,
-          "bottom_left_x": 4.3241787,
-          "bottom_left_y": 4.3241787
-        },
-        {
-          "top_left_x": 1.6414614,
-          "top_left_y": 1.6414614,
-          "top_right_x": 1.6414614,
-          "top_right_y": 1.6414614,
-          "bottom_right_x": 3.2829227,
-          "bottom_right_y": 3.2829227,
-          "bottom_left_x": 3.2829227,
-          "bottom_left_y": 3.2829227
-        },
-        {
-          "top_left_x": 1.2361269,
-          "top_left_y": 1.2361269,
-          "top_right_x": 1.2361269,
-          "top_right_y": 1.2361269,
-          "bottom_right_x": 2.4722538,
-          "bottom_right_y": 2.4722538,
-          "bottom_left_x": 2.4722538,
-          "bottom_left_y": 2.4722538
-        },
-        {
-          "top_left_x": 0.92435074,
-          "top_left_y": 0.92435074,
-          "top_right_x": 0.92435074,
-          "top_right_y": 0.92435074,
-          "bottom_right_x": 1.8487015,
-          "bottom_right_y": 1.8487015,
-          "bottom_left_x": 1.8487015,
-          "bottom_left_y": 1.8487015
-        },
-        {
-          "top_left_x": 0.68693924,
-          "top_left_y": 0.68693924,
-          "top_right_x": 0.68693924,
-          "top_right_y": 0.68693924,
-          "bottom_right_x": 1.3738785,
-          "bottom_right_y": 1.3738785,
-          "bottom_left_x": 1.3738785,
-          "bottom_left_y": 1.3738785
-        },
-        {
-          "top_left_x": 0.5076904,
-          "top_left_y": 0.5076904,
-          "top_right_x": 0.5076904,
-          "top_right_y": 0.5076904,
-          "bottom_right_x": 1.0153809,
-          "bottom_right_y": 1.0153809,
-          "bottom_left_x": 1.0153809,
-          "bottom_left_y": 1.0153809
-        },
-        {
-          "top_left_x": 0.3733511,
-          "top_left_y": 0.3733511,
-          "top_right_x": 0.3733511,
-          "top_right_y": 0.3733511,
-          "bottom_right_x": 0.7467022,
-          "bottom_right_y": 0.7467022,
-          "bottom_left_x": 0.7467022,
-          "bottom_left_y": 0.7467022
-        },
-        {
-          "top_left_x": 0.27331638,
-          "top_left_y": 0.27331638,
-          "top_right_x": 0.27331638,
-          "top_right_y": 0.27331638,
-          "bottom_right_x": 0.54663277,
-          "bottom_right_y": 0.54663277,
-          "bottom_left_x": 0.54663277,
-          "bottom_left_y": 0.54663277
-        },
-        {
-          "top_left_x": 0.19925308,
-          "top_left_y": 0.19925308,
-          "top_right_x": 0.19925308,
-          "top_right_y": 0.19925308,
-          "bottom_right_x": 0.39850616,
-          "bottom_right_y": 0.39850616,
-          "bottom_left_x": 0.39850616,
-          "bottom_left_y": 0.39850616
-        },
-        {
-          "top_left_x": 0.14470005,
-          "top_left_y": 0.14470005,
-          "top_right_x": 0.14470005,
-          "top_right_y": 0.14470005,
-          "bottom_right_x": 0.2894001,
-          "bottom_right_y": 0.2894001,
-          "bottom_left_x": 0.2894001,
-          "bottom_left_y": 0.2894001
-        },
-        {
-          "top_left_x": 0.10470486,
-          "top_left_y": 0.10470486,
-          "top_right_x": 0.10470486,
-          "top_right_y": 0.10470486,
-          "bottom_right_x": 0.20940971,
-          "bottom_right_y": 0.20940971,
-          "bottom_left_x": 0.20940971,
-          "bottom_left_y": 0.20940971
-        },
-        {
-          "top_left_x": 0.07550812,
-          "top_left_y": 0.07550812,
-          "top_right_x": 0.07550812,
-          "top_right_y": 0.07550812,
-          "bottom_right_x": 0.15101624,
-          "bottom_right_y": 0.15101624,
-          "bottom_left_x": 0.15101624,
-          "bottom_left_y": 0.15101624
-        }
-      ]
-    },
-    {
-      "name": "alpha",
-      "type": "int",
-      "data_points": [
-        0,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        249,
-        226,
-        192,
-        153,
-        112,
-        72,
-        34,
-        0,
-        0,
-        0
-      ]
-    }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimationWithoutFade_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimationWithoutFade_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimationWithoutFade_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimationWithoutFade_whenReturning_withSpring.actual.mp4"
-  }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
index a1f59c2..1268de0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
@@ -23,11 +23,14 @@
 import android.graphics.Color
 import android.graphics.PointF
 import android.graphics.drawable.GradientDrawable
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.platform.test.annotations.MotionTest
 import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.activity.EmptyTestActivity
 import com.android.systemui.concurrency.fakeExecutor
@@ -45,25 +48,29 @@
 import platform.test.runner.parameterized.Parameters
 import platform.test.screenshot.GoldenPathManager
 import platform.test.screenshot.PathConfig
+import platform.test.screenshot.PathElementNoContext
 
 @SmallTest
 @MotionTest
 @RunWith(ParameterizedAndroidJunit4::class)
 class TransitionAnimatorTest(
     private val fadeWindowBackgroundLayer: Boolean,
+    private val drawHole: Boolean,
     private val isLaunching: Boolean,
     private val useSpring: Boolean,
 ) : SysuiTestCase() {
     companion object {
         private const val GOLDENS_PATH = "frameworks/base/packages/SystemUI/tests/goldens"
 
-        @get:Parameters(name = "fadeBackground={0}, isLaunching={1}, useSpring={2}")
+        @get:Parameters(name = "fadeBackground={0}, drawHole={1}, isLaunching={2}, useSpring={3}")
         @JvmStatic
         val parameterValues = buildList {
             booleanArrayOf(true, false).forEach { fadeBackground ->
-                booleanArrayOf(true, false).forEach { isLaunching ->
-                    booleanArrayOf(true, false).forEach { useSpring ->
-                        add(arrayOf(fadeBackground, isLaunching, useSpring))
+                booleanArrayOf(true, false).forEach { drawHole ->
+                    booleanArrayOf(true, false).forEach { isLaunching ->
+                        booleanArrayOf(true, false).forEach { useSpring ->
+                            add(arrayOf(fadeBackground, drawHole, isLaunching, useSpring))
+                        }
                     }
                 }
             }
@@ -71,7 +78,44 @@
     }
 
     private val kosmos = Kosmos()
-    private val pathManager = GoldenPathManager(context, GOLDENS_PATH, pathConfig = PathConfig())
+    private val pathManager =
+        GoldenPathManager(
+            context,
+            GOLDENS_PATH,
+            pathConfig =
+                PathConfig(
+                    PathElementNoContext("base", isDir = true) { "animations" },
+                    PathElementNoContext("fade", isDir = false) {
+                        if (fadeWindowBackgroundLayer) {
+                            "withFade"
+                        } else {
+                            "withoutFade"
+                        }
+                    },
+                    PathElementNoContext("hole", isDir = false) {
+                        if (drawHole) {
+                            "withHole"
+                        } else {
+                            "withoutHole"
+                        }
+                    },
+                    PathElementNoContext("direction", isDir = false) {
+                        if (isLaunching) {
+                            "whenLaunching"
+                        } else {
+                            "whenReturning"
+                        }
+                    },
+                    PathElementNoContext("mode", isDir = false) {
+                        if (useSpring) {
+                            "withSpring"
+                        } else {
+                            "withAnimator"
+                        }
+                    },
+                ),
+        )
+
     private val transitionAnimator =
         TransitionAnimator(
             kosmos.fakeExecutor,
@@ -80,24 +124,6 @@
             ActivityTransitionAnimator.SPRING_TIMINGS,
             ActivityTransitionAnimator.SPRING_INTERPOLATORS,
         )
-    private val fade =
-        if (fadeWindowBackgroundLayer) {
-            "withFade"
-        } else {
-            "withoutFade"
-        }
-    private val direction =
-        if (isLaunching) {
-            "whenLaunching"
-        } else {
-            "whenReturning"
-        }
-    private val mode =
-        if (useSpring) {
-            "withSpring"
-        } else {
-            "withAnimator"
-        }
 
     @get:Rule(order = 1) val activityRule = ActivityScenarioRule(EmptyTestActivity::class.java)
     @get:Rule(order = 2) val animatorTestRule = android.animation.AnimatorTestRule(this)
@@ -108,6 +134,7 @@
             pathManager,
         )
 
+    @DisableFlags(Flags.FLAG_MOVE_TRANSITION_ANIMATION_LAYER)
     @Test
     fun backgroundAnimationTimeSeries() {
         val transitionContainer = createScene()
@@ -118,7 +145,21 @@
 
         motionRule
             .assertThat(recordedMotion)
-            .timeSeriesMatchesGolden("backgroundAnimationTimeSeries_${fade}_${direction}_$mode")
+            .timeSeriesMatchesGolden("backgroundAnimationTimeSeries")
+    }
+
+    @EnableFlags(Flags.FLAG_MOVE_TRANSITION_ANIMATION_LAYER)
+    @Test
+    fun backgroundAnimationTimeSeries_drawHoleAfterFadeout() {
+        val transitionContainer = createScene()
+        val backgroundLayer = createBackgroundLayer()
+        val animation = createAnimation(transitionContainer, backgroundLayer)
+
+        val recordedMotion = record(backgroundLayer, animation)
+
+        motionRule
+            .assertThat(recordedMotion)
+            .timeSeriesMatchesGolden("backgroundAnimationTimeSeries_drawHoleAfterFadeout")
     }
 
     private fun createScene(): ViewGroup {
@@ -169,6 +210,7 @@
                 endState,
                 backgroundLayer,
                 fadeWindowBackgroundLayer,
+                drawHole,
                 startVelocity = startVelocity,
             )
             .apply { runOnMainThreadAndWaitForIdleSync { start() } }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
index 7c8822b..96ef8b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
@@ -18,8 +18,6 @@
 
 import android.bluetooth.BluetoothDevice
 import android.graphics.drawable.Drawable
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
 import android.testing.TestableLooper
 import android.util.Pair
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -29,7 +27,6 @@
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
-import com.android.settingslib.flags.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.res.R
 import com.google.common.truth.Truth.assertThat
@@ -208,42 +205,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testSavedFactory_isFilterMatched_bondedAndNotConnected_returnsTrue() {
-        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
-        `when`(cachedDevice.isConnected).thenReturn(false)
-
-        assertThat(
-                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
-            )
-            .isTrue()
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testSavedFactory_isFilterMatched_connected_returnsFalse() {
-        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
-        `when`(cachedDevice.isConnected).thenReturn(true)
-
-        assertThat(
-                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
-            )
-            .isFalse()
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() {
-        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
-
-        assertThat(
-                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
-            )
-            .isFalse()
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testSavedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true)
@@ -255,7 +216,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testSavedFactory_isFilterMatched_notExclusiveManaged_returnsTrue() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
@@ -269,7 +229,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testSavedFactory_isFilterMatched_notExclusivelyManaged_connected_returnsFalse() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
@@ -283,35 +242,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() {
-        `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(true)
-
-        assertThat(
-                connectedDeviceItemFactory.isFilterMatched(
-                    context,
-                    cachedDevice,
-                    isOngoingCall = false,
-                )
-            )
-            .isTrue()
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testConnectedFactory_isFilterMatched_notConnected_returnsFalse() {
-        assertThat(
-                connectedDeviceItemFactory.isFilterMatched(
-                    context,
-                    cachedDevice,
-                    isOngoingCall = false,
-                )
-            )
-            .isFalse()
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testConnectedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true)
@@ -327,7 +257,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testConnectedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
@@ -344,7 +273,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notConnected_returnsFalse() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index 5624815..5c893da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -28,7 +28,6 @@
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_EXPANDED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_MINIMIZED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
-import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -60,7 +59,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.screenshot.TimeoutHandler;
 import com.android.systemui.settings.FakeDisplayTracker;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -102,7 +100,6 @@
     @Mock
     private UiEventLogger mUiEventLogger;
     private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
-    private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
 
     @Mock
     private Animator mAnimator;
@@ -152,8 +149,6 @@
 
         mSampleClipData = new ClipData("Test", new String[]{"text/plain"},
                 new ClipData.Item("Test Item"));
-
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, true); // turned off for legacy tests
     }
 
     /**
@@ -170,13 +165,13 @@
                 getFakeBroadcastDispatcher(),
                 mBroadcastSender,
                 mTimeoutHandler,
-                mFeatureFlags,
                 mClipboardUtils,
                 mExecutor,
                 mClipboardImageLoader,
                 mClipboardTransitionExecutor,
                 mClipboardIndicationProvider,
-                mUiEventLogger);
+                mUiEventLogger,
+                new ActionIntentCreator());
         verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
         mCallbacks = mOverlayCallbacksCaptor.getValue();
     }
@@ -193,7 +188,6 @@
 
         ClipData clipData = new ClipData("", new String[]{"image/png"},
                 new ClipData.Item(Uri.parse("")));
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
 
         mOverlayController.setClipData(clipData, "");
 
@@ -208,7 +202,6 @@
 
         ClipData clipData = new ClipData("", new String[]{"resource/png"},
                 new ClipData.Item(Uri.parse("")));
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
 
         mOverlayController.setClipData(clipData, "");
 
@@ -219,7 +212,6 @@
 
     @Test
     public void test_setClipData_textData_legacy() {
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
         initController();
 
         mOverlayController.setClipData(mSampleClipData, "abc");
@@ -232,7 +224,6 @@
 
     @Test
     public void test_setClipData_sensitiveTextData_legacy() {
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
         initController();
 
         ClipDescription description = mSampleClipData.getDescription();
@@ -250,7 +241,6 @@
     @Test
     public void test_setClipData_repeatedCalls_legacy() {
         when(mAnimator.isRunning()).thenReturn(true);
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
         initController();
 
         mOverlayController.setClipData(mSampleClipData, "");
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 e8054c0..8105ae0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -283,7 +283,6 @@
                 () -> mSelectedUserInteractor,
                 mock(UserTracker.class),
                 mKosmos.getNotificationShadeWindowModel(),
-                mSecureSettings,
                 mKosmos::getCommunalInteractor,
                 mKosmos.getShadeLayoutParams());
         mFeatureFlags = new FakeFeatureFlags();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 205ccea..9ad2235 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -406,11 +406,6 @@
         }
 
         @Override
-        int getHeaderIconSize() {
-            return 10;
-        }
-
-        @Override
         CharSequence getHeaderText() {
             return mHeaderTitle;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
index f0902e3..f1bf7c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
@@ -50,6 +50,7 @@
 import com.android.settingslib.media.BluetoothMediaDevice;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestCaseExtKt;
 import com.android.systemui.animation.DialogTransitionAnimator;
@@ -152,9 +153,9 @@
                         volumePanelGlobalStateInteractor,
                         mUserTracker);
         mMediaSwitchingController.mLocalMediaManager = mLocalMediaManager;
-        mMediaOutputBroadcastDialog =
-                new MediaOutputBroadcastDialog(
-                        mContext, false, mBroadcastSender, mMediaSwitchingController);
+        mMediaOutputBroadcastDialog = new MediaOutputBroadcastDialog(mContext, false,
+                mBroadcastSender, mMediaSwitchingController, mContext.getMainExecutor(),
+                ThreadUtils.getBackgroundExecutor());
         mMediaOutputBroadcastDialog.show();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index d3ecb3d..420fd6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -53,6 +53,7 @@
 import com.android.settingslib.flags.Flags;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestCaseExtKt;
 import com.android.systemui.animation.DialogTransitionAnimator;
@@ -455,6 +456,8 @@
                 controller,
                 mDialogTransitionAnimator,
                 mUiEventLogger,
+                mContext.getMainExecutor(),
+                ThreadUtils.getBackgroundExecutor(),
                 true);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt
index 0a5efb7..155059e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
+import com.android.systemui.log.assertLogsWtf
 import com.android.systemui.model.sysUiState
 import com.android.systemui.navigationbar.NavigationBarController
 import com.android.systemui.navigationbar.NavigationModeController
@@ -162,8 +163,7 @@
         wakefulnessLifecycle.dispatchFinishedGoingToSleep()
         clearInvocations(launcherProxy)
 
-        wakefulnessLifecycle
-            .dispatchFinishedWakingUp()
+        wakefulnessLifecycle.dispatchFinishedWakingUp()
 
         verify(launcherProxy)
             .onSystemUiStateChanged(
@@ -222,7 +222,7 @@
         `when`(processWrapper.isSystemUser).thenReturn(false)
         `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false)
         val spyContext = spy(context)
-        val ops = createLauncherProxyService(spyContext)
+        val ops = assertLogsWtf { createLauncherProxyService(spyContext) }.result
         ops.startConnectionToCurrentUser()
         verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any())
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
index a64ff321..11aaeef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
@@ -134,10 +134,7 @@
         val frame = activityRule.activity.requireViewById<View>(viewId)
 
         val lp = frame.layoutParams as ViewGroup.MarginLayoutParams
-        val horizontalMargin =
-            activityRule.activity.resources.getDimensionPixelSize(
-                R.dimen.notification_side_paddings
-            )
+        val horizontalMargin = 0
         assertThat(lp.leftMargin).isEqualTo(horizontalMargin)
         assertThat(lp.rightMargin).isEqualTo(horizontalMargin)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
index 8418598..116a2ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
@@ -19,9 +19,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.shared.condition.Condition.START_EAGERLY
-import com.android.systemui.shared.condition.Condition.START_LAZILY
-import com.android.systemui.shared.condition.Condition.START_WHEN_NEEDED
+import com.android.systemui.shared.condition.Condition.Companion.START_EAGERLY
+import com.android.systemui.shared.condition.Condition.Companion.START_LAZILY
+import com.android.systemui.shared.condition.Condition.Companion.START_WHEN_NEEDED
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -40,7 +40,7 @@
         scope: CoroutineScope,
         initialValue: Boolean?,
         overriding: Boolean = false,
-        @StartStrategy private val startStrategy: Int = START_WHEN_NEEDED,
+        @StartStrategy override val startStrategy: Int = START_WHEN_NEEDED,
     ) : Condition(scope, initialValue, overriding) {
         private var _started = false
         val started: Boolean
@@ -54,10 +54,6 @@
             _started = false
         }
 
-        override fun getStartStrategy(): Int {
-            return startStrategy
-        }
-
         fun setValue(value: Boolean?) {
             value?.also { updateCondition(value) } ?: clearCondition()
         }
@@ -75,13 +71,8 @@
         val combinedCondition =
             CombinedCondition(
                 scope = this,
-                conditions =
-                    listOf(
-                        eagerCondition,
-                        lazyCondition,
-                        startWhenNeededCondition,
-                    ),
-                operand = Evaluator.OP_OR
+                conditions = listOf(eagerCondition, lazyCondition, startWhenNeededCondition),
+                operand = Evaluator.OP_OR,
             )
 
         val callback = Condition.Callback {}
@@ -124,13 +115,8 @@
         val combinedCondition =
             CombinedCondition(
                 scope = this,
-                conditions =
-                    listOf(
-                        startWhenNeededCondition,
-                        lazyCondition,
-                        eagerCondition,
-                    ),
-                operand = Evaluator.OP_AND
+                conditions = listOf(startWhenNeededCondition, lazyCondition, eagerCondition),
+                operand = Evaluator.OP_AND,
             )
 
         val callback = Condition.Callback {}
@@ -175,7 +161,7 @@
                     FakeCondition(
                         scope = this,
                         initialValue = false,
-                        startStrategy = START_WHEN_NEEDED
+                        startStrategy = START_WHEN_NEEDED,
                     )
                 }
                 .toList()
@@ -214,7 +200,7 @@
                     FakeCondition(
                         scope = this,
                         initialValue = false,
-                        startStrategy = START_WHEN_NEEDED
+                        startStrategy = START_WHEN_NEEDED,
                     )
                 }
                 .toList()
@@ -262,7 +248,7 @@
                     FakeCondition(
                         scope = this,
                         initialValue = false,
-                        startStrategy = START_WHEN_NEEDED
+                        startStrategy = START_WHEN_NEEDED,
                     )
                 }
                 .toList()
@@ -300,9 +286,9 @@
                         overridingCondition1,
                         lazyCondition,
                         startWhenNeededCondition,
-                        overridingCondition2
+                        overridingCondition2,
                     ),
-                operand = Evaluator.OP_OR
+                operand = Evaluator.OP_OR,
             )
 
         val callback = Condition.Callback {}
@@ -414,11 +400,7 @@
     fun testEmptyConditions() = runSelfCancelingTest {
         for (operand in intArrayOf(Evaluator.OP_OR, Evaluator.OP_AND)) {
             val combinedCondition =
-                CombinedCondition(
-                    scope = this,
-                    conditions = emptyList(),
-                    operand = operand,
-                )
+                CombinedCondition(scope = this, conditions = emptyList(), operand = operand)
 
             val callback = Condition.Callback {}
             combinedCondition.addCallback(callback)
@@ -435,9 +417,7 @@
      * Executes the given block of execution within the scope of a dedicated [CoroutineScope] which
      * is then automatically canceled and cleaned-up.
      */
-    private fun runSelfCancelingTest(
-        block: suspend CoroutineScope.() -> Unit,
-    ) =
+    private fun runSelfCancelingTest(block: suspend CoroutineScope.() -> Unit) =
         runBlocking(IMMEDIATE) {
             val scope = CoroutineScope(coroutineContext + Job())
             block(scope)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 81213ca..3570cf8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -77,7 +77,6 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -1795,7 +1794,7 @@
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
 
         // THEN an exception is NOT thrown directly, but a WTF IS logged.
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             dispatchBuild();
             runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
         });
@@ -1818,7 +1817,7 @@
         addNotif(0, PACKAGE_2);
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
 
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             Assert.assertThrows(IllegalStateException.class, () -> {
                 dispatchBuild();
                 runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
@@ -1844,13 +1843,13 @@
         addNotif(0, PACKAGE_2);
 
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             dispatchBuild();
             runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
         });
 
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             // Note: dispatchBuild itself triggers a non-reentrant pipeline run.
             dispatchBuild();
             runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
@@ -1874,7 +1873,7 @@
         addNotif(0, PACKAGE_1);
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
 
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             dispatchBuild();
             runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
         });
@@ -1897,7 +1896,7 @@
         addNotif(0, PACKAGE_1);
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
 
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             Assert.assertThrows(IllegalStateException.class, () -> {
                 dispatchBuild();
                 runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
@@ -1922,7 +1921,7 @@
         addNotif(0, PACKAGE_2);
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
 
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             dispatchBuild();
             runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
         });
@@ -1945,7 +1944,7 @@
         addNotif(0, PACKAGE_2);
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
 
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             Assert.assertThrows(IllegalStateException.class, () -> {
                 dispatchBuild();
                 runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
@@ -1970,7 +1969,7 @@
         addNotif(0, PACKAGE_2);
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
 
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             dispatchBuild();
             runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
         });
@@ -1993,7 +1992,7 @@
         addNotif(0, PACKAGE_2);
         invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
 
-        LogAssertKt.assertLogsWtfs(() -> {
+        LogAssertKt.assertRunnableLogsWtfs(() -> {
             Assert.assertThrows(IllegalStateException.class, () -> {
                 dispatchBuild();
                 runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
index 86689cb..d035760 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
@@ -21,6 +21,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod
+import com.android.systemui.statusbar.notification.row.shared.IconData
 import com.android.systemui.statusbar.notification.row.shared.ImageModel
 import com.android.systemui.statusbar.notification.row.shared.ImageModelProvider.ImageSizeClass.SmallSquare
 import com.google.common.truth.Truth.assertThat
@@ -38,20 +39,22 @@
     private val resIcon2 = Icon.createWithResource(context, android.R.drawable.ic_delete)
     private val badUriIcon = Icon.createWithContentUri("content://com.test/does_not_exist")
 
+    private var latestImageModelIndex: ImageModelIndex? = null
+
     @Before
     fun setUp() {
-        rowImageInflater = RowImageInflater.newInstance(null)
+        rowImageInflater = RowImageInflater.newInstance(null, reinflating = false)
     }
 
     @Test
     fun getNewImageIndex_returnsNullWhenUnused() {
-        assertThat(rowImageInflater.getNewImageIndex()).isNull()
+        assertThat(getNewImageIndex()).isNull()
     }
 
     @Test
     fun getNewImageIndex_returnsEmptyIndexWhenZeroImagesLoaded() {
         assertThat(getImageModelsForIcons()).isEmpty()
-        val result = rowImageInflater.getNewImageIndex()
+        val result = getNewImageIndex()
         assertThat(result).isNotNull()
         assertThat(result?.contentsForTesting).isEmpty()
     }
@@ -59,7 +62,7 @@
     @Test
     fun getNewImageIndex_returnsSingleImageWhenOneImageLoaded() {
         assertThat(getImageModelsForIcons(resIcon1)).hasSize(1)
-        val result = rowImageInflater.getNewImageIndex()
+        val result = getNewImageIndex()
         assertThat(result).isNotNull()
         assertThat(result?.contentsForTesting).hasSize(1)
     }
@@ -85,7 +88,7 @@
         assertThat(providedModels[3].drawable).isNotNull()
 
         // VERIFY the returned index has all 3 entries, 2 of which have drawables
-        val indexGen1 = rowImageInflater.getNewImageIndex()
+        val indexGen1 = getNewImageIndex()
         assertThat(indexGen1).isNotNull()
         assertThat(indexGen1?.contentsForTesting).hasSize(3)
         assertThat(indexGen1?.contentsForTesting?.mapNotNull { it.drawable }).hasSize(2)
@@ -96,7 +99,7 @@
         exampleFirstGeneration()
 
         // THEN start a new generation of the inflation
-        rowImageInflater = RowImageInflater.newInstance(rowImageInflater.getNewImageIndex())
+        rowImageInflater = RowImageInflater.newInstance(getNewImageIndex(), reinflating = false)
 
         getNewImageIndex_returnsEmptyIndexWhenZeroImagesLoaded()
     }
@@ -104,13 +107,47 @@
     @Test
     fun exampleSecondGeneration_whichLoadsOneImage() {
         exampleFirstGeneration()
+        val gen1Index = latestImageModelIndex!!
 
         // THEN start a new generation of the inflation
-        rowImageInflater = RowImageInflater.newInstance(rowImageInflater.getNewImageIndex())
+        rowImageInflater = RowImageInflater.newInstance(gen1Index, reinflating = false)
 
         getNewImageIndex_returnsSingleImageWhenOneImageLoaded()
+        val gen2Index = latestImageModelIndex!!
+
+        // VERIFY that the drawable was copied from the previous index
+        val gen1model = gen1Index.findModel(resIcon1)
+        val gen2model = gen2Index.findModel(resIcon1)
+        assertThat(gen2model).isNotSameInstanceAs(gen1model)
+        assertThat(gen2model.drawable).isSameInstanceAs(gen1model.drawable)
     }
 
+    @Test
+    fun exampleSecondGeneration_reinflating_whichLoadsOneImage() {
+        exampleFirstGeneration()
+        val gen1Index = latestImageModelIndex!!
+
+        // THEN start a new generation of the inflation
+        rowImageInflater = RowImageInflater.newInstance(gen1Index, reinflating = true)
+
+        getNewImageIndex_returnsSingleImageWhenOneImageLoaded()
+        val gen2Index = latestImageModelIndex!!
+
+        // VERIFY that the drawable was reloaded rather than copied from the previous index
+        val gen1model = gen1Index.findModel(resIcon1)
+        val gen2model = gen2Index.findModel(resIcon1)
+        assertThat(gen2model).isNotSameInstanceAs(gen1model)
+        assertThat(gen2model.drawable).isNotSameInstanceAs(gen1model.drawable)
+    }
+
+    private fun ImageModelIndex.findModel(icon: Icon): LazyImage =
+        IconData.fromIcon(icon)
+            .let { iconData -> contentsForTesting.find { it.icon == iconData } }
+            .also { assertThat(it).isNotNull() }!!
+
+    private fun getNewImageIndex(): ImageModelIndex? =
+        rowImageInflater.getNewImageIndex().also { latestImageModelIndex = it }
+
     private fun getImageModelsForIcons(vararg icons: Icon): List<ImageModel> {
         val provider = rowImageInflater.useForContentModel()
         return icons.map { icon ->
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 89b7bee..a3616d2 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
@@ -128,6 +128,7 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.kosmos.KosmosJavaAdapter;
+import com.android.systemui.media.NotificationMediaManager;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.notetask.NoteTaskController;
 import com.android.systemui.plugins.ActivityStarter;
@@ -164,7 +165,6 @@
 import com.android.systemui.statusbar.LightRevealScrim;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractorTest.kt
index df45e2e..7946a68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractorTest.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.collectLastValue
 import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.policy.batteryController
 import com.android.systemui.statusbar.policy.fake
 import com.android.systemui.testKosmos
@@ -32,7 +33,7 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class BatteryInteractorTest : SysuiTestCase() {
-    val kosmos = testKosmos()
+    val kosmos = testKosmos().useUnconfinedTestDispatcher()
     val Kosmos.underTest by Kosmos.Fixture { batteryInteractor }
 
     @Test
@@ -50,12 +51,62 @@
 
             assertThat(latest).isEqualTo(BatteryAttributionModel.Defend)
 
+            batteryController.fake._isDefender = false
             batteryController.fake._isPowerSave = true
 
             assertThat(latest).isEqualTo(BatteryAttributionModel.PowerSave)
 
+            batteryController.fake._isPowerSave = false
             batteryController.fake._isPluggedIn = true
 
             assertThat(latest).isEqualTo(BatteryAttributionModel.Charging)
         }
+
+    @Test
+    fun attributionType_prioritizesPowerSaveOverCharging() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.batteryAttributionType)
+
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = true
+            batteryController.fake._isPowerSave = true
+
+            assertThat(latest).isEqualTo(BatteryAttributionModel.PowerSave)
+        }
+
+    @Test
+    fun attributionType_prioritizesPowerSaveOverDefender() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.batteryAttributionType)
+
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isPowerSave = true
+            batteryController.fake._isDefender = false
+
+            assertThat(latest).isEqualTo(BatteryAttributionModel.PowerSave)
+        }
+
+    @Test
+    fun attributionType_prioritizesDefenderOverCharging() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.batteryAttributionType)
+
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isPowerSave = false
+            batteryController.fake._isDefender = true
+
+            assertThat(latest).isEqualTo(BatteryAttributionModel.Defend)
+        }
+
+    @Test
+    fun attributionType_prioritizesChargingOnly() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.batteryAttributionType)
+
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = false
+            batteryController.fake._isPowerSave = false
+
+            assertThat(latest).isEqualTo(BatteryAttributionModel.Charging)
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelTest.kt
index 6f4c745..d817348 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelTest.kt
@@ -97,4 +97,39 @@
 
             assertThat(underTest.glyphList).isEqualTo(listOf(BatteryGlyph.BoltLarge))
         }
+
+    @Test
+    fun glyphList_attributionOrdering_prioritizesDefendOverCharging() =
+        kosmos.runTest {
+            fakeSystemSettingsRepository.setInt(Settings.System.SHOW_BATTERY_PERCENT, 0)
+            batteryController.fake._level = 39
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = true
+
+            assertThat(underTest.glyphList).isEqualTo(listOf(BatteryGlyph.DefendLarge))
+        }
+
+    @Test
+    fun glyphList_attributionOrdering_prioritizesPowerSaveOverDefend() =
+        kosmos.runTest {
+            fakeSystemSettingsRepository.setInt(Settings.System.SHOW_BATTERY_PERCENT, 0)
+            batteryController.fake._level = 39
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = true
+            batteryController.fake._isPowerSave = true
+
+            assertThat(underTest.glyphList).isEqualTo(listOf(BatteryGlyph.PlusLarge))
+        }
+
+    @Test
+    fun glyphList_attributionOrdering_prioritizesPowerSaveOverCharging() =
+        kosmos.runTest {
+            fakeSystemSettingsRepository.setInt(Settings.System.SHOW_BATTERY_PERCENT, 0)
+            batteryController.fake._level = 39
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = false
+            batteryController.fake._isPowerSave = true
+
+            assertThat(underTest.glyphList).isEqualTo(listOf(BatteryGlyph.PlusLarge))
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index ffe7750..4a0445d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -269,14 +269,14 @@
         when(viewRoot.getOnBackInvokedDispatcher()).thenReturn(backInvokedDispatcher);
         view.setViewRootImpl(viewRoot);
 
-        /* verify that predictive back callback registered when RemoteInputView becomes visible */
-        view.onVisibilityAggregated(true);
+        /* verify that predictive back callback registered when RemoteInputView gains focus */
+        view.focus();
         verify(backInvokedDispatcher).registerOnBackInvokedCallback(
                 eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
                 onBackInvokedCallbackCaptor.capture());
 
-        /* verify that same callback unregistered when RemoteInputView becomes invisible */
-        view.onVisibilityAggregated(false);
+        /* verify that same callback unregistered when RemoteInputView loses focus */
+        view.onDefocus(false, false, null);
         verify(backInvokedDispatcher).unregisterOnBackInvokedCallback(
                 eq(onBackInvokedCallbackCaptor.getValue()));
     }
@@ -299,13 +299,12 @@
         view.onVisibilityAggregated(true);
         view.setEditTextReferenceToSelf();
 
+        view.focus();
         /* capture the callback during registration */
         verify(backInvokedDispatcher).registerOnBackInvokedCallback(
                 eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
                 onBackInvokedCallbackCaptor.capture());
 
-        view.focus();
-
         /* invoke the captured callback */
         onBackInvokedCallbackCaptor.getValue().onBackInvoked();
 
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 341bd3a..a978ecd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -33,6 +33,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -55,8 +57,6 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
@@ -136,7 +136,6 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -166,7 +165,6 @@
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 import com.android.systemui.util.FakeEventLog;
 import com.android.systemui.util.settings.FakeGlobalSettings;
-import com.android.systemui.util.settings.FakeSettings;
 import com.android.systemui.util.settings.SystemSettings;
 import com.android.systemui.util.time.SystemClock;
 import com.android.wm.shell.Flags;
@@ -451,7 +449,6 @@
                 () -> mSelectedUserInteractor,
                 mUserTracker,
                 mNotificationShadeWindowModel,
-                new FakeSettings(),
                 mKosmos::getCommunalInteractor,
                 mKosmos.getShadeLayoutParams()
         );
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
index 0ba7c85..a3d0135 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
@@ -47,6 +47,7 @@
 import com.android.systemui.log.dagger.BroadcastDispatcherLog
 import com.android.systemui.log.dagger.FaceAuthLog
 import com.android.systemui.log.dagger.SceneFrameworkLog
+import com.android.systemui.media.NotificationMediaManager
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
 import com.android.systemui.model.SysUiState
 import com.android.systemui.plugins.ActivityStarter
@@ -57,7 +58,6 @@
 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.NotificationShadeDepthController
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
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 6f570a8..cd4b09c 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
@@ -21,7 +21,6 @@
 import com.android.systemui.dump.dumpManager
 import com.android.systemui.keyevent.domain.interactor.keyEventInteractor
 import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
-import com.android.systemui.keyguard.domain.interactor.keyguardBypassInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.power.domain.interactor.powerInteractor
 import com.android.systemui.util.time.systemClock
@@ -31,8 +30,6 @@
         DeviceEntryHapticsInteractor(
             biometricSettingsRepository = biometricSettingsRepository,
             deviceEntryBiometricAuthInteractor = deviceEntryBiometricAuthInteractor,
-            deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor,
-            keyguardBypassInteractor = keyguardBypassInteractor,
             deviceEntryFingerprintAuthInteractor = deviceEntryFingerprintAuthInteractor,
             deviceEntrySourceInteractor = deviceEntrySourceInteractor,
             fingerprintPropertyRepository = fingerprintPropertyRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt
index 97dab49..807bc82 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/FakeKeyEventRepository.kt
@@ -27,9 +27,16 @@
     private val _isPowerButtonDown = MutableStateFlow(false)
     override val isPowerButtonDown: Flow<Boolean> = _isPowerButtonDown.asStateFlow()
 
+    private val _isPowerButtonLongPressed = MutableStateFlow(false)
+    override val isPowerButtonLongPressed = _isPowerButtonLongPressed.asStateFlow()
+
     fun setPowerButtonDown(isDown: Boolean) {
         _isPowerButtonDown.value = isDown
     }
+
+    fun setPowerButtonBeingLongPressed(isLongPressed: Boolean) {
+        _isPowerButtonLongPressed.value = isLongPressed
+    }
 }
 
 @Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
index 2797b44..bf45697 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
@@ -48,5 +48,6 @@
             primaryBouncerToLockscreenTransitionViewModel,
         lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel,
         glanceableHubToAodTransitionViewModel = glanceableHubToAodTransitionViewModel,
+        glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index 27ca0f86..a9aa8cd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -84,6 +84,7 @@
         occludedToAodTransitionViewModel = occludedToAodTransitionViewModel,
         occludedToDozingTransitionViewModel = occludedToDozingTransitionViewModel,
         occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+        occludedToPrimaryBouncerTransitionViewModel = occludedToPrimaryBouncerTransitionViewModel,
         offToLockscreenTransitionViewModel = offToLockscreenTransitionViewModel,
         primaryBouncerToAodTransitionViewModel = primaryBouncerToAodTransitionViewModel,
         primaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/util/KeyguardTransitionRepositorySpySubject.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/util/KeyguardTransitionRepositorySpySubject.kt
index 11f0c19..7093a94 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/util/KeyguardTransitionRepositorySpySubject.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/util/KeyguardTransitionRepositorySpySubject.kt
@@ -115,14 +115,14 @@
         fun assertThat(
             repository: KeyguardTransitionRepository
         ): KeyguardTransitionRepositorySpySubject =
-            assertAbout { failureMetadata, repository: KeyguardTransitionRepository ->
+                assertAbout { failureMetadata, repository: KeyguardTransitionRepository? ->
                     if (!Mockito.mockingDetails(repository).isSpy) {
                         fail(
                             "Cannot assert on a non-spy KeyguardTransitionRepository. " +
                                 "Use Mockito.spy(keyguardTransitionRepository)."
                         )
                     }
-                    KeyguardTransitionRepositorySpySubject(failureMetadata, repository)
+                    KeyguardTransitionRepositorySpySubject(failureMetadata, repository!!)
                 }
                 .that(repository)
     }
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 af89403..623989e 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
@@ -67,6 +67,7 @@
 import com.android.systemui.scene.ui.view.mockWindowRootViewProvider
 import com.android.systemui.settings.brightness.data.repository.brightnessMirrorShowingRepository
 import com.android.systemui.settings.displayTracker
+import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.shade.domain.interactor.shadeLayoutParams
@@ -203,5 +204,6 @@
     val windowRootViewBlurInteractor by lazy { kosmos.windowRootViewBlurInteractor }
     val sysuiState by lazy { kosmos.sysUiState }
     val displayTracker by lazy { kosmos.displayTracker }
+    val fakeShadeDisplaysRepository by lazy { kosmos.fakeShadeDisplaysRepository }
     val sysUIStateDispatcher by lazy { kosmos.sysUIStateDispatcher }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
index 5e67182..b41ceff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
@@ -13,89 +13,103 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.android.systemui.log
 
 import android.util.Log
 import android.util.Log.TerribleFailureHandler
-import junit.framework.Assert
+import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.Callable
 
-/** Asserts that the given block does not make a call to Log.wtf */
-fun assertDoesNotLogWtf(
+/** Asserts that [notLoggingBlock] does not make a call to [Log.wtf] */
+fun <T> assertDoesNotLogWtf(
     message: String = "Expected Log.wtf not to be called",
-    notLoggingBlock: () -> Unit,
-) {
+    notLoggingBlock: () -> T,
+): T {
     var caught: TerribleFailureLog? = null
     val newHandler = TerribleFailureHandler { tag, failure, system ->
         caught = TerribleFailureLog(tag, failure, system)
     }
     val oldHandler = Log.setWtfHandler(newHandler)
-    try {
-        notLoggingBlock()
-    } finally {
-        Log.setWtfHandler(oldHandler)
-    }
+    val result =
+        try {
+            notLoggingBlock()
+        } finally {
+            Log.setWtfHandler(oldHandler)
+        }
     caught?.let { throw AssertionError("$message: $it", it.failure) }
+    return result
 }
 
-fun assertDoesNotLogWtf(
-    message: String = "Expected Log.wtf not to be called",
-    notLoggingRunnable: Runnable,
-) = assertDoesNotLogWtf(message = message) { notLoggingRunnable.run() }
-
-/**
- * Assert that the given block makes a call to Log.wtf
- *
- * @return the details of the log
- */
-fun assertLogsWtf(
+/** Assert that [loggingBlock] makes a call to [Log.wtf] */
+@JvmOverloads
+fun <T> assertLogsWtf(
     message: String = "Expected Log.wtf to be called",
     allowMultiple: Boolean = false,
-    loggingBlock: () -> Unit,
-): TerribleFailureLog {
-    var caught: TerribleFailureLog? = null
-    var count = 0
+    loggingBlock: () -> T,
+): WtfBlockResult<T> {
+    val caught = mutableListOf<TerribleFailureLog>()
     val newHandler = TerribleFailureHandler { tag, failure, system ->
-        if (caught == null) {
-            caught = TerribleFailureLog(tag, failure, system)
-        }
-        count++
+        caught.add(TerribleFailureLog(tag, failure, system))
     }
     val oldHandler = Log.setWtfHandler(newHandler)
-    try {
-        loggingBlock()
-    } finally {
-        Log.setWtfHandler(oldHandler)
+    val result =
+        try {
+            loggingBlock()
+        } finally {
+            Log.setWtfHandler(oldHandler)
+        }
+    assertWithMessage(message).that(caught).isNotEmpty()
+    if (!allowMultiple) {
+        assertWithMessage("Unexpectedly caught Log.Wtf multiple times").that(caught).hasSize(1)
     }
-    Assert.assertNotNull(message, caught)
-    if (!allowMultiple && count != 1) {
-        Assert.fail("Unexpectedly caught Log.Wtf $count times; expected only 1.  First: $caught")
-    }
-    return caught!!
+    return WtfBlockResult(caught, result)
 }
 
+/** Assert that [loggingCallable] makes a call to [Log.wtf] */
 @JvmOverloads
-fun assertLogsWtf(
+fun <T> assertLogsWtf(
     message: String = "Expected Log.wtf to be called",
     allowMultiple: Boolean = false,
-    loggingRunnable: Runnable,
-): TerribleFailureLog =
-    assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() }
+    loggingCallable: Callable<T>,
+): WtfBlockResult<T> =
+    assertLogsWtf(message = message, allowMultiple = allowMultiple, loggingCallable::call)
 
-fun assertLogsWtfs(
-    message: String = "Expected Log.wtf to be called once or more",
-    loggingBlock: () -> Unit,
-): TerribleFailureLog = assertLogsWtf(message, allowMultiple = true, loggingBlock)
-
+/** Assert that [loggingBlock] makes at least one call to [Log.wtf] */
 @JvmOverloads
-fun assertLogsWtfs(
+fun <T> assertLogsWtfs(
     message: String = "Expected Log.wtf to be called once or more",
-    loggingRunnable: Runnable,
-): TerribleFailureLog = assertLogsWtfs(message) { loggingRunnable.run() }
+    loggingBlock: () -> T,
+): WtfBlockResult<T> = assertLogsWtf(message, allowMultiple = true, loggingBlock)
+
+/** Assert that [loggingCallable] makes at least one call to [Log.wtf] */
+@JvmOverloads
+fun <T> assertLogsWtfs(
+    message: String = "Expected Log.wtf to be called once or more",
+    loggingCallable: Callable<T>,
+): WtfBlockResult<T> = assertLogsWtf(message, allowMultiple = true, loggingCallable)
 
 /** The data passed to [TerribleFailureHandler.onTerribleFailure] */
 data class TerribleFailureLog(
     val tag: String,
     val failure: Log.TerribleFailure,
-    val system: Boolean
+    val system: Boolean,
 )
+
+/** The [Log.wtf] logs and return value of the block */
+data class WtfBlockResult<T>(val logs: List<TerribleFailureLog>, val result: T)
+
+/** Assert that [loggingRunnable] makes a call to [Log.wtf] */
+@JvmOverloads
+fun assertRunnableLogsWtf(
+    message: String = "Expected Log.wtf to be called",
+    allowMultiple: Boolean = false,
+    loggingRunnable: Runnable,
+): WtfBlockResult<Unit> =
+    assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() }
+
+/** Assert that [loggingRunnable] makes at least one call to [Log.wtf] */
+@JvmOverloads
+fun assertRunnableLogsWtfs(
+    message: String = "Expected Log.wtf to be called once or more",
+    loggingRunnable: Runnable,
+): WtfBlockResult<Unit> = assertRunnableLogsWtf(message, allowMultiple = true, loggingRunnable)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogWtfHandlerRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogWtfHandlerRule.kt
index e639326..0e348c8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogWtfHandlerRule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogWtfHandlerRule.kt
@@ -24,21 +24,23 @@
 
 class LogWtfHandlerRule : TestRule {
 
-    private var started = false
-    private var handler = ThrowAndFailAtEnd
+    private var failureLogExemptions = mutableListOf<FailureLogExemption>()
 
     override fun apply(base: Statement, description: Description): Statement {
         return object : Statement() {
             override fun evaluate() {
-                started = true
+                val handler = TerribleFailureTestHandler()
                 val originalWtfHandler = Log.setWtfHandler(handler)
                 var failure: Throwable? = null
                 try {
                     base.evaluate()
                 } catch (ex: Throwable) {
-                    failure = ex.runAndAddSuppressed { handler.onTestFailure(ex) }
+                    failure = ex
                 } finally {
-                    failure = failure.runAndAddSuppressed { handler.onTestFinished() }
+                    failure =
+                        runAndAddSuppressed(failure) {
+                            handler.onTestFinished(failureLogExemptions)
+                        }
                     Log.setWtfHandler(originalWtfHandler)
                 }
                 if (failure != null) {
@@ -48,74 +50,52 @@
         }
     }
 
-    fun Throwable?.runAndAddSuppressed(block: () -> Unit): Throwable? {
+    /** Adds a log failure exemption. Exemptions are evaluated at the end of the test. */
+    fun addFailureLogExemption(exemption: FailureLogExemption) {
+        failureLogExemptions.add(exemption)
+    }
+
+    /** Clears and sets exemptions. Exemptions are evaluated at the end of the test. */
+    fun resetFailureLogExemptions(vararg exemptions: FailureLogExemption) {
+        failureLogExemptions = exemptions.toMutableList()
+    }
+
+    private fun runAndAddSuppressed(currentError: Throwable?, block: () -> Unit): Throwable? {
         try {
             block()
         } catch (t: Throwable) {
-            if (this == null) {
+            if (currentError == null) {
                 return t
             }
-            addSuppressed(t)
+            currentError.addSuppressed(t)
         }
-        return this
+        return currentError
     }
 
-    fun setWtfHandler(handler: TerribleFailureTestHandler) {
-        check(!started) { "Should only be called before the test starts" }
-        this.handler = handler
-    }
+    private class TerribleFailureTestHandler : TerribleFailureHandler {
+        private val failureLogs = mutableListOf<FailureLog>()
 
-    fun interface TerribleFailureTestHandler : TerribleFailureHandler {
-        fun onTestFailure(failure: Throwable) {}
-        fun onTestFinished() {}
-    }
+        override fun onTerribleFailure(tag: String, what: Log.TerribleFailure, system: Boolean) {
+            failureLogs.add(FailureLog(tag = tag, failure = what, system = system))
+        }
 
-    companion object Handlers {
-        val ThrowAndFailAtEnd
-            get() =
-                object : TerribleFailureTestHandler {
-                    val failures = mutableListOf<Log.TerribleFailure>()
-
-                    override fun onTerribleFailure(
-                        tag: String,
-                        what: Log.TerribleFailure,
-                        system: Boolean
-                    ) {
-                        failures.add(what)
-                        throw what
-                    }
-
-                    override fun onTestFailure(failure: Throwable) {
-                        super.onTestFailure(failure)
-                    }
-
-                    override fun onTestFinished() {
-                        if (failures.isNotEmpty()) {
-                            throw AssertionError("Unexpected Log.wtf calls: $failures", failures[0])
-                        }
-                    }
+        fun onTestFinished(exemptions: List<FailureLogExemption>) {
+            val failures =
+                failureLogs.filter { failureLog ->
+                    !exemptions.any { it.isFailureLogExempt(failureLog) }
                 }
+            if (failures.isNotEmpty()) {
+                throw AssertionError("Unexpected Log.wtf calls: $failures", failures[0].failure)
+            }
+        }
+    }
 
-        val JustThrow = TerribleFailureTestHandler { _, what, _ -> throw what }
+    /** All the information from a call to [Log.wtf] that was handed to [TerribleFailureHandler] */
+    data class FailureLog(val tag: String, val failure: Log.TerribleFailure, val system: Boolean)
 
-        val JustFailAtEnd
-            get() =
-                object : TerribleFailureTestHandler {
-                    val failures = mutableListOf<Log.TerribleFailure>()
-
-                    override fun onTerribleFailure(
-                        tag: String,
-                        what: Log.TerribleFailure,
-                        system: Boolean
-                    ) {
-                        failures.add(what)
-                    }
-
-                    override fun onTestFinished() {
-                        if (failures.isNotEmpty()) {
-                            throw AssertionError("Unexpected Log.wtf calls: $failures", failures[0])
-                        }
-                    }
-                }
+    /** An interface for exempting a [FailureLog] from causing a test failure. */
+    fun interface FailureLogExemption {
+        /** Determines whether a log should be except from failing the test. */
+        fun isFailureLogExempt(log: FailureLog): Boolean
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/model/SysUiStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SysUiStateKosmos.kt
index dbd1c9c..11bd4c7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/model/SysUiStateKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SysUiStateKosmos.kt
@@ -32,12 +32,7 @@
     object : SysUiStateImpl.Factory {
         override fun create(displayId: Int): SysUiStateImpl {
             return spy(
-                SysUiStateImpl(
-                    displayId,
-                    sceneContainerPlugin,
-                    dumpManager,
-                    sysUIStateDispatcher,
-                )
+                SysUiStateImpl(displayId, sceneContainerPlugin, dumpManager, sysUIStateDispatcher)
             )
         }
     }
@@ -48,3 +43,15 @@
 val Kosmos.sysuiStateInteractor by Fixture {
     SysUIStateDisplaysInteractor(fakeSysUIStatePerDisplayRepository, displayRepository)
 }
+
+val Kosmos.sysUiStateOverrideFactory by Fixture {
+    { displayId: Int ->
+        SysUIStateOverride(
+            displayId,
+            sceneContainerPlugin,
+            dumpManager,
+            sysUiState,
+            sysUIStateDispatcher,
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt
index e09f280..c1e689c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt
@@ -68,8 +68,8 @@
         ): QSTileIntentUserInputHandlerSubject =
             Truth.assertAbout {
                     failureMetadata: FailureMetadata,
-                    subject: FakeQSTileIntentUserInputHandler ->
-                    QSTileIntentUserInputHandlerSubject(failureMetadata, subject)
+                    subject: FakeQSTileIntentUserInputHandler? ->
+                    QSTileIntentUserInputHandlerSubject(failureMetadata, subject!!)
                 }
                 .that(handler)
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt
index aa29808..657a95a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt
@@ -63,7 +63,7 @@
     companion object {
 
         /** Returns a factory to be used with [Truth.assertAbout]. */
-        fun states(): Factory<QSTileStateSubject, QSTileState?> {
+        fun states(): Factory<QSTileStateSubject, QSTileState> {
             return Factory { failureMetadata: FailureMetadata, subject: QSTileState? ->
                 QSTileStateSubject(failureMetadata, subject)
             }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/TileSubject.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/TileSubject.kt
index d2351dc..cc8b44b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/TileSubject.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/TileSubject.kt
@@ -59,7 +59,7 @@
     companion object {
 
         /** Returns a factory to be used with [Truth.assertAbout]. */
-        fun tiles(): Factory<TileSubject, Tile?> {
+        fun tiles(): Factory<TileSubject, Tile> {
             return Factory { failureMetadata: FailureMetadata, subject: Tile? ->
                 TileSubject(failureMetadata, subject)
             }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationActivityStarterKosmos.kt
index c337ac2..8e98fe3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationActivityStarterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationActivityStarterKosmos.kt
@@ -18,6 +18,10 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.statusbar.phone.statusBarNotificationActivityStarter
+import org.mockito.kotlin.mock
 
 var Kosmos.notificationActivityStarter: NotificationActivityStarter by
     Kosmos.Fixture { statusBarNotificationActivityStarter }
+
+var Kosmos.mockNotificationActivityStarter: NotificationActivityStarter by
+Kosmos.Fixture { mock<NotificationActivityStarter>() }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerKosmos.kt
similarity index 66%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerKosmos.kt
index 9b7cd70..f3cdabb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.statusbar.notification.collection.render
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.kotlin.mock
+
+var Kosmos.groupMembershipManager by Kosmos.Fixture { mock<GroupMembershipManager>() }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractorKosmos.kt
similarity index 66%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractorKosmos.kt
index 9b7cd70..c263c5d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractorKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.statusbar.notification.people
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.kotlin.mock
+
+val Kosmos.notificationPersonExtractor by Kosmos.Fixture { mock<NotificationPersonExtractor>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierKosmos.kt
new file mode 100644
index 0000000..20982eb
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.people
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.collection.render.groupMembershipManager
+
+val Kosmos.peopleNotificationIdentifier by
+    Kosmos.Fixture {
+        PeopleNotificationIdentifierImpl(notificationPersonExtractor, groupMembershipManager)
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
index da879d9..2b3158d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
@@ -39,7 +39,8 @@
         promotedNotificationContentExtractor.extractContent(
             entry,
             Notification.Builder.recoverBuilder(applicationContext, entry.sbn.notification),
-            RowImageInflater.newInstance(null).useForContentModel(),
+            RowImageInflater.newInstance(previousIndex = null, reinflating = false)
+                .useForContentModel(),
         )
     entry.promotedNotificationContentModel =
         requireNotNull(extractedContent) { "extractContent returned null" }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
new file mode 100644
index 0000000..e99f61e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 com.android.internal.logging.metricsLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
+import com.android.systemui.statusbar.notification.collection.coordinator.visualStabilityCoordinator
+import com.android.systemui.statusbar.notification.mockNotificationActivityStarter
+import com.android.systemui.statusbar.notification.people.peopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
+
+val Kosmos.entryAdapterFactory by
+Kosmos.Fixture {
+    EntryAdapterFactoryImpl(
+        mockNotificationActivityStarter,
+        metricsLogger,
+        peopleNotificationIdentifier,
+        notificationIconStyleProvider,
+        visualStabilityCoordinator,
+    )
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index 771e1a5..7f012ba 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
 import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.media.NotificationMediaManager
 import com.android.systemui.media.controls.util.MediaFeatureFlag
 import com.android.systemui.media.dialog.MediaOutputDialogManager
 import com.android.systemui.plugins.ActivityStarter
@@ -45,7 +46,6 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper
 import com.android.systemui.shared.system.PackageManagerWrapper
-import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.NotificationRemoteInputManager
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.RankingBuilder
@@ -53,8 +53,11 @@
 import com.android.systemui.statusbar.notification.ColorUpdateLogger
 import com.android.systemui.statusbar.notification.ConversationNotificationManager
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
@@ -76,6 +79,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag
 import com.android.systemui.statusbar.notification.row.icon.AppIconProviderImpl
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
 import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProviderImpl
 import com.android.systemui.statusbar.notification.row.icon.NotificationRowIconViewInflaterFactory
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor
@@ -364,11 +368,22 @@
             )
         val row = rowInflaterTask.inflateSynchronously(context, null, entry)
 
+        val entryAdapter =
+            EntryAdapterFactoryImpl(
+                    Mockito.mock(NotificationActivityStarter::class.java),
+                    Mockito.mock(MetricsLogger::class.java),
+                    Mockito.mock(PeopleNotificationIdentifier::class.java),
+                    Mockito.mock(NotificationIconStyleProvider::class.java),
+                    Mockito.mock(VisualStabilityCoordinator::class.java),
+                )
+                .create(entry)
+
         entry.row = row
         mIconManager.createIcons(entry)
         mBindPipelineEntryListener.onEntryInit(entry)
         mBindPipeline.manageRow(entry, row)
         row.initialize(
+            entryAdapter,
             entry,
             Mockito.mock(RemoteInputViewSubcomponent.Factory::class.java, STUB_ONLY),
             APP_NAME,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt
index 8ff7c7d..08cfd9f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt
@@ -38,6 +38,7 @@
     notificationKey: String = "test",
     appName: String = "",
     promotedContent: PromotedNotificationContentModel? = null,
+    isAppVisible: Boolean = false,
 ) =
     OngoingCallModel.InCall(
         startTimeMs,
@@ -46,6 +47,7 @@
         notificationKey,
         appName,
         promotedContent,
+        isAppVisible,
     )
 
 object OngoingCallTestHelper {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileDomainInteractorKairosKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileDomainInteractorKairosKosmos.kt
new file mode 100644
index 0000000..d9a327b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileDomainInteractorKairosKosmos.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.content.applicationContext
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kairos.ActivatedKairosFixture
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.userSetupRepository
+import com.android.systemui.util.carrierConfigTracker
+
+@ExperimentalKairosApi
+val Kosmos.mobileIconsInteractorKairos by ActivatedKairosFixture {
+    MobileIconsInteractorKairosImpl(
+        mobileConnectionsRepositoryKairos,
+        carrierConfigTracker,
+        logcatTableLogBuffer(this),
+        connectivityRepository,
+        userSetupRepository,
+        applicationContext,
+        featureFlagsClassic,
+    )
+}
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairosKosmos.kt
similarity index 65%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairosKosmos.kt
index 6b8161c..3ee3380 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModelKairosKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,6 +14,9 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
 
-parcelable SoundProfileHandle;
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.stackedMobileIconViewModelKairos by
+    Kosmos.Fixture { StackedMobileIconViewModelKairos(mobileIconsViewModel) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
index a97c651..5c4deaa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.log.table.tableLogBufferFactory
 import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.domain.interactor.shadeDisplaysInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
 import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
@@ -40,29 +41,34 @@
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.homeStatusBarInteractor
 
 var Kosmos.homeStatusBarViewModel: HomeStatusBarViewModel by
+    Kosmos.Fixture { homeStatusBarViewModelFactory.invoke(testableContext.displayId) }
+var Kosmos.homeStatusBarViewModelFactory: (Int) -> HomeStatusBarViewModel by
     Kosmos.Fixture {
-        HomeStatusBarViewModelImpl(
-            testableContext.displayId,
-            batteryViewModelFactory,
-            tableLogBufferFactory,
-            homeStatusBarInteractor,
-            homeStatusBarIconBlockListInteractor,
-            lightsOutInteractor,
-            activeNotificationsInteractor,
-            darkIconInteractor,
-            headsUpNotificationInteractor,
-            keyguardTransitionInteractor,
-            keyguardInteractor,
-            statusBarOperatorNameViewModel,
-            sceneInteractor,
-            sceneContainerOcclusionInteractor,
-            shadeInteractor,
-            shareToAppChipViewModel,
-            ongoingActivityChipsViewModel,
-            statusBarPopupChipsViewModelFactory,
-            systemStatusEventAnimationInteractor,
-            multiDisplayStatusBarContentInsetsViewModelStore,
-            backgroundScope,
-            testDispatcher,
-        )
+        { displayId ->
+            HomeStatusBarViewModelImpl(
+                displayId,
+                batteryViewModelFactory,
+                tableLogBufferFactory,
+                homeStatusBarInteractor,
+                homeStatusBarIconBlockListInteractor,
+                lightsOutInteractor,
+                activeNotificationsInteractor,
+                darkIconInteractor,
+                headsUpNotificationInteractor,
+                keyguardTransitionInteractor,
+                keyguardInteractor,
+                statusBarOperatorNameViewModel,
+                sceneInteractor,
+                sceneContainerOcclusionInteractor,
+                shadeInteractor,
+                shareToAppChipViewModel,
+                ongoingActivityChipsViewModel,
+                statusBarPopupChipsViewModelFactory,
+                systemStatusEventAnimationInteractor,
+                multiDisplayStatusBarContentInsetsViewModelStore,
+                backgroundScope,
+                testDispatcher,
+                { shadeDisplaysInteractor },
+            )
+        }
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/truth/correspondence/FakeUiEvent.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/truth/correspondence/FakeUiEvent.kt
index 48cd345..6c10526 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/truth/correspondence/FakeUiEvent.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/truth/correspondence/FakeUiEvent.kt
@@ -24,7 +24,7 @@
 object FakeUiEvent {
     val EVENT_ID =
         Correspondence.transforming<FakeUiEvent, Int>(
-            { it?.eventId },
+            { it.eventId },
             "has a eventId of",
         )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/truth/correspondence/LogMaker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/truth/correspondence/LogMaker.kt
index 3f0a9524..9664bf3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/truth/correspondence/LogMaker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/truth/correspondence/LogMaker.kt
@@ -23,7 +23,7 @@
 object LogMaker {
     val CATEGORY =
         Correspondence.transforming<LogMaker, Int>(
-            { it?.category },
+            { it.category },
             "has a category of",
         )
 }
diff --git a/media/java/android/media/quality/SoundProfileHandle.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/util/CarrierConfigTrackerKosmos.kt
similarity index 74%
copy from media/java/android/media/quality/SoundProfileHandle.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/util/CarrierConfigTrackerKosmos.kt
index 6b8161c..5847369 100644
--- a/media/java/android/media/quality/SoundProfileHandle.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/CarrierConfigTrackerKosmos.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
-package android.media.quality;
+package com.android.systemui.util
 
-parcelable SoundProfileHandle;
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mockFixture
+
+var Kosmos.carrierConfigTracker: CarrierConfigTracker by mockFixture()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
index 4ca044d..3421864 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
@@ -33,6 +33,8 @@
 import com.android.systemui.volume.dialog.sliders.domain.model.volumeDialogSliderType
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogOverscrollViewBinder
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderViewBinder
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.volumeDialogSliderViewModel
 import com.android.systemui.volume.dialog.sliders.ui.volumeDialogOverscrollViewBinder
 import com.android.systemui.volume.dialog.sliders.ui.volumeDialogSliderViewBinder
 import com.android.systemui.volume.mediaControllerRepository
@@ -60,6 +62,9 @@
                     }
                 }
 
+        override fun sliderViewModel(): VolumeDialogSliderViewModel =
+            localKosmos.volumeDialogSliderViewModel
+
         override fun sliderViewBinder(): VolumeDialogSliderViewBinder =
             localKosmos.volumeDialogSliderViewBinder
 
diff --git a/ravenwood/scripts/extract-last-soong-commands.py b/ravenwood/scripts/extract-last-soong-commands.py
index 0629b77..b8d6f20 100755
--- a/ravenwood/scripts/extract-last-soong-commands.py
+++ b/ravenwood/scripts/extract-last-soong-commands.py
@@ -55,7 +55,7 @@
 
                 if s.startswith("verbose"):
                     continue
-                if re.match('^\[.*bootstrap blueprint', s):
+                if re.match('^\\[.*bootstrap blueprint', s):
                     continue
 
                 s = s.rstrip()
diff --git a/ravenwood/scripts/list-ravenwood-tests.sh b/ravenwood/scripts/list-ravenwood-tests.sh
index 05f3fdf..5d7daeb 100755
--- a/ravenwood/scripts/list-ravenwood-tests.sh
+++ b/ravenwood/scripts/list-ravenwood-tests.sh
@@ -15,4 +15,20 @@
 
 # List all the ravenwood test modules.
 
-jq -r 'to_entries[] | select( .value.compatibility_suites | index("ravenwood-tests") ) | .key' "$OUT/module-info.json" | sort
+set -e
+
+in="$OUT/module-info.json"
+cache="$OUT/ravenwood-test-list.cached.tmp"
+cache_temp="$OUT/ravenwood-test-list.temp.tmp"
+
+if [[ "$in" -nt "$cache" ]] ; then
+    rm -f "$cache_temp" "$cache"
+
+    # First, create to a temp file, and once it's completed, rename it
+    # to the actual cache file, so that if the command failed or is interrupted,
+    # we don't update the cache.
+    jq -r 'to_entries[] | select( .value.compatibility_suites | index("ravenwood-tests") ) | .key' "$OUT/module-info.json" | sort > "$cache_temp"
+    mv "$cache_temp" "$cache"
+fi
+
+cat "$cache"
diff --git a/ravenwood/tools/hoststubgen/Android.bp b/ravenwood/tools/hoststubgen/Android.bp
index a5ff496..004834e 100644
--- a/ravenwood/tools/hoststubgen/Android.bp
+++ b/ravenwood/tools/hoststubgen/Android.bp
@@ -90,11 +90,9 @@
 java_library_host {
     name: "hoststubgen-lib",
     defaults: ["ravenwood-internal-only-visibility-java"],
-    srcs: ["src/**/*.kt"],
+    srcs: ["lib/**/*.kt"],
     static_libs: [
         "hoststubgen-helper-runtime",
-    ],
-    libs: [
         "junit",
         "ow2-asm",
         "ow2-asm-analysis",
@@ -108,15 +106,8 @@
 java_binary_host {
     name: "hoststubgen",
     main_class: "com.android.hoststubgen.HostStubGenMain",
-    static_libs: [
-        "hoststubgen-lib",
-        "junit",
-        "ow2-asm",
-        "ow2-asm-analysis",
-        "ow2-asm-commons",
-        "ow2-asm-tree",
-        "ow2-asm-util",
-    ],
+    srcs: ["src/**/*.kt"],
+    static_libs: ["hoststubgen-lib"],
     visibility: ["//visibility:public"],
 }
 
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Exceptions.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Exceptions.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Exceptions.kt
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt
new file mode 100644
index 0000000..4fe21ea
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hoststubgen
+
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.filters.AnnotationBasedFilter
+import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
+import com.android.hoststubgen.filters.ConstantFilter
+import com.android.hoststubgen.filters.DefaultHookInjectingFilter
+import com.android.hoststubgen.filters.FilterRemapper
+import com.android.hoststubgen.filters.ImplicitOutputFilter
+import com.android.hoststubgen.filters.KeepNativeFilter
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.filters.SanitizationFilter
+import com.android.hoststubgen.filters.TextFileFilterPolicyBuilder
+import com.android.hoststubgen.utils.ClassPredicate
+import com.android.hoststubgen.visitors.BaseAdapter
+import com.android.hoststubgen.visitors.PackageRedirectRemapper
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.ClassWriter
+import org.objectweb.asm.commons.ClassRemapper
+import org.objectweb.asm.util.CheckClassAdapter
+
+/**
+ * This class implements bytecode transformation of HostStubGen.
+ */
+class HostStubGenClassProcessor(
+    private val options: HostStubGenClassProcessorOptions,
+    private val allClasses: ClassNodes,
+    private val errors: HostStubGenErrors = HostStubGenErrors(),
+    private val stats: HostStubGenStats? = null,
+) {
+    val filter = buildFilter()
+    val remapper = FilterRemapper(filter)
+
+    private val packageRedirector = PackageRedirectRemapper(options.packageRedirects)
+
+    /**
+     * Build the filter, which decides what classes/methods/fields should be put in stub or impl
+     * jars, and "how". (e.g. with substitution?)
+     */
+    private fun buildFilter(): OutputFilter {
+        // We build a "chain" of multiple filters here.
+        //
+        // The filters are build in from "inside", meaning the first filter created here is
+        // the last filter used, so it has the least precedence.
+        //
+        // So, for example, the "remove" annotation, which is handled by AnnotationBasedFilter,
+        // can override a class-wide annotation, which is handled by
+        // ClassWidePolicyPropagatingFilter, and any annotations can be overridden by the
+        // text-file based filter, which is handled by parseTextFilterPolicyFile.
+
+        // The first filter is for the default policy from the command line options.
+        var filter: OutputFilter = ConstantFilter(options.defaultPolicy.get, "default-by-options")
+
+        // Next, we build a filter that preserves all native methods by default
+        filter = KeepNativeFilter(allClasses, filter)
+
+        // Next, we need a filter that resolves "class-wide" policies.
+        // This is used when a member (methods, fields, nested classes) don't get any policies
+        // from upper filters. e.g. when a method has no annotations, then this filter will apply
+        // the class-wide policy, if any. (if not, we'll fall back to the above filter.)
+        filter = ClassWidePolicyPropagatingFilter(allClasses, filter)
+
+        // Inject default hooks from options.
+        filter = DefaultHookInjectingFilter(
+            allClasses,
+            options.defaultClassLoadHook.get,
+            options.defaultMethodCallHook.get,
+            filter
+        )
+
+        val annotationAllowedPredicate = options.annotationAllowedClassesFile.get.let { file ->
+            if (file == null) {
+                ClassPredicate.newConstantPredicate(true) // Allow all classes
+            } else {
+                ClassPredicate.loadFromFile(file, false)
+            }
+        }
+
+        // Next, Java annotation based filter.
+        val annotFilter = AnnotationBasedFilter(
+            errors,
+            allClasses,
+            options.keepAnnotations,
+            options.keepClassAnnotations,
+            options.throwAnnotations,
+            options.removeAnnotations,
+            options.ignoreAnnotations,
+            options.substituteAnnotations,
+            options.redirectAnnotations,
+            options.redirectionClassAnnotations,
+            options.classLoadHookAnnotations,
+            options.partiallyAllowedAnnotations,
+            options.keepStaticInitializerAnnotations,
+            annotationAllowedPredicate,
+            filter
+        )
+        filter = annotFilter
+
+        // Next, "text based" filter, which allows to override policies without touching
+        // the target code.
+        if (options.policyOverrideFiles.isNotEmpty()) {
+            val builder = TextFileFilterPolicyBuilder(allClasses, filter)
+            options.policyOverrideFiles.forEach(builder::parse)
+            filter = builder.createOutputFilter()
+            annotFilter.annotationAllowedMembers = builder.annotationAllowedMembersFilter
+        }
+
+        // Apply the implicit filter.
+        filter = ImplicitOutputFilter(errors, allClasses, filter)
+
+        // Add a final sanitization step.
+        filter = SanitizationFilter(errors, allClasses, filter)
+
+        return filter
+    }
+
+    fun processClassBytecode(bytecode: ByteArray): ByteArray {
+        val cr = ClassReader(bytecode)
+
+        // COMPUTE_FRAMES wouldn't be happy if code uses
+        val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES
+        val cw = ClassWriter(flags)
+
+        // Connect to the class writer
+        var outVisitor: ClassVisitor = cw
+        if (options.enableClassChecker.get) {
+            outVisitor = CheckClassAdapter(outVisitor)
+        }
+
+        // Remapping should happen at the end.
+        outVisitor = ClassRemapper(outVisitor, remapper)
+
+        val visitorOptions = BaseAdapter.Options(
+            errors = errors,
+            stats = stats,
+            enablePreTrace = options.enablePreTrace.get,
+            enablePostTrace = options.enablePostTrace.get,
+            deleteClassFinals = options.deleteFinals.get,
+            deleteMethodFinals = options.deleteFinals.get,
+        )
+        outVisitor = BaseAdapter.getVisitor(
+            cr.className, allClasses, outVisitor, filter,
+            packageRedirector, visitorOptions
+        )
+
+        cr.accept(outVisitor, ClassReader.EXPAND_FRAMES)
+        return cw.toByteArray()
+    }
+}
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt
new file mode 100644
index 0000000..c7c45e6
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hoststubgen
+
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.BaseOptions
+import com.android.hoststubgen.utils.SetOnce
+
+private fun parsePackageRedirect(fromColonTo: String): Pair<String, String> {
+    val colon = fromColonTo.indexOf(':')
+    if ((colon < 1) || (colon + 1 >= fromColonTo.length)) {
+        throw ArgumentsException("--package-redirect must be a colon-separated string")
+    }
+    // TODO check for duplicates
+    return Pair(fromColonTo.substring(0, colon), fromColonTo.substring(colon + 1))
+}
+
+/**
+ * Options to configure [HostStubGenClassProcessor].
+ */
+open class HostStubGenClassProcessorOptions(
+    var keepAnnotations: MutableSet<String> = mutableSetOf(),
+    var throwAnnotations: MutableSet<String> = mutableSetOf(),
+    var removeAnnotations: MutableSet<String> = mutableSetOf(),
+    var ignoreAnnotations: MutableSet<String> = mutableSetOf(),
+    var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
+    var partiallyAllowedAnnotations: MutableSet<String> = mutableSetOf(),
+    var redirectAnnotations: MutableSet<String> = mutableSetOf(),
+
+    var substituteAnnotations: MutableSet<String> = mutableSetOf(),
+    var redirectionClassAnnotations: MutableSet<String> = mutableSetOf(),
+    var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
+    var keepStaticInitializerAnnotations: MutableSet<String> = mutableSetOf(),
+
+    var packageRedirects: MutableList<Pair<String, String>> = mutableListOf(),
+
+    var annotationAllowedClassesFile: SetOnce<String?> = SetOnce(null),
+
+    var defaultClassLoadHook: SetOnce<String?> = SetOnce(null),
+    var defaultMethodCallHook: SetOnce<String?> = SetOnce(null),
+
+    var policyOverrideFiles: MutableList<String> = mutableListOf(),
+
+    var defaultPolicy: SetOnce<FilterPolicy> = SetOnce(FilterPolicy.Remove),
+
+    var deleteFinals: SetOnce<Boolean> = SetOnce(false),
+
+    var enableClassChecker: SetOnce<Boolean> = SetOnce(false),
+    var enablePreTrace: SetOnce<Boolean> = SetOnce(false),
+    var enablePostTrace: SetOnce<Boolean> = SetOnce(false),
+) : BaseOptions() {
+
+    private val allAnnotations = mutableSetOf<String>()
+
+    private fun ensureUniqueAnnotation(name: String): String {
+        if (!allAnnotations.add(name)) {
+            throw DuplicateAnnotationException(name)
+        }
+        return name
+    }
+
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        // Define some shorthands...
+        fun nextArg(): String = ai.nextArgRequired(option)
+        fun MutableSet<String>.addUniqueAnnotationArg(): String =
+            nextArg().also { this += ensureUniqueAnnotation(it) }
+
+        when (option) {
+            "--policy-override-file" ->
+                policyOverrideFiles.add(nextArg().ensureFileExists())
+
+            "--default-remove" -> defaultPolicy.set(FilterPolicy.Remove)
+            "--default-throw" -> defaultPolicy.set(FilterPolicy.Throw)
+            "--default-keep" -> defaultPolicy.set(FilterPolicy.Keep)
+
+            "--keep-annotation" ->
+                keepAnnotations.addUniqueAnnotationArg()
+
+            "--keep-class-annotation" ->
+                keepClassAnnotations.addUniqueAnnotationArg()
+
+            "--partially-allowed-annotation" ->
+                partiallyAllowedAnnotations.addUniqueAnnotationArg()
+
+            "--throw-annotation" ->
+                throwAnnotations.addUniqueAnnotationArg()
+
+            "--remove-annotation" ->
+                removeAnnotations.addUniqueAnnotationArg()
+
+            "--ignore-annotation" ->
+                ignoreAnnotations.addUniqueAnnotationArg()
+
+            "--substitute-annotation" ->
+                substituteAnnotations.addUniqueAnnotationArg()
+
+            "--redirect-annotation" ->
+                redirectAnnotations.addUniqueAnnotationArg()
+
+            "--redirection-class-annotation" ->
+                redirectionClassAnnotations.addUniqueAnnotationArg()
+
+            "--class-load-hook-annotation" ->
+                classLoadHookAnnotations.addUniqueAnnotationArg()
+
+            "--keep-static-initializer-annotation" ->
+                keepStaticInitializerAnnotations.addUniqueAnnotationArg()
+
+            "--package-redirect" ->
+                packageRedirects += parsePackageRedirect(nextArg())
+
+            "--annotation-allowed-classes-file" ->
+                annotationAllowedClassesFile.set(nextArg())
+
+            "--default-class-load-hook" ->
+                defaultClassLoadHook.set(nextArg())
+
+            "--default-method-call-hook" ->
+                defaultMethodCallHook.set(nextArg())
+
+            "--delete-finals" -> deleteFinals.set(true)
+
+            // Following options are for debugging.
+            "--enable-class-checker" -> enableClassChecker.set(true)
+            "--no-class-checker" -> enableClassChecker.set(false)
+
+            "--enable-pre-trace" -> enablePreTrace.set(true)
+            "--no-pre-trace" -> enablePreTrace.set(false)
+
+            "--enable-post-trace" -> enablePostTrace.set(true)
+            "--no-post-trace" -> enablePostTrace.set(false)
+
+            else -> return false
+        }
+
+        return true
+    }
+
+    override fun dumpFields(): String {
+        return """
+            keepAnnotations=$keepAnnotations,
+            throwAnnotations=$throwAnnotations,
+            removeAnnotations=$removeAnnotations,
+            ignoreAnnotations=$ignoreAnnotations,
+            keepClassAnnotations=$keepClassAnnotations,
+            partiallyAllowedAnnotations=$partiallyAllowedAnnotations,
+            substituteAnnotations=$substituteAnnotations,
+            nativeSubstituteAnnotations=$redirectionClassAnnotations,
+            classLoadHookAnnotations=$classLoadHookAnnotations,
+            keepStaticInitializerAnnotations=$keepStaticInitializerAnnotations,
+            packageRedirects=$packageRedirects,
+            annotationAllowedClassesFile=$annotationAllowedClassesFile,
+            defaultClassLoadHook=$defaultClassLoadHook,
+            defaultMethodCallHook=$defaultMethodCallHook,
+            policyOverrideFiles=${policyOverrideFiles.toTypedArray().contentToString()},
+            defaultPolicy=$defaultPolicy,
+            deleteFinals=$deleteFinals,
+            enableClassChecker=$enableClassChecker,
+            enablePreTrace=$enablePreTrace,
+            enablePostTrace=$enablePostTrace,
+        """.trimIndent()
+    }
+}
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenErrors.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenErrors.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenLogger.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenLogger.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenStats.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenStats.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Utils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Utils.kt
similarity index 84%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Utils.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Utils.kt
index 10179ee..b2af782 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Utils.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Utils.kt
@@ -15,6 +15,8 @@
  */
 package com.android.hoststubgen
 
+import java.io.PrintWriter
+
 /**
  * Name of this executable. Set it in the main method.
  */
@@ -96,3 +98,23 @@
 fun csvEscape(value: String): String {
     return "\"" + value.replace("\"", "\"\"") + "\""
 }
+
+inline fun runMainWithBoilerplate(realMain: () -> Unit) {
+    var success = false
+
+    try {
+        realMain()
+
+        success = true
+    } catch (e: Throwable) {
+        log.e("$executableName: Error: ${e.message}")
+        if (e !is UserErrorException) {
+            e.printStackTrace(PrintWriter(log.getWriter(LogLevel.Error)))
+        }
+    } finally {
+        log.i("$executableName finished")
+        log.flush()
+    }
+
+    System.exit(if (success) 0 else 1 )
+}
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/ClassNodes.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/ClassNodes.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/dumper/ApiDumper.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/dumper/ApiDumper.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
similarity index 97%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
index 6b360b7..b225209 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
@@ -66,7 +66,7 @@
             || className.endsWith("/FeatureFlags")
             || className.endsWith("/FeatureFlagsImpl")
             || className.endsWith("/CustomFeatureFlags")
-            || className.endsWith("/FakeFeatureFlagsImpl");
+            || className.endsWith("/FakeFeatureFlagsImpl")
 }
 
 /**
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ConstantFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ConstantFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DelegatingFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DelegatingFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicy.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicy.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterRemapper.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterRemapper.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/KeepNativeFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/KeepNativeFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/OutputFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/OutputFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/PackageFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/PackageFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/SanitizationFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/SanitizationFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/SubclassFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/SubclassFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassPredicate.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/ClassPredicate.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassPredicate.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/ClassPredicate.kt
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt
new file mode 100644
index 0000000..0b17879
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hoststubgen.utils
+
+import com.android.hoststubgen.ArgumentsException
+import com.android.hoststubgen.ensureFileExists
+import com.android.hoststubgen.log
+import com.android.hoststubgen.normalizeTextLine
+import java.io.BufferedReader
+import java.io.FileReader
+
+/**
+ * Base class for parsing arguments from commandline.
+ */
+abstract class BaseOptions {
+    /**
+     * Parse all arguments.
+     *
+     * This method should remain final. For customization in subclasses, override [parseOption].
+     */
+    fun parseArgs(args: List<String>) {
+        val ai = ArgIterator.withAtFiles(args)
+        while (true) {
+            val arg = ai.nextArgOptional() ?: break
+
+            if (log.maybeHandleCommandLineArg(arg) { ai.nextArgRequired(arg) }) {
+                continue
+            }
+            try {
+                if (!parseOption(arg, ai)) {
+                    throw ArgumentsException("Unknown option: $arg")
+                }
+            } catch (e: SetOnce.SetMoreThanOnceException) {
+                throw ArgumentsException("Duplicate or conflicting argument found: $arg")
+            }
+        }
+
+        checkArgs()
+    }
+
+    /**
+     * Print out all fields in this class.
+     *
+     * This method should remain final. For customization in subclasses, override [dumpFields].
+     */
+    final override fun toString(): String {
+        val fields = dumpFields().prependIndent("  ")
+        return "${this::class.simpleName} {\n$fields\n}"
+    }
+
+    /**
+     * Check whether the parsed options are in a correct state.
+     *
+     * This method is called as the last step in [parseArgs].
+     */
+    open fun checkArgs() {}
+
+    /**
+     * Parse a single option. Return true if the option is accepted, otherwise return false.
+     *
+     * Subclasses override/extend this method to support more options.
+     */
+    abstract fun parseOption(option: String, ai: ArgIterator): Boolean
+
+    abstract fun dumpFields(): String
+}
+
+class ArgIterator(
+    private val args: List<String>,
+    private var currentIndex: Int = -1
+) {
+    val current: String
+        get() = args[currentIndex]
+
+    /**
+     * Get the next argument, or [null] if there's no more arguments.
+     */
+    fun nextArgOptional(): String? {
+        if ((currentIndex + 1) >= args.size) {
+            return null
+        }
+        return args[++currentIndex]
+    }
+
+    /**
+     * Get the next argument, or throw if
+     */
+    fun nextArgRequired(argName: String): String {
+        nextArgOptional().let {
+            if (it == null) {
+                throw ArgumentsException("Missing parameter for option $argName")
+            }
+            if (it.isEmpty()) {
+                throw ArgumentsException("Parameter can't be empty for option $argName")
+            }
+            return it
+        }
+    }
+
+    companion object {
+        fun withAtFiles(args: List<String>): ArgIterator {
+            return ArgIterator(expandAtFiles(args))
+        }
+
+        /**
+         * Scan the arguments, and if any of them starts with an `@`, then load from the file
+         * and use its content as arguments.
+         *
+         * In order to pass an argument that starts with an '@', use '@@' instead.
+         *
+         * In this file, each line is treated as a single argument.
+         *
+         * The file can contain '#' as comments.
+         */
+        private fun expandAtFiles(args: List<String>): List<String> {
+            val ret = mutableListOf<String>()
+
+            args.forEach { arg ->
+                if (arg.startsWith("@@")) {
+                    ret += arg.substring(1)
+                    return@forEach
+                } else if (!arg.startsWith('@')) {
+                    ret += arg
+                    return@forEach
+                }
+                // Read from the file, and add each line to the result.
+                val filename = arg.substring(1).ensureFileExists()
+
+                log.v("Expanding options file $filename")
+
+                BufferedReader(FileReader(filename)).use { reader ->
+                    while (true) {
+                        var line = reader.readLine() ?: break // EOF
+
+                        line = normalizeTextLine(line)
+                        if (line.isNotEmpty()) {
+                            ret += line
+                        }
+                    }
+                }
+            }
+            return ret
+        }
+    }
+}
+
+/**
+ * A single value that can only set once.
+ */
+open class SetOnce<T>(private var value: T) {
+    class SetMoreThanOnceException : Exception()
+
+    private var set = false
+
+    fun set(v: T): T {
+        if (set) {
+            throw SetMoreThanOnceException()
+        }
+        if (v == null) {
+            throw NullPointerException("This shouldn't happen")
+        }
+        set = true
+        value = v
+        return v
+    }
+
+    val get: T
+        get() = this.value
+
+    val isSet: Boolean
+        get() = this.set
+
+    fun <R> ifSet(block: (T & Any) -> R): R? {
+        if (isSet) {
+            return block(value!!)
+        }
+        return null
+    }
+
+    override fun toString(): String {
+        return "$value"
+    }
+}
+
+class IntSetOnce(value: Int) : SetOnce<Int>(value) {
+    fun set(v: String): Int {
+        try {
+            return this.set(v.toInt())
+        } catch (e: NumberFormatException) {
+            throw ArgumentsException("Invalid integer $v")
+        }
+    }
+}
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/Trie.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/Trie.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BaseAdapter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BaseAdapter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/Helper.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/Helper.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 7e294ed..3335405 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -17,36 +17,15 @@
 
 import com.android.hoststubgen.asm.ClassNodes
 import com.android.hoststubgen.dumper.ApiDumper
-import com.android.hoststubgen.filters.AnnotationBasedFilter
-import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
-import com.android.hoststubgen.filters.ConstantFilter
-import com.android.hoststubgen.filters.DefaultHookInjectingFilter
 import com.android.hoststubgen.filters.FilterPolicy
-import com.android.hoststubgen.filters.FilterRemapper
-import com.android.hoststubgen.filters.ImplicitOutputFilter
-import com.android.hoststubgen.filters.KeepNativeFilter
-import com.android.hoststubgen.filters.OutputFilter
-import com.android.hoststubgen.filters.SanitizationFilter
-import com.android.hoststubgen.filters.TextFileFilterPolicyBuilder
 import com.android.hoststubgen.filters.printAsTextPolicy
-import com.android.hoststubgen.utils.ClassPredicate
-import com.android.hoststubgen.visitors.BaseAdapter
-import com.android.hoststubgen.visitors.PackageRedirectRemapper
 import java.io.BufferedInputStream
 import java.io.BufferedOutputStream
 import java.io.FileOutputStream
-import java.io.InputStream
-import java.io.OutputStream
 import java.io.PrintWriter
 import java.util.zip.ZipEntry
 import java.util.zip.ZipFile
 import java.util.zip.ZipOutputStream
-import org.objectweb.asm.ClassReader
-import org.objectweb.asm.ClassVisitor
-import org.objectweb.asm.ClassWriter
-import org.objectweb.asm.commons.ClassRemapper
-import org.objectweb.asm.commons.Remapper
-import org.objectweb.asm.util.CheckClassAdapter
 
 /**
  * Actual main class.
@@ -76,21 +55,15 @@
             }
         }
 
-        // Build the filters.
-        val filter = buildFilter(errors, allClasses, options)
-
-        val filterRemapper = FilterRemapper(filter)
+        // Build the class processor
+        val processor = HostStubGenClassProcessor(options, allClasses, errors, stats)
 
         // Transform the jar.
         convert(
             options.inJar.get,
             options.outJar.get,
-            filter,
+            processor,
             options.enableClassChecker.get,
-            allClasses,
-            errors,
-            stats,
-            filterRemapper,
             options.numShards.get,
             options.shard.get,
         )
@@ -106,109 +79,20 @@
                 PrintWriter(it).use { pw ->
                     // TODO, when dumping a jar that's not framework-minus-apex.jar, we need to feed
                     // framework-minus-apex.jar so that we can dump inherited methods from it.
-                    ApiDumper(pw, allClasses, null, filter).dump()
+                    ApiDumper(pw, allClasses, null, processor.filter).dump()
                 }
             }
         }
     }
 
     /**
-     * Build the filter, which decides what classes/methods/fields should be put in stub or impl
-     * jars, and "how". (e.g. with substitution?)
-     */
-    private fun buildFilter(
-        errors: HostStubGenErrors,
-        allClasses: ClassNodes,
-        options: HostStubGenOptions,
-    ): OutputFilter {
-        // We build a "chain" of multiple filters here.
-        //
-        // The filters are build in from "inside", meaning the first filter created here is
-        // the last filter used, so it has the least precedence.
-        //
-        // So, for example, the "remove" annotation, which is handled by AnnotationBasedFilter,
-        // can override a class-wide annotation, which is handled by
-        // ClassWidePolicyPropagatingFilter, and any annotations can be overridden by the
-        // text-file based filter, which is handled by parseTextFilterPolicyFile.
-
-        // The first filter is for the default policy from the command line options.
-        var filter: OutputFilter = ConstantFilter(options.defaultPolicy.get, "default-by-options")
-
-        // Next, we build a filter that preserves all native methods by default
-        filter = KeepNativeFilter(allClasses, filter)
-
-        // Next, we need a filter that resolves "class-wide" policies.
-        // This is used when a member (methods, fields, nested classes) don't get any polices
-        // from upper filters. e.g. when a method has no annotations, then this filter will apply
-        // the class-wide policy, if any. (if not, we'll fall back to the above filter.)
-        filter = ClassWidePolicyPropagatingFilter(allClasses, filter)
-
-        // Inject default hooks from options.
-        filter = DefaultHookInjectingFilter(
-            allClasses,
-            options.defaultClassLoadHook.get,
-            options.defaultMethodCallHook.get,
-            filter
-        )
-
-        val annotationAllowedPredicate = options.annotationAllowedClassesFile.get.let { file ->
-            if (file == null) {
-                ClassPredicate.newConstantPredicate(true) // Allow all classes
-            } else {
-                ClassPredicate.loadFromFile(file, false)
-            }
-        }
-
-        // Next, Java annotation based filter.
-        val annotFilter = AnnotationBasedFilter(
-            errors,
-            allClasses,
-            options.keepAnnotations,
-            options.keepClassAnnotations,
-            options.throwAnnotations,
-            options.removeAnnotations,
-            options.ignoreAnnotations,
-            options.substituteAnnotations,
-            options.redirectAnnotations,
-            options.redirectionClassAnnotations,
-            options.classLoadHookAnnotations,
-            options.partiallyAllowedAnnotations,
-            options.keepStaticInitializerAnnotations,
-            annotationAllowedPredicate,
-            filter
-        )
-        filter = annotFilter
-
-        // Next, "text based" filter, which allows to override polices without touching
-        // the target code.
-        if (options.policyOverrideFiles.isNotEmpty()) {
-            val builder = TextFileFilterPolicyBuilder(allClasses, filter)
-            options.policyOverrideFiles.forEach(builder::parse)
-            filter = builder.createOutputFilter()
-            annotFilter.annotationAllowedMembers = builder.annotationAllowedMembersFilter
-        }
-
-        // Apply the implicit filter.
-        filter = ImplicitOutputFilter(errors, allClasses, filter)
-
-        // Add a final sanitization step.
-        filter = SanitizationFilter(errors, allClasses, filter)
-
-        return filter
-    }
-
-    /**
      * Convert a JAR file into "stub" and "impl" JAR files.
      */
     private fun convert(
         inJar: String,
         outJar: String?,
-        filter: OutputFilter,
+        processor: HostStubGenClassProcessor,
         enableChecker: Boolean,
-        classes: ClassNodes,
-        errors: HostStubGenErrors,
-        stats: HostStubGenStats,
-        remapper: Remapper?,
         numShards: Int,
         shard: Int
     ) {
@@ -216,8 +100,6 @@
         log.i("ASM CheckClassAdapter is %s", if (enableChecker) "enabled" else "disabled")
 
         log.iTime("Transforming jar") {
-            val packageRedirector = PackageRedirectRemapper(options.packageRedirects)
-
             var itemIndex = 0
             var numItemsProcessed = 0
             var numItems = -1 // == Unknown
@@ -240,11 +122,7 @@
                             if (!inShard) {
                                 continue
                             }
-                            convertSingleEntry(
-                                inZip, entry, outStream, filter,
-                                packageRedirector, remapper, enableChecker,
-                                classes, errors, stats
-                            )
+                            convertSingleEntry(inZip, entry, outStream, processor)
                             numItemsProcessed++
                         }
                         log.i("Converted all entries.")
@@ -270,13 +148,7 @@
         inZip: ZipFile,
         entry: ZipEntry,
         outStream: ZipOutputStream?,
-        filter: OutputFilter,
-        packageRedirector: PackageRedirectRemapper,
-        remapper: Remapper?,
-        enableChecker: Boolean,
-        classes: ClassNodes,
-        errors: HostStubGenErrors,
-        stats: HostStubGenStats
+        processor: HostStubGenClassProcessor
     ) {
         log.d("Entry: %s", entry.name)
         log.withIndent {
@@ -289,10 +161,7 @@
 
             // If it's a class, convert it.
             if (name.endsWith(".class")) {
-                processSingleClass(
-                    inZip, entry, outStream, filter, packageRedirector,
-                    remapper, enableChecker, classes, errors, stats
-                )
+                processSingleClass(inZip, entry, outStream, processor)
                 return
             }
 
@@ -332,29 +201,23 @@
     }
 
     /**
-     * Convert a single class to "stub" and "impl".
+     * Convert a single class.
      */
     private fun processSingleClass(
         inZip: ZipFile,
         entry: ZipEntry,
         outStream: ZipOutputStream?,
-        filter: OutputFilter,
-        packageRedirector: PackageRedirectRemapper,
-        remapper: Remapper?,
-        enableChecker: Boolean,
-        classes: ClassNodes,
-        errors: HostStubGenErrors,
-        stats: HostStubGenStats
+        processor: HostStubGenClassProcessor
     ) {
         val classInternalName = entry.name.replaceFirst("\\.class$".toRegex(), "")
-        val classPolicy = filter.getPolicyForClass(classInternalName)
+        val classPolicy = processor.filter.getPolicyForClass(classInternalName)
         if (classPolicy.policy == FilterPolicy.Remove) {
             log.d("Removing class: %s %s", classInternalName, classPolicy)
             return
         }
         // If we're applying a remapper, we need to rename the file too.
         var newName = entry.name
-        remapper?.mapType(classInternalName)?.let { remappedName ->
+        processor.remapper.mapType(classInternalName)?.let { remappedName ->
             if (remappedName != classInternalName) {
                 log.d("Renaming class file: %s -> %s", classInternalName, remappedName)
                 newName = "$remappedName.class"
@@ -367,64 +230,11 @@
                 BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
                     val newEntry = ZipEntry(newName)
                     outStream.putNextEntry(newEntry)
-                    convertClass(
-                        classInternalName, bis,
-                        outStream, filter, packageRedirector, remapper,
-                        enableChecker, classes, errors, stats
-                    )
+                    val classBytecode = bis.readAllBytes()
+                    outStream.write(processor.processClassBytecode(classBytecode))
                     outStream.closeEntry()
                 }
             }
         }
     }
-
-    /**
-     * Convert a single class to either "stub" or "impl".
-     */
-    private fun convertClass(
-        classInternalName: String,
-        input: InputStream,
-        out: OutputStream,
-        filter: OutputFilter,
-        packageRedirector: PackageRedirectRemapper,
-        remapper: Remapper?,
-        enableChecker: Boolean,
-        classes: ClassNodes,
-        errors: HostStubGenErrors,
-        stats: HostStubGenStats?
-    ) {
-        val cr = ClassReader(input)
-
-        // COMPUTE_FRAMES wouldn't be happy if code uses
-        val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES
-        val cw = ClassWriter(flags)
-
-        // Connect to the class writer
-        var outVisitor: ClassVisitor = cw
-        if (enableChecker) {
-            outVisitor = CheckClassAdapter(outVisitor)
-        }
-
-        // Remapping should happen at the end.
-        remapper?.let {
-            outVisitor = ClassRemapper(outVisitor, remapper)
-        }
-
-        val visitorOptions = BaseAdapter.Options(
-            errors = errors,
-            stats = stats,
-            enablePreTrace = options.enablePreTrace.get,
-            enablePostTrace = options.enablePostTrace.get,
-            deleteClassFinals = options.deleteFinals.get,
-            deleteMethodFinals = options.deleteFinals.get,
-        )
-        outVisitor = BaseAdapter.getVisitor(
-            classInternalName, classes, outVisitor, filter,
-            packageRedirector, visitorOptions
-        )
-
-        cr.accept(outVisitor, ClassReader.EXPAND_FRAMES)
-        val data = cw.toByteArray()
-        out.write(data)
-    }
 }
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
index 8506466..4ba8c5c 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
@@ -17,8 +17,6 @@
 
 package com.android.hoststubgen
 
-import java.io.PrintWriter
-
 /**
  * Entry point.
  */
@@ -26,10 +24,10 @@
     executableName = "HostStubGen"
     runMainWithBoilerplate {
         // Parse the command line arguments.
-        var clanupOnError = false
+        var cleanupOnError = false
         try {
-            val options = HostStubGenOptions.parseArgs(args)
-            clanupOnError = options.cleanUpOnError.get
+            val options = HostStubGenOptions().apply { parseArgs(args.asList()) }
+            cleanupOnError = options.cleanUpOnError.get
 
             log.v("$executableName started")
             log.v("Options: $options")
@@ -37,30 +35,10 @@
             // Run.
             HostStubGen(options).run()
         } catch (e: Throwable) {
-            if (clanupOnError) {
+            if (cleanupOnError) {
                 TODO("Remove output jars here")
             }
             throw e
         }
     }
 }
-
-inline fun runMainWithBoilerplate(realMain: () -> Unit) {
-    var success = false
-
-    try {
-        realMain()
-
-        success = true
-    } catch (e: Throwable) {
-        log.e("$executableName: Error: ${e.message}")
-        if (e !is UserErrorException) {
-            e.printStackTrace(PrintWriter(log.getWriter(LogLevel.Error)))
-        }
-    } finally {
-        log.i("$executableName finished")
-        log.flush()
-    }
-
-    System.exit(if (success) 0 else 1 )
-}
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index 1ab88d2..8bb454f 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -15,385 +15,102 @@
  */
 package com.android.hoststubgen
 
-import com.android.hoststubgen.filters.FilterPolicy
-import java.io.BufferedReader
-import java.io.FileReader
-
-/**
- * A single value that can only set once.
- */
-open class SetOnce<T>(private var value: T) {
-    class SetMoreThanOnceException : Exception()
-
-    private var set = false
-
-    fun set(v: T): T {
-        if (set) {
-            throw SetMoreThanOnceException()
-        }
-        if (v == null) {
-            throw NullPointerException("This shouldn't happen")
-        }
-        set = true
-        value = v
-        return v
-    }
-
-    val get: T
-        get() = this.value
-
-    val isSet: Boolean
-        get() = this.set
-
-    fun <R> ifSet(block: (T & Any) -> R): R? {
-        if (isSet) {
-            return block(value!!)
-        }
-        return null
-    }
-
-    override fun toString(): String {
-        return "$value"
-    }
-}
-
-class IntSetOnce(value: Int) : SetOnce<Int>(value) {
-    fun set(v: String): Int {
-        try {
-            return this.set(v.toInt())
-        } catch (e: NumberFormatException) {
-            throw ArgumentsException("Invalid integer $v")
-        }
-    }
-}
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.IntSetOnce
+import com.android.hoststubgen.utils.SetOnce
 
 /**
  * Options that can be set from command line arguments.
  */
 class HostStubGenOptions(
-        /** Input jar file*/
-        var inJar: SetOnce<String> = SetOnce(""),
+    /** Input jar file*/
+    var inJar: SetOnce<String> = SetOnce(""),
 
-        /** Output jar file */
-        var outJar: SetOnce<String?> = SetOnce(null),
+    /** Output jar file */
+    var outJar: SetOnce<String?> = SetOnce(null),
 
-        var inputJarDumpFile: SetOnce<String?> = SetOnce(null),
+    var inputJarDumpFile: SetOnce<String?> = SetOnce(null),
 
-        var inputJarAsKeepAllFile: SetOnce<String?> = SetOnce(null),
+    var inputJarAsKeepAllFile: SetOnce<String?> = SetOnce(null),
 
-        var keepAnnotations: MutableSet<String> = mutableSetOf(),
-        var throwAnnotations: MutableSet<String> = mutableSetOf(),
-        var removeAnnotations: MutableSet<String> = mutableSetOf(),
-        var ignoreAnnotations: MutableSet<String> = mutableSetOf(),
-        var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
-        var partiallyAllowedAnnotations: MutableSet<String> = mutableSetOf(),
-        var redirectAnnotations: MutableSet<String> = mutableSetOf(),
+    var cleanUpOnError: SetOnce<Boolean> = SetOnce(false),
 
-        var substituteAnnotations: MutableSet<String> = mutableSetOf(),
-        var redirectionClassAnnotations: MutableSet<String> = mutableSetOf(),
-        var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
-        var keepStaticInitializerAnnotations: MutableSet<String> = mutableSetOf(),
+    var statsFile: SetOnce<String?> = SetOnce(null),
 
-        var packageRedirects: MutableList<Pair<String, String>> = mutableListOf(),
+    var apiListFile: SetOnce<String?> = SetOnce(null),
 
-        var annotationAllowedClassesFile: SetOnce<String?> = SetOnce(null),
+    var numShards: IntSetOnce = IntSetOnce(1),
+    var shard: IntSetOnce = IntSetOnce(0),
+) : HostStubGenClassProcessorOptions() {
 
-        var defaultClassLoadHook: SetOnce<String?> = SetOnce(null),
-        var defaultMethodCallHook: SetOnce<String?> = SetOnce(null),
-
-        var policyOverrideFiles: MutableList<String> = mutableListOf(),
-
-        var defaultPolicy: SetOnce<FilterPolicy> = SetOnce(FilterPolicy.Remove),
-
-        var cleanUpOnError: SetOnce<Boolean> = SetOnce(false),
-
-        var deleteFinals: SetOnce<Boolean> = SetOnce(false),
-
-        var enableClassChecker: SetOnce<Boolean> = SetOnce(false),
-        var enablePreTrace: SetOnce<Boolean> = SetOnce(false),
-        var enablePostTrace: SetOnce<Boolean> = SetOnce(false),
-
-        var statsFile: SetOnce<String?> = SetOnce(null),
-
-        var apiListFile: SetOnce<String?> = SetOnce(null),
-
-        var numShards: IntSetOnce = IntSetOnce(1),
-        var shard: IntSetOnce = IntSetOnce(0),
-) {
-    companion object {
-
-        private fun parsePackageRedirect(fromColonTo: String): Pair<String, String> {
-            val colon = fromColonTo.indexOf(':')
-            if ((colon < 1) || (colon + 1 >= fromColonTo.length)) {
-                throw ArgumentsException("--package-redirect must be a colon-separated string")
-            }
-            // TODO check for duplicates
-            return Pair(fromColonTo.substring(0, colon), fromColonTo.substring(colon + 1))
+    override fun checkArgs() {
+        if (!inJar.isSet) {
+            throw ArgumentsException("Required option missing: --in-jar")
+        }
+        if (!outJar.isSet) {
+            log.w("--out-jar is not set. $executableName will not generate jar files.")
+        }
+        if (numShards.isSet != shard.isSet) {
+            throw ArgumentsException("--num-shards and --shard-index must be used together")
         }
 
-        fun parseArgs(args: Array<String>): HostStubGenOptions {
-            val ret = HostStubGenOptions()
-
-            val ai = ArgIterator.withAtFiles(args)
-
-            var allAnnotations = mutableSetOf<String>()
-
-            fun ensureUniqueAnnotation(name: String): String {
-                if (!allAnnotations.add(name)) {
-                    throw DuplicateAnnotationException(ai.current)
-                }
-                return name
+        if (numShards.isSet) {
+            if (shard.get >= numShards.get) {
+                throw ArgumentsException("--shard-index must be smaller than --num-shards")
             }
-
-            while (true) {
-                val arg = ai.nextArgOptional() ?: break
-
-                // Define some shorthands...
-                fun nextArg(): String = ai.nextArgRequired(arg)
-                fun MutableSet<String>.addUniqueAnnotationArg(): String =
-                        nextArg().also { this += ensureUniqueAnnotation(it) }
-
-                if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
-                    continue
-                }
-                try {
-                    when (arg) {
-                        // TODO: Write help
-                        "-h", "--help" -> TODO("Help is not implemented yet")
-
-                        "--in-jar" -> ret.inJar.set(nextArg()).ensureFileExists()
-                        // We support both arguments because some AOSP dependencies
-                        // still use the old argument
-                        "--out-jar", "--out-impl-jar" -> ret.outJar.set(nextArg())
-
-                        "--policy-override-file" ->
-                            ret.policyOverrideFiles.add(nextArg().ensureFileExists())
-
-                        "--clean-up-on-error" -> ret.cleanUpOnError.set(true)
-                        "--no-clean-up-on-error" -> ret.cleanUpOnError.set(false)
-
-                        "--default-remove" -> ret.defaultPolicy.set(FilterPolicy.Remove)
-                        "--default-throw" -> ret.defaultPolicy.set(FilterPolicy.Throw)
-                        "--default-keep" -> ret.defaultPolicy.set(FilterPolicy.Keep)
-
-                        "--keep-annotation" ->
-                            ret.keepAnnotations.addUniqueAnnotationArg()
-
-                        "--keep-class-annotation" ->
-                            ret.keepClassAnnotations.addUniqueAnnotationArg()
-
-                        "--partially-allowed-annotation" ->
-                            ret.partiallyAllowedAnnotations.addUniqueAnnotationArg()
-
-                        "--throw-annotation" ->
-                            ret.throwAnnotations.addUniqueAnnotationArg()
-
-                        "--remove-annotation" ->
-                            ret.removeAnnotations.addUniqueAnnotationArg()
-
-                        "--ignore-annotation" ->
-                            ret.ignoreAnnotations.addUniqueAnnotationArg()
-
-                        "--substitute-annotation" ->
-                            ret.substituteAnnotations.addUniqueAnnotationArg()
-
-                        "--redirect-annotation" ->
-                            ret.redirectAnnotations.addUniqueAnnotationArg()
-
-                        "--redirection-class-annotation" ->
-                            ret.redirectionClassAnnotations.addUniqueAnnotationArg()
-
-                        "--class-load-hook-annotation" ->
-                            ret.classLoadHookAnnotations.addUniqueAnnotationArg()
-
-                        "--keep-static-initializer-annotation" ->
-                            ret.keepStaticInitializerAnnotations.addUniqueAnnotationArg()
-
-                        "--package-redirect" ->
-                            ret.packageRedirects += parsePackageRedirect(nextArg())
-
-                        "--annotation-allowed-classes-file" ->
-                            ret.annotationAllowedClassesFile.set(nextArg())
-
-                        "--default-class-load-hook" ->
-                            ret.defaultClassLoadHook.set(nextArg())
-
-                        "--default-method-call-hook" ->
-                            ret.defaultMethodCallHook.set(nextArg())
-
-                        "--gen-keep-all-file" ->
-                            ret.inputJarAsKeepAllFile.set(nextArg())
-
-                        "--delete-finals" -> ret.deleteFinals.set(true)
-
-                        // Following options are for debugging.
-                        "--enable-class-checker" -> ret.enableClassChecker.set(true)
-                        "--no-class-checker" -> ret.enableClassChecker.set(false)
-
-                        "--enable-pre-trace" -> ret.enablePreTrace.set(true)
-                        "--no-pre-trace" -> ret.enablePreTrace.set(false)
-
-                        "--enable-post-trace" -> ret.enablePostTrace.set(true)
-                        "--no-post-trace" -> ret.enablePostTrace.set(false)
-
-                        "--gen-input-dump-file" -> ret.inputJarDumpFile.set(nextArg())
-
-                        "--stats-file" -> ret.statsFile.set(nextArg())
-                        "--supported-api-list-file" -> ret.apiListFile.set(nextArg())
-
-                        "--num-shards" -> ret.numShards.set(nextArg()).also {
-                            if (it < 1) {
-                                throw ArgumentsException("$arg must be positive integer")
-                            }
-                        }
-                        "--shard-index" -> ret.shard.set(nextArg()).also {
-                            if (it < 0) {
-                                throw ArgumentsException("$arg must be positive integer or zero")
-                            }
-                        }
-
-                        else -> throw ArgumentsException("Unknown option: $arg")
-                    }
-                } catch (e: SetOnce.SetMoreThanOnceException) {
-                    throw ArgumentsException("Duplicate or conflicting argument found: $arg")
-                }
-            }
-
-            if (!ret.inJar.isSet) {
-                throw ArgumentsException("Required option missing: --in-jar")
-            }
-            if (!ret.outJar.isSet) {
-                log.w("--out-jar is not set. $executableName will not generate jar files.")
-            }
-            if (ret.numShards.isSet != ret.shard.isSet) {
-                throw ArgumentsException("--num-shards and --shard-index must be used together")
-            }
-
-            if (ret.numShards.isSet) {
-                if (ret.shard.get >= ret.numShards.get) {
-                    throw ArgumentsException("--shard-index must be smaller than --num-shards")
-                }
-            }
-
-            return ret
         }
     }
 
-    override fun toString(): String {
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        // Define some shorthands...
+        fun nextArg(): String = ai.nextArgRequired(option)
+
+        when (option) {
+            // TODO: Write help
+            "-h", "--help" -> TODO("Help is not implemented yet")
+
+            "--in-jar" -> inJar.set(nextArg()).ensureFileExists()
+            // We support both arguments because some AOSP dependencies
+            // still use the old argument
+            "--out-jar", "--out-impl-jar" -> outJar.set(nextArg())
+
+            "--clean-up-on-error" -> cleanUpOnError.set(true)
+            "--no-clean-up-on-error" -> cleanUpOnError.set(false)
+
+            "--gen-input-dump-file" -> inputJarDumpFile.set(nextArg())
+            "--gen-keep-all-file" -> inputJarAsKeepAllFile.set(nextArg())
+
+            "--stats-file" -> statsFile.set(nextArg())
+            "--supported-api-list-file" -> apiListFile.set(nextArg())
+
+            "--num-shards" -> numShards.set(nextArg()).also {
+                if (it < 1) {
+                    throw ArgumentsException("$option must be positive integer")
+                }
+            }
+            "--shard-index" -> shard.set(nextArg()).also {
+                if (it < 0) {
+                    throw ArgumentsException("$option must be positive integer or zero")
+                }
+            }
+
+            else -> return super.parseOption(option, ai)
+        }
+
+        return true
+    }
+
+    override fun dumpFields(): String {
         return """
-            HostStubGenOptions{
-              inJar='$inJar',
-              outJar='$outJar',
-              inputJarDumpFile=$inputJarDumpFile,
-              inputJarAsKeepAllFile=$inputJarAsKeepAllFile,
-              keepAnnotations=$keepAnnotations,
-              throwAnnotations=$throwAnnotations,
-              removeAnnotations=$removeAnnotations,
-              ignoreAnnotations=$ignoreAnnotations,
-              keepClassAnnotations=$keepClassAnnotations,
-              partiallyAllowedAnnotations=$partiallyAllowedAnnotations,
-              substituteAnnotations=$substituteAnnotations,
-              nativeSubstituteAnnotations=$redirectionClassAnnotations,
-              classLoadHookAnnotations=$classLoadHookAnnotations,
-              keepStaticInitializerAnnotations=$keepStaticInitializerAnnotations,
-              packageRedirects=$packageRedirects,
-              annotationAllowedClassesFile=$annotationAllowedClassesFile,
-              defaultClassLoadHook=$defaultClassLoadHook,
-              defaultMethodCallHook=$defaultMethodCallHook,
-              policyOverrideFiles=${policyOverrideFiles.toTypedArray().contentToString()},
-              defaultPolicy=$defaultPolicy,
-              deleteFinals=$deleteFinals,
-              cleanUpOnError=$cleanUpOnError,
-              enableClassChecker=$enableClassChecker,
-              enablePreTrace=$enablePreTrace,
-              enablePostTrace=$enablePostTrace,
-              statsFile=$statsFile,
-              apiListFile=$apiListFile,
-              numShards=$numShards,
-              shard=$shard,
-            }
-            """.trimIndent()
+            inJar=$inJar,
+            outJar=$outJar,
+            inputJarDumpFile=$inputJarDumpFile,
+            inputJarAsKeepAllFile=$inputJarAsKeepAllFile,
+            cleanUpOnError=$cleanUpOnError,
+            statsFile=$statsFile,
+            apiListFile=$apiListFile,
+            numShards=$numShards,
+            shard=$shard,
+        """.trimIndent() + '\n' + super.dumpFields()
     }
 }
-
-class ArgIterator(
-    private val args: List<String>,
-    private var currentIndex: Int = -1
-) {
-    val current: String
-        get() = args.get(currentIndex)
-
-    /**
-     * Get the next argument, or [null] if there's no more arguments.
-     */
-    fun nextArgOptional(): String? {
-        if ((currentIndex + 1) >= args.size) {
-            return null
-        }
-        return args.get(++currentIndex)
-    }
-
-    /**
-     * Get the next argument, or throw if
-     */
-    fun nextArgRequired(argName: String): String {
-        nextArgOptional().let {
-            if (it == null) {
-                throw ArgumentsException("Missing parameter for option $argName")
-            }
-            if (it.isEmpty()) {
-                throw ArgumentsException("Parameter can't be empty for option $argName")
-            }
-            return it
-        }
-    }
-
-    companion object {
-        fun withAtFiles(args: Array<String>): ArgIterator {
-            return ArgIterator(expandAtFiles(args))
-        }
-    }
-}
-
-/**
- * Scan the arguments, and if any of them starts with an `@`, then load from the file
- * and use its content as arguments.
- *
- * In order to pass an argument that starts with an '@', use '@@' instead.
- *
- * In this file, each line is treated as a single argument.
- *
- * The file can contain '#' as comments.
- */
-private fun expandAtFiles(args: Array<String>): List<String> {
-    val ret = mutableListOf<String>()
-
-    args.forEach { arg ->
-        if (arg.startsWith("@@")) {
-            ret += arg.substring(1)
-            return@forEach
-        } else if (!arg.startsWith('@')) {
-            ret += arg
-            return@forEach
-        }
-        // Read from the file, and add each line to the result.
-        val filename = arg.substring(1).ensureFileExists()
-
-        log.v("Expanding options file $filename")
-
-        BufferedReader(FileReader(filename)).use { reader ->
-            while (true) {
-                var line = reader.readLine()
-                if (line == null) {
-                    break // EOF
-                }
-
-                line = normalizeTextLine(line)
-                if (line.isNotEmpty()) {
-                    ret += line
-                }
-            }
-        }
-    }
-    return ret
-}
diff --git a/ravenwood/tools/ravenhelper/Android.bp b/ravenwood/tools/ravenhelper/Android.bp
index 3da6dd8..b279147 100644
--- a/ravenwood/tools/ravenhelper/Android.bp
+++ b/ravenwood/tools/ravenhelper/Android.bp
@@ -14,13 +14,7 @@
     static_libs: [
         "guava",
         "hoststubgen-lib",
-        "junit",
         "metalava-gradle-plugin-deps", // Get lint/PSI related classes from here.
-        "ow2-asm",
-        "ow2-asm-analysis",
-        "ow2-asm-commons",
-        "ow2-asm-tree",
-        "ow2-asm-util",
     ],
     visibility: ["//visibility:public"],
 }
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt
index 08bd95f..f7fd080 100644
--- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt
@@ -15,11 +15,11 @@
  */
 package com.android.platform.test.ravenwood.ravenhelper.policytoannot
 
-import com.android.hoststubgen.ArgIterator
 import com.android.hoststubgen.ArgumentsException
-import com.android.hoststubgen.SetOnce
 import com.android.hoststubgen.ensureFileExists
-import com.android.hoststubgen.log
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.BaseOptions
+import com.android.hoststubgen.utils.SetOnce
 
 /**
  * Options for the "ravenhelper pta" subcommand.
@@ -39,68 +39,48 @@
 
     /** Dump the operations (for debugging) */
     var dumpOperations: SetOnce<Boolean> = SetOnce(false),
-) {
-    companion object {
-        fun parseArgs(args: List<String>): PtaOptions {
-            val ret = PtaOptions()
-            val ai = ArgIterator.withAtFiles(args.toTypedArray())
+) : BaseOptions() {
 
-            while (true) {
-                val arg = ai.nextArgOptional() ?: break
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        fun nextArg(): String = ai.nextArgRequired(option)
 
-                fun nextArg(): String = ai.nextArgRequired(arg)
+        when (option) {
+            // TODO: Write help
+            "-h", "--help" -> TODO("Help is not implemented yet")
 
-                if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
-                    continue
-                }
-                try {
-                    when (arg) {
-                        // TODO: Write help
-                        "-h", "--help" -> TODO("Help is not implemented yet")
+            "-p", "--policy-override-file" ->
+                policyOverrideFiles.add(nextArg().ensureFileExists())
 
-                        "-p", "--policy-override-file" ->
-                            ret.policyOverrideFiles.add(nextArg().ensureFileExists())
+            "-a", "--annotation-allowed-classes-file" ->
+                annotationAllowedClassesFile.set(nextArg().ensureFileExists())
 
-                        "-a", "--annotation-allowed-classes-file" ->
-                            ret.annotationAllowedClassesFile.set(nextArg().ensureFileExists())
+            "-s", "--src" -> sourceFilesOrDirectories.add(nextArg().ensureFileExists())
+            "--dump" -> dumpOperations.set(true)
+            "-o", "--output-script" -> outputScriptFile.set(nextArg())
 
-                        "-s", "--src" ->
-                            ret.sourceFilesOrDirectories.add(nextArg().ensureFileExists())
+            else -> return false
+        }
 
-                        "--dump" ->
-                            ret.dumpOperations.set(true)
+        return true
+    }
 
-                        "-o", "--output-script" ->
-                            ret.outputScriptFile.set(nextArg())
+    override fun checkArgs() {
+        if (policyOverrideFiles.size == 0) {
+            throw ArgumentsException("Must specify at least one policy file")
+        }
 
-                        else -> throw ArgumentsException("Unknown option: $arg")
-                    }
-                } catch (e: SetOnce.SetMoreThanOnceException) {
-                    throw ArgumentsException("Duplicate or conflicting argument found: $arg")
-                }
-            }
-
-            if (ret.policyOverrideFiles.size == 0) {
-                throw ArgumentsException("Must specify at least one policy file")
-            }
-
-            if (ret.sourceFilesOrDirectories.size == 0) {
-                throw ArgumentsException("Must specify at least one source path")
-            }
-
-            return ret
+        if (sourceFilesOrDirectories.size == 0) {
+            throw ArgumentsException("Must specify at least one source path")
         }
     }
 
-    override fun toString(): String {
+    override fun dumpFields(): String {
         return """
-            PtaOptions{
-              policyOverrideFiles=$policyOverrideFiles
-              annotationAllowedClassesFile=$annotationAllowedClassesFile
-              sourceFilesOrDirectories=$sourceFilesOrDirectories
-              outputScriptFile=$outputScriptFile
-              dumpOperations=$dumpOperations
-            }
-            """.trimIndent()
+            policyOverrideFiles=$policyOverrideFiles
+            annotationAllowedClassesFile=$annotationAllowedClassesFile
+            sourceFilesOrDirectories=$sourceFilesOrDirectories
+            outputScriptFile=$outputScriptFile
+            dumpOperations=$dumpOperations
+        """.trimIndent()
     }
-}
\ No newline at end of file
+}
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt
index a7f481a..fd6f732 100644
--- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt
@@ -39,7 +39,7 @@
  */
 class PtaProcessor : SubcommandHandler {
     override fun handle(args: List<String>) {
-        val options = PtaOptions.parseArgs(args)
+        val options = PtaOptions().apply { parseArgs(args) }
 
         log.v("Options: $options")
 
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt
index ee200bb..8b95843 100644
--- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt
@@ -15,11 +15,11 @@
  */
 package com.android.platform.test.ravenwood.ravenhelper.sourcemap
 
-import com.android.hoststubgen.ArgIterator
 import com.android.hoststubgen.ArgumentsException
-import com.android.hoststubgen.SetOnce
 import com.android.hoststubgen.ensureFileExists
-import com.android.hoststubgen.log
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.BaseOptions
+import com.android.hoststubgen.utils.SetOnce
 
 /**
  * Options for the "ravenhelper map" subcommand.
@@ -36,60 +36,36 @@
 
     /** Text to insert. */
     var text: SetOnce<String?> = SetOnce(null),
-) {
-    companion object {
-        fun parseArgs(args: List<String>): MapOptions {
-            val ret = MapOptions()
-            val ai = ArgIterator.withAtFiles(args.toTypedArray())
+) : BaseOptions() {
 
-            while (true) {
-                val arg = ai.nextArgOptional() ?: break
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        fun nextArg(): String = ai.nextArgRequired(option)
 
-                fun nextArg(): String = ai.nextArgRequired(arg)
+        when (option) {
+            // TODO: Write help
+            "-h", "--help" -> TODO("Help is not implemented yet")
+            "-s", "--src" -> sourceFilesOrDirectories.add(nextArg().ensureFileExists())
+            "-i", "--input" -> targetMethodFiles.add(nextArg().ensureFileExists())
+            "-o", "--output-script" -> outputScriptFile.set(nextArg())
+            "-t", "--text" -> text.set(nextArg())
+            else -> return false
+        }
 
-                if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
-                    continue
-                }
-                try {
-                    when (arg) {
-                        // TODO: Write help
-                        "-h", "--help" -> TODO("Help is not implemented yet")
+        return true
+    }
 
-                        "-s", "--src" ->
-                            ret.sourceFilesOrDirectories.add(nextArg().ensureFileExists())
-
-                        "-i", "--input" ->
-                            ret.targetMethodFiles.add(nextArg().ensureFileExists())
-
-                        "-o", "--output-script" ->
-                            ret.outputScriptFile.set(nextArg())
-
-                        "-t", "--text" ->
-                            ret.text.set(nextArg())
-
-                        else -> throw ArgumentsException("Unknown option: $arg")
-                    }
-                } catch (e: SetOnce.SetMoreThanOnceException) {
-                    throw ArgumentsException("Duplicate or conflicting argument found: $arg")
-                }
-            }
-
-            if (ret.sourceFilesOrDirectories.size == 0) {
-                throw ArgumentsException("Must specify at least one source path")
-            }
-
-            return ret
+    override fun checkArgs() {
+        if (sourceFilesOrDirectories.size == 0) {
+            throw ArgumentsException("Must specify at least one source path")
         }
     }
 
-    override fun toString(): String {
+    override fun dumpFields(): String {
         return """
-            PtaOptions{
-              sourceFilesOrDirectories=$sourceFilesOrDirectories
-              targetMethods=$targetMethodFiles
-              outputScriptFile=$outputScriptFile
-              text=$text
-            }
-            """.trimIndent()
+            sourceFilesOrDirectories=$sourceFilesOrDirectories
+            targetMethods=$targetMethodFiles
+            outputScriptFile=$outputScriptFile
+            text=$text
+        """.trimIndent()
     }
-}
\ No newline at end of file
+}
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt
index 8085253..f1c1398 100644
--- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt
@@ -35,7 +35,7 @@
  */
 class MarkMethodHandler : SubcommandHandler {
     override fun handle(args: List<String>) {
-        val options = MapOptions.parseArgs(args)
+        val options = MapOptions().apply { parseArgs(args) }
 
         log.i("Options: $options")
 
diff --git a/ravenwood/tools/ravenizer/Android.bp b/ravenwood/tools/ravenizer/Android.bp
index a52a04b..957e206 100644
--- a/ravenwood/tools/ravenizer/Android.bp
+++ b/ravenwood/tools/ravenizer/Android.bp
@@ -13,12 +13,6 @@
     srcs: ["src/**/*.kt"],
     static_libs: [
         "hoststubgen-lib",
-        "ow2-asm",
-        "ow2-asm-analysis",
-        "ow2-asm-commons",
-        "ow2-asm-tree",
-        "ow2-asm-util",
-        "junit",
         "ravenwood-junit-for-ravenizer",
     ],
     visibility: ["//visibility:public"],
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt
index aee4530..7f4829e 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt
@@ -21,6 +21,21 @@
 import com.android.hoststubgen.executableName
 import com.android.hoststubgen.log
 import com.android.hoststubgen.runMainWithBoilerplate
+import java.nio.file.Paths
+import kotlin.io.path.exists
+
+/**
+ * If this file exits, we also read options from it. This is "unsafe" because it could break
+ * incremental builds, if it sets any flag that affects the output file.
+ * (however, for now, there's no such options.)
+ *
+ * For example, to enable verbose logging, do `echo '-v' > ~/.raveniezr-unsafe`
+ *
+ * (but even the content of this file changes, soong won't rerun the command, so you need to
+ * remove the output first and then do a build again.)
+ */
+private val RAVENIZER_DOTFILE = System.getenv("HOME") + "/.ravenizer-unsafe"
+
 
 /**
  * Entry point.
@@ -30,7 +45,15 @@
     log.setConsoleLogLevel(LogLevel.Info)
 
     runMainWithBoilerplate {
-        val options = RavenizerOptions.parseArgs(args)
+        var newArgs = args.asList()
+        if (Paths.get(RAVENIZER_DOTFILE).exists()) {
+            log.i("Reading options from $RAVENIZER_DOTFILE")
+            newArgs = args.toMutableList().apply {
+                add(0, "@$RAVENIZER_DOTFILE")
+            }
+        }
+
+        val options = RavenizerOptions().apply { parseArgs(newArgs) }
 
         log.i("$executableName started")
         log.v("Options: $options")
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
index a0e5599..2c03654 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
@@ -15,25 +15,11 @@
  */
 package com.android.platform.test.ravenwood.ravenizer
 
-import com.android.hoststubgen.ArgIterator
 import com.android.hoststubgen.ArgumentsException
-import com.android.hoststubgen.SetOnce
 import com.android.hoststubgen.ensureFileExists
-import com.android.hoststubgen.log
-import java.nio.file.Paths
-import kotlin.io.path.exists
-
-/**
- * If this file exits, we also read options from it. This is "unsafe" because it could break
- * incremental builds, if it sets any flag that affects the output file.
- * (however, for now, there's no such options.)
- *
- * For example, to enable verbose logging, do `echo '-v' > ~/.raveniezr-unsafe`
- *
- * (but even the content of this file changes, soong won't rerun the command, so you need to
- * remove the output first and then do a build again.)
- */
-private val RAVENIZER_DOTFILE = System.getenv("HOME") + "/.raveniezr-unsafe"
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.BaseOptions
+import com.android.hoststubgen.utils.SetOnce
 
 class RavenizerOptions(
     /** Input jar file*/
@@ -50,72 +36,49 @@
 
     /** Whether to remove mockito and dexmaker classes. */
     var stripMockito: SetOnce<Boolean> = SetOnce(false),
-) {
-    companion object {
+) : BaseOptions() {
 
-        fun parseArgs(origArgs: Array<String>): RavenizerOptions {
-            val args = origArgs.toMutableList()
-            if (Paths.get(RAVENIZER_DOTFILE).exists()) {
-                log.i("Reading options from $RAVENIZER_DOTFILE")
-                args.add(0, "@$RAVENIZER_DOTFILE")
-            }
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        fun nextArg(): String = ai.nextArgRequired(option)
 
-            val ret = RavenizerOptions()
-            val ai = ArgIterator.withAtFiles(args.toTypedArray())
+        when (option) {
+            // TODO: Write help
+            "-h", "--help" -> TODO("Help is not implemented yet")
 
-            while (true) {
-                val arg = ai.nextArgOptional()
-                if (arg == null) {
-                    break
-                }
+            "--in-jar" -> inJar.set(nextArg()).ensureFileExists()
+            "--out-jar" -> outJar.set(nextArg())
 
-                fun nextArg(): String = ai.nextArgRequired(arg)
+            "--enable-validation" -> enableValidation.set(true)
+            "--disable-validation" -> enableValidation.set(false)
 
-                if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
-                    continue
-                }
-                try {
-                    when (arg) {
-                        // TODO: Write help
-                        "-h", "--help" -> TODO("Help is not implemented yet")
+            "--fatal-validation" -> fatalValidation.set(true)
+            "--no-fatal-validation" -> fatalValidation.set(false)
 
-                        "--in-jar" -> ret.inJar.set(nextArg()).ensureFileExists()
-                        "--out-jar" -> ret.outJar.set(nextArg())
+            "--strip-mockito" -> stripMockito.set(true)
+            "--no-strip-mockito" -> stripMockito.set(false)
 
-                        "--enable-validation" -> ret.enableValidation.set(true)
-                        "--disable-validation" -> ret.enableValidation.set(false)
+            else -> return false
+        }
 
-                        "--fatal-validation" -> ret.fatalValidation.set(true)
-                        "--no-fatal-validation" -> ret.fatalValidation.set(false)
+        return true
+    }
 
-                        "--strip-mockito" -> ret.stripMockito.set(true)
-                        "--no-strip-mockito" -> ret.stripMockito.set(false)
-
-                        else -> throw ArgumentsException("Unknown option: $arg")
-                    }
-                } catch (e: SetOnce.SetMoreThanOnceException) {
-                    throw ArgumentsException("Duplicate or conflicting argument found: $arg")
-                }
-            }
-
-            if (!ret.inJar.isSet) {
-                throw ArgumentsException("Required option missing: --in-jar")
-            }
-            if (!ret.outJar.isSet) {
-                throw ArgumentsException("Required option missing: --out-jar")
-            }
-           return ret
+    override fun checkArgs() {
+        if (!inJar.isSet) {
+            throw ArgumentsException("Required option missing: --in-jar")
+        }
+        if (!outJar.isSet) {
+            throw ArgumentsException("Required option missing: --out-jar")
         }
     }
 
-    override fun toString(): String {
+    override fun dumpFields(): String {
         return """
-            RavenizerOptions{
-              inJar=$inJar,
-              outJar=$outJar,
-              enableValidation=$enableValidation,
-              fatalValidation=$fatalValidation,
-            }
-            """.trimIndent()
+            inJar=$inJar,
+            outJar=$outJar,
+            enableValidation=$enableValidation,
+            fatalValidation=$fatalValidation,
+            stripMockito=$stripMockito,
+        """.trimIndent()
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 42834ce..c49151d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -287,7 +287,8 @@
 
     public static final int INVALID_SERVICE_ID = -1;
 
-    // Each service has an ID. Also provide one for magnification gesture handling
+    // Each service has an ID. Also provide one for magnification gesture handling.
+    // This ID is also used for mouse event handling.
     public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0;
 
     private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1;
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
index 0f6f86b..739ea0d 100644
--- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
@@ -25,6 +25,7 @@
 import static com.android.server.accessibility.autoclick.AutoclickIndicatorView.SHOW_INDICATOR_DELAY_TIME;
 import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK;
 import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_RIGHT_CLICK;
+import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_SCROLL;
 import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AutoclickType;
 import static com.android.server.accessibility.autoclick.AutoclickTypePanel.ClickPanelControllerInterface;
 
@@ -87,6 +88,7 @@
     @VisibleForTesting AutoclickIndicatorScheduler mAutoclickIndicatorScheduler;
     @VisibleForTesting AutoclickIndicatorView mAutoclickIndicatorView;
     @VisibleForTesting AutoclickTypePanel mAutoclickTypePanel;
+    @VisibleForTesting AutoclickScrollPanel mAutoclickScrollPanel;
     private WindowManager mWindowManager;
 
     // Default click type is left-click.
@@ -98,6 +100,11 @@
                 @Override
                 public void handleAutoclickTypeChange(@AutoclickType int clickType) {
                     mActiveClickType = clickType;
+
+                    // Hide scroll panel when type is not scroll.
+                    if (clickType != AUTOCLICK_TYPE_SCROLL && mAutoclickScrollPanel != null) {
+                        mAutoclickScrollPanel.hide();
+                    }
                 }
 
                 @Override
@@ -161,6 +168,7 @@
         mWindowManager = mContext.getSystemService(WindowManager.class);
         mAutoclickTypePanel =
                 new AutoclickTypePanel(mContext, mWindowManager, mUserId, clickPanelController);
+        mAutoclickScrollPanel = new AutoclickScrollPanel(mContext, mWindowManager);
 
         mAutoclickTypePanel.show();
         mWindowManager.addView(mAutoclickIndicatorView, mAutoclickIndicatorView.getLayoutParams());
@@ -189,6 +197,10 @@
             mClickScheduler.cancel();
         }
 
+        if (mAutoclickScrollPanel != null) {
+            mAutoclickScrollPanel.hide();
+        }
+
         super.clearEvents(inputSource);
     }
 
@@ -209,6 +221,11 @@
             mWindowManager.removeView(mAutoclickIndicatorView);
             mAutoclickTypePanel.hide();
         }
+
+        if (mAutoclickScrollPanel != null) {
+            mAutoclickScrollPanel.hide();
+            mAutoclickScrollPanel = null;
+        }
     }
 
     private void handleMouseMotion(MotionEvent event, int policyFlags) {
@@ -687,6 +704,14 @@
                 return;
             }
 
+            // Handle scroll type specially, show scroll panel instead of sending click events.
+            if (mActiveClickType == AutoclickTypePanel.AUTOCLICK_TYPE_SCROLL) {
+                if (mAutoclickScrollPanel != null) {
+                    mAutoclickScrollPanel.show();
+                }
+                return;
+            }
+
             final int pointerIndex = mLastMotionEvent.getActionIndex();
 
             if (mTempPointerProperties == null) {
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java
new file mode 100644
index 0000000..86f79a8
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickScrollPanel.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.autoclick;
+
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.internal.R;
+
+public class AutoclickScrollPanel {
+    private final Context mContext;
+    private final View mContentView;
+    private final WindowManager mWindowManager;
+    private boolean mInScrollMode = false;
+
+    public AutoclickScrollPanel(Context context, WindowManager windowManager) {
+        mContext = context;
+        mWindowManager = windowManager;
+        mContentView = LayoutInflater.from(context).inflate(
+                R.layout.accessibility_autoclick_scroll_panel, null);
+    }
+
+    /**
+     * Shows the autoclick scroll panel.
+     */
+    public void show() {
+        if (mInScrollMode) {
+            return;
+        }
+        mWindowManager.addView(mContentView, getLayoutParams());
+        mInScrollMode = true;
+    }
+
+    /**
+     * Hides the autoclick scroll panel.
+     */
+    public void hide() {
+        if (!mInScrollMode) {
+            return;
+        }
+        mWindowManager.removeView(mContentView);
+        mInScrollMode = false;
+    }
+
+    /**
+     * Retrieves the layout params for AutoclickScrollPanel, used when it's added to the Window
+     * Manager.
+     */
+    @NonNull
+    private WindowManager.LayoutParams getLayoutParams() {
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+        layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        layoutParams.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+        layoutParams.setFitInsetsTypes(WindowInsets.Type.statusBars());
+        layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        layoutParams.format = PixelFormat.TRANSLUCENT;
+        layoutParams.setTitle(AutoclickScrollPanel.class.getSimpleName());
+        layoutParams.accessibilityTitle =
+                mContext.getString(R.string.accessibility_autoclick_scroll_panel_title);
+        layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
+        layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        layoutParams.gravity = Gravity.CENTER;
+        return layoutParams;
+    }
+
+    @VisibleForTesting
+    public boolean isVisible() {
+        return mInScrollMode;
+    }
+
+    @VisibleForTesting
+    public View getContentViewForTesting() {
+        return mContentView;
+    }
+
+    @VisibleForTesting
+    public WindowManager.LayoutParams getLayoutParamsForTesting() {
+        return getLayoutParams();
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 11b8ccb..004b3ff 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -121,6 +121,8 @@
     @NonNull private final Supplier<MagnificationThumbnail> mThumbnailSupplier;
     @NonNull private final Supplier<Boolean> mMagnificationConnectionStateSupplier;
 
+    private boolean mIsPointerMotionFilterInstalled = false;
+
     /**
      * This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
      * magnification information per display.
@@ -830,9 +832,17 @@
                 return;
             }
 
-            final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
-            final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
-            if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
+            setOffset(mCurrentMagnificationSpec.offsetX - offsetX,
+                    mCurrentMagnificationSpec.offsetY - offsetY, id);
+        }
+
+        @GuardedBy("mLock")
+        void setOffset(float offsetX, float offsetY, int id) {
+            if (!mRegistered) {
+                return;
+            }
+
+            if (updateCurrentSpecWithOffsetsLocked(offsetX, offsetY)) {
                 onMagnificationChangedLocked(/* isScaleTransient= */ false);
             }
             if (id != INVALID_SERVICE_ID) {
@@ -1065,6 +1075,7 @@
             if (display.register()) {
                 mDisplays.put(displayId, display);
                 mScreenStateObserver.registerIfNecessary();
+                configurePointerMotionFilter(true);
             }
         }
     }
@@ -1613,6 +1624,28 @@
     }
 
     /**
+     * Sets the offset of the magnified region.
+     *
+     * @param displayId The logical display id.
+     * @param offsetX   the offset of the magnified region in the X coordinate, in current
+     *                  screen pixels.
+     * @param offsetY   the offset of the magnified region in the Y coordinate, in current
+     *                  screen pixels.
+     * @param id        the ID of the service requesting the change
+     */
+    @SuppressWarnings("GuardedBy")
+    // errorprone cannot recognize an inner class guarded by an outer class member.
+    public void setOffset(int displayId, float offsetX, float offsetY, int id) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            display.setOffset(offsetX, offsetY, id);
+        }
+    }
+
+    /**
      * Offsets the magnified region. Note that the offsetX and offsetY values actually move in the
      * opposite direction as the offsets passed in here.
      *
@@ -1885,6 +1918,7 @@
         }
         if (!hasRegister) {
             mScreenStateObserver.unregister();
+            configurePointerMotionFilter(false);
         }
     }
 
@@ -1900,6 +1934,22 @@
         }
     }
 
+    private void configurePointerMotionFilter(boolean enabled) {
+        if (!Flags.enableMagnificationFollowsMouseWithPointerMotionFilter()) {
+            return;
+        }
+        if (enabled == mIsPointerMotionFilterInstalled) {
+            return;
+        }
+        if (!enabled) {
+            mControllerCtx.getInputManager().registerAccessibilityPointerMotionFilter(null);
+        } else {
+            mControllerCtx.getInputManager().registerAccessibilityPointerMotionFilter(
+                    new FullScreenMagnificationPointerMotionEventFilter(this));
+        }
+        mIsPointerMotionFilterInstalled = enabled;
+    }
+
     private boolean traceEnabled() {
         return mControllerCtx.getTraceManager().isA11yTracingEnabledForTypes(
                 FLAGS_WINDOW_MANAGER_INTERNAL);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index e0dd8b6..59b4a16 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -182,6 +182,7 @@
     private final int mMinimumVelocity;
     private final int mMaximumVelocity;
 
+    @Nullable
     private final MouseEventHandler mMouseEventHandler;
 
     public FullScreenMagnificationGestureHandler(
@@ -313,7 +314,9 @@
         mOverscrollEdgeSlop = context.getResources().getDimensionPixelSize(
                 R.dimen.accessibility_fullscreen_magnification_gesture_edge_slop);
         mIsWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
-        mMouseEventHandler = new MouseEventHandler(mFullScreenMagnificationController);
+        mMouseEventHandler =
+                Flags.enableMagnificationFollowsMouseWithPointerMotionFilter()
+                        ? null : new MouseEventHandler(mFullScreenMagnificationController);
 
         if (mDetectShortcutTrigger) {
             mScreenStateReceiver = new ScreenStateReceiver(context, this);
@@ -337,9 +340,11 @@
 
     @Override
     void handleMouseOrStylusEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        if (!mFullScreenMagnificationController.isActivated(mDisplayId)) {
+        if (mMouseEventHandler == null
+                || !mFullScreenMagnificationController.isActivated(mDisplayId)) {
             return;
         }
+
         // TODO(b/354696546): Allow mouse/stylus to activate whichever display they are
         // over, rather than only interacting with the current display.
 
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java
new file mode 100644
index 0000000..f1ba83e
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.magnification;
+
+import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;
+
+import android.annotation.NonNull;
+
+import com.android.server.input.InputManagerInternal;
+
+/**
+ * Handles pointer motion event for full screen magnification.
+ * Responsible for controlling magnification's cursor following feature.
+ */
+public class FullScreenMagnificationPointerMotionEventFilter implements
+        InputManagerInternal.AccessibilityPointerMotionFilter {
+
+    private final FullScreenMagnificationController mController;
+
+    public FullScreenMagnificationPointerMotionEventFilter(
+            FullScreenMagnificationController controller) {
+        mController = controller;
+    }
+
+    /**
+     * This call happens on the input hot path and it is extremely performance sensitive. It
+     * also must not call back into native code.
+     */
+    @Override
+    @NonNull
+    public float[] filterPointerMotionEvent(float dx, float dy, float currentX, float currentY,
+            int displayId) {
+        if (!mController.isActivated(displayId)) {
+            // unrelated display.
+            return new float[]{dx, dy};
+        }
+
+        // TODO(361817142): implement centered and edge following types.
+
+        // Continuous cursor following.
+        float scale = mController.getScale(displayId);
+        final float newCursorX = currentX + dx;
+        final float newCursorY = currentY + dy;
+        mController.setOffset(displayId,
+                newCursorX - newCursorX * scale, newCursorY - newCursorY * scale,
+                MAGNIFICATION_GESTURE_HANDLER_ID);
+
+        // In the continuous mode, the cursor speed in physical display is kept.
+        // Thus, we don't consume any motion delta.
+        return new float[]{dx, dy};
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 6fdb2b6..6515b23 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -64,6 +64,7 @@
 import static com.android.server.autofill.FillResponseEventLogger.DETECTION_PREFER_PCC;
 import static com.android.server.autofill.FillResponseEventLogger.DETECTION_PREFER_UNKNOWN;
 import static com.android.server.autofill.FillResponseEventLogger.HAVE_SAVE_TRIGGER_ID;
+import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_CANCELLED;
 import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_FAILURE;
 import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SESSION_DESTROYED;
 import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SUCCESS;
@@ -1416,6 +1417,15 @@
 
         // Remove the FillContext as there will never be a response for the service
         if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
+            // Start a new FillResponse logger for the cancellation case.
+            mFillResponseEventLogger.startLogForNewResponse();
+            mFillResponseEventLogger.maybeSetRequestId(canceledRequest);
+            mFillResponseEventLogger.maybeSetAppPackageUid(uid);
+            mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_CANCELLED);
+            mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
+                    (int) (SystemClock.elapsedRealtime() - mLatencyBaseTime));
+            mFillResponseEventLogger.logAndEndEvent();
+
             final int numContexts = mContexts.size();
 
             // It is most likely the last context, hence search backwards
diff --git a/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
index 9a353fb..867cd51 100644
--- a/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
+++ b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
@@ -44,6 +44,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
+import com.android.server.backup.BackupRestoreTask.CancellationReason;
 import com.android.server.backup.internal.LifecycleOperationStorage;
 
 import java.util.Set;
@@ -298,20 +299,22 @@
             // Offload operation cancellation off the main thread as the cancellation callbacks
             // might call out to BackupTransport. Other operations started on the same package
             // before the cancellation callback has executed will also be cancelled by the callback.
-            Runnable cancellationRunnable = () -> {
-                // handleCancel() causes the PerformFullTransportBackupTask to go on to
-                // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
-                // that the package being backed up doesn't get stuck in restricted mode until the
-                // backup time-out elapses.
-                for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
-                    if (DEBUG) {
-                        Slog.d(TAG,
-                                mUserIdMsg + "agentDisconnected: will handleCancel(all) for token:"
-                                        + Integer.toHexString(token));
-                    }
-                    mUserBackupManagerService.handleCancel(token, true /* cancelAll */);
-                }
-            };
+            Runnable cancellationRunnable =
+                    () -> {
+                        // On handleCancel(), the operation will call unbindAgent() which will make
+                        // sure the app doesn't get stuck in restricted mode.
+                        for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
+                            if (DEBUG) {
+                                Slog.d(
+                                        TAG,
+                                        mUserIdMsg
+                                                + "agentDisconnected: cancelling for token:"
+                                                + Integer.toHexString(token));
+                            }
+                            mUserBackupManagerService.handleCancel(
+                                    token, CancellationReason.AGENT_DISCONNECTED);
+                        }
+                    };
             getThreadForCancellation(cancellationRunnable).start();
 
             mAgentConnectLock.notifyAll();
diff --git a/services/backup/java/com/android/server/backup/BackupRestoreTask.java b/services/backup/java/com/android/server/backup/BackupRestoreTask.java
index acaab0c..7ec5f0d 100644
--- a/services/backup/java/com/android/server/backup/BackupRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/BackupRestoreTask.java
@@ -16,9 +16,12 @@
 
 package com.android.server.backup;
 
-/**
- * Interface and methods used by the asynchronous-with-timeout backup/restore operations.
- */
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Interface and methods used by the asynchronous-with-timeout backup/restore operations. */
 public interface BackupRestoreTask {
 
     // Execute one tick of whatever state machine the task implements
@@ -27,6 +30,24 @@
     // An operation that wanted a callback has completed
     void operationComplete(long result);
 
-    // An operation that wanted a callback has timed out
-    void handleCancel(boolean cancelAll);
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        CancellationReason.TIMEOUT,
+        CancellationReason.AGENT_DISCONNECTED,
+        CancellationReason.EXTERNAL,
+        CancellationReason.SCHEDULED_JOB_STOPPED,
+    })
+    @interface CancellationReason {
+        // The task timed out.
+        int TIMEOUT = 0;
+        // The agent went away before the task was able to finish (e.g. due to an app crash).
+        int AGENT_DISCONNECTED = 1;
+        // An external caller cancelled the operation (e.g. via BackupManager#cancelBackups).
+        int EXTERNAL = 2;
+        // The job scheduler has stopped an ongoing scheduled backup pass.
+        int SCHEDULED_JOB_STOPPED = 3;
+    }
+
+    /** The task is cancelled for the given {@link CancellationReason}. */
+    void handleCancel(@CancellationReason int cancellationReason);
 }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 2143aaa..b3af444 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -102,6 +102,7 @@
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
+import com.android.server.backup.BackupRestoreTask.CancellationReason;
 import com.android.server.backup.OperationStorage.OpState;
 import com.android.server.backup.OperationStorage.OpType;
 import com.android.server.backup.fullbackup.FullBackupEntry;
@@ -168,6 +169,7 @@
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.IntConsumer;
 
 /** System service that performs backup/restore operations. */
 public class UserBackupManagerService {
@@ -1816,11 +1818,9 @@
 
             for (Integer token : operationsToCancel) {
                 mOperationStorage.cancelOperation(
-                        token, /* cancelAll */
-                        true,
-                        operationType -> {
-                            /* no callback needed here */
-                        });
+                        token,
+                        operationType -> {}, // no callback needed here
+                        CancellationReason.EXTERNAL);
             }
             // We don't want the backup jobs to kick in any time soon.
             // Reschedules them to run in the distant future.
@@ -1897,19 +1897,17 @@
     }
 
     /** Cancel the operation associated with {@code token}. */
-    public void handleCancel(int token, boolean cancelAll) {
+    public void handleCancel(int token, @CancellationReason int cancellationReason) {
         // Remove all pending timeout messages of types OpType.BACKUP_WAIT and
         // OpType.RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and
         // doesn't require cancellation.
-        mOperationStorage.cancelOperation(
-                token,
-                cancelAll,
-                operationType -> {
-                    if (operationType == OpType.BACKUP_WAIT
-                            || operationType == OpType.RESTORE_WAIT) {
-                        mBackupHandler.removeMessages(getMessageIdForOperationType(operationType));
+        IntConsumer timeoutCallback =
+                opType -> {
+                    if (opType == OpType.BACKUP_WAIT || opType == OpType.RESTORE_WAIT) {
+                        mBackupHandler.removeMessages(getMessageIdForOperationType(opType));
                     }
-                });
+                };
+        mOperationStorage.cancelOperation(token, timeoutCallback, cancellationReason);
     }
 
     /** Returns {@code true} if a backup is currently running, else returns {@code false}. */
@@ -2219,19 +2217,16 @@
         // offload the mRunningFullBackupTask.handleCancel() call to another thread,
         // as we might have to wait for mCancelLock
         Runnable endFullBackupRunnable =
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        PerformFullTransportBackupTask pftbt = null;
-                        synchronized (mQueueLock) {
-                            if (mRunningFullBackupTask != null) {
-                                pftbt = mRunningFullBackupTask;
-                            }
+                () -> {
+                    PerformFullTransportBackupTask pftbt = null;
+                    synchronized (mQueueLock) {
+                        if (mRunningFullBackupTask != null) {
+                            pftbt = mRunningFullBackupTask;
                         }
-                        if (pftbt != null) {
-                            Slog.i(TAG, mLogIdMsg + "Telling running backup to stop");
-                            pftbt.handleCancel(true);
-                        }
+                    }
+                    if (pftbt != null) {
+                        Slog.i(TAG, mLogIdMsg + "Telling running backup to stop");
+                        pftbt.handleCancel(CancellationReason.SCHEDULED_JOB_STOPPED);
                     }
                 };
         new Thread(endFullBackupRunnable, "end-full-backup").start();
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 0d4364e..7fc9ed3 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -484,7 +484,7 @@
     }
 
     @Override
-    public void handleCancel(boolean cancelAll) {
+    public void handleCancel(@CancellationReason int cancellationReason) {
         final PackageInfo target = mCurrentTarget;
         Slog.w(TAG, "adb backup cancel of " + target);
         if (target != null) {
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index c182c26..f677c9d 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -162,7 +162,7 @@
 
     // This is true when a backup operation for some package is in progress.
     private volatile boolean mIsDoingBackup;
-    private volatile boolean mCancelAll;
+    private volatile boolean mCancelled;
     private final int mCurrentOpToken;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final BackupEligibilityRules mBackupEligibilityRules;
@@ -199,7 +199,7 @@
 
         if (backupManagerService.isBackupOperationInProgress()) {
             Slog.d(TAG, "Skipping full backup. A backup is already in progress.");
-            mCancelAll = true;
+            mCancelled = true;
             return;
         }
 
@@ -287,25 +287,23 @@
     }
 
     @Override
-    public void handleCancel(boolean cancelAll) {
+    public void handleCancel(@CancellationReason int cancellationReason) {
         synchronized (mCancelLock) {
-            // We only support 'cancelAll = true' case for this task. Cancelling of a single package
-
-            // due to timeout is handled by SinglePackageBackupRunner and
+            // This callback is only used for cancelling the entire backup operation. Cancelling of
+            // a single package due to timeout is handled by SinglePackageBackupRunner and
             // SinglePackageBackupPreflight.
-
-            if (!cancelAll) {
-                Slog.wtf(TAG, "Expected cancelAll to be true.");
+            if (cancellationReason == CancellationReason.TIMEOUT) {
+                Slog.wtf(TAG, "This task cannot time out");
             }
 
-            if (mCancelAll) {
+            if (mCancelled) {
                 Slog.d(TAG, "Ignoring duplicate cancel call.");
                 return;
             }
 
-            mCancelAll = true;
+            mCancelled = true;
             if (mIsDoingBackup) {
-                mUserBackupManagerService.handleCancel(mBackupRunnerOpToken, cancelAll);
+                mUserBackupManagerService.handleCancel(mBackupRunnerOpToken, cancellationReason);
                 try {
                     // If we're running a backup we should be connected to a transport
                     BackupTransportClient transport =
@@ -410,7 +408,7 @@
                 int backupPackageStatus;
                 long quota = Long.MAX_VALUE;
                 synchronized (mCancelLock) {
-                    if (mCancelAll) {
+                    if (mCancelled) {
                         break;
                     }
                     backupPackageStatus = transport.performFullBackup(currentPackage,
@@ -478,7 +476,7 @@
                             if (nRead > 0) {
                                 out.write(buffer, 0, nRead);
                                 synchronized (mCancelLock) {
-                                    if (!mCancelAll) {
+                                    if (!mCancelled) {
                                         backupPackageStatus = transport.sendBackupData(nRead);
                                     }
                                 }
@@ -509,7 +507,7 @@
                     synchronized (mCancelLock) {
                         mIsDoingBackup = false;
                         // If mCancelCurrent is true, we have already called cancelFullBackup().
-                        if (!mCancelAll) {
+                        if (!mCancelled) {
                             if (backupRunnerResult == BackupTransport.TRANSPORT_OK) {
                                 // If we were otherwise in a good state, now interpret the final
                                 // result based on what finishBackup() returns.  If we're in a
@@ -607,7 +605,7 @@
                             .sendBackupOnPackageResult(mBackupObserver, packageName,
                                     BackupManager.ERROR_BACKUP_CANCELLED);
                     Slog.w(TAG, "Backup cancelled. package=" + packageName +
-                            ", cancelAll=" + mCancelAll);
+                            ", entire session cancelled=" + mCancelled);
                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_CANCELLED, packageName);
                     mUserBackupManagerService.getBackupAgentConnectionManager().unbindAgent(
                             currentPackage.applicationInfo, /* allowKill= */ true);
@@ -654,7 +652,7 @@
 
         } finally {
 
-            if (mCancelAll) {
+            if (mCancelled) {
                 backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED;
             }
 
@@ -820,7 +818,7 @@
         }
 
         @Override
-        public void handleCancel(boolean cancelAll) {
+        public void handleCancel(@CancellationReason int cancellationReason) {
             if (DEBUG) {
                 Slog.i(TAG, "Preflight cancelled; failing");
             }
@@ -974,7 +972,7 @@
         public void operationComplete(long result) { /* intentionally empty */ }
 
         @Override
-        public void handleCancel(boolean cancelAll) {
+        public void handleCancel(@CancellationReason int cancellationReason) {
             Slog.w(TAG, "Full backup cancel of " + mTarget.packageName);
 
             mBackupManagerMonitorEventSender.monitorEvent(
@@ -984,7 +982,7 @@
                     /* extras= */ null);
             mIsCancelled = true;
             // Cancel tasks spun off by this task.
-            mUserBackupManagerService.handleCancel(mEphemeralToken, cancelAll);
+            mUserBackupManagerService.handleCancel(mEphemeralToken, cancellationReason);
             mUserBackupManagerService.getBackupAgentConnectionManager().unbindAgent(
                     mTarget.applicationInfo, /* allowKill= */ true);
             // Free up everyone waiting on this task and its children.
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 87cf8a3..464dc2d 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -34,6 +34,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.BackupRestoreTask.CancellationReason;
 import com.android.server.backup.DataChangedJournal;
 import com.android.server.backup.OperationStorage;
 import com.android.server.backup.TransportManager;
@@ -410,8 +411,8 @@
 
             case MSG_BACKUP_OPERATION_TIMEOUT:
             case MSG_RESTORE_OPERATION_TIMEOUT: {
-                Slog.d(TAG, "Timeout message received for token=" + Integer.toHexString(msg.arg1));
-                backupManagerService.handleCancel(msg.arg1, false);
+                Slog.d(TAG, "Timeout for token=" + Integer.toHexString(msg.arg1));
+                backupManagerService.handleCancel(msg.arg1, CancellationReason.TIMEOUT);
                 break;
             }
 
diff --git a/services/backup/java/com/android/server/backup/internal/LifecycleOperationStorage.java b/services/backup/java/com/android/server/backup/internal/LifecycleOperationStorage.java
index 0b974e2..5aacb2f 100644
--- a/services/backup/java/com/android/server/backup/internal/LifecycleOperationStorage.java
+++ b/services/backup/java/com/android/server/backup/internal/LifecycleOperationStorage.java
@@ -24,6 +24,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.BackupRestoreTask.CancellationReason;
 import com.android.server.backup.OperationStorage;
 
 import com.google.android.collect.Sets;
@@ -296,20 +297,18 @@
     }
 
     /**
-     * Cancel the operation associated with {@code token}.  Cancellation may be
-     * propagated to the operation's callback (a {@link BackupRestoreTask}) if
-     * the operation has one, and the cancellation is due to the operation
-     * timing out.
+     * Cancel the operation associated with {@code token}. Cancellation may be propagated to the
+     * operation's callback (a {@link BackupRestoreTask}) if the operation has one, and the
+     * cancellation is due to the operation timing out.
      *
      * @param token the operation token specified when registering the operation
-     * @param cancelAll this is passed on when propagating the cancellation
-     * @param operationTimedOutCallback a lambda that is invoked with the
-     *                                  operation type where the operation is
-     *                                  cancelled due to timeout, allowing the
-     *                                  caller to do type-specific clean-ups.
+     * @param operationTimedOutCallback a lambda that is invoked with the operation type where the
+     *     operation is cancelled due to timeout, allowing the caller to do type-specific clean-ups.
      */
     public void cancelOperation(
-            int token, boolean cancelAll, IntConsumer operationTimedOutCallback) {
+            int token,
+            IntConsumer operationTimedOutCallback,
+            @CancellationReason int cancellationReason) {
         // Notify any synchronous waiters
         Operation op = null;
         synchronized (mOperationsLock) {
@@ -343,7 +342,7 @@
             if (DEBUG) {
                 Slog.v(TAG, "[UserID:" + mUserId + "   Invoking cancel on " + op.callback);
             }
-            op.callback.handleCancel(cancelAll);
+            op.callback.handleCancel(cancellationReason);
         }
     }
 }
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 494b9d5..8e7a23c 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -171,7 +171,7 @@
  * complete backup should be performed.
  *
  * <p>This task is designed to run on a dedicated thread, with the exception of the {@link
- * #handleCancel(boolean)} method, which can be called from any thread.
+ * BackupRestoreTask#handleCancel(int)} method, which can be called from any thread.
  */
 // TODO: Stop poking into BMS state and doing things for it (e.g. synchronizing on public locks)
 // TODO: Consider having the caller responsible for some clean-up (like resetting state)
@@ -1208,13 +1208,13 @@
      *
      * <p>Note: This method is inherently racy since there are no guarantees about how much of the
      * task will be executed after you made the call.
-     *
-     * @param cancelAll MUST be {@code true}. Will be removed.
      */
     @Override
-    public void handleCancel(boolean cancelAll) {
+    public void handleCancel(@CancellationReason int cancellationReason) {
         // This is called in a thread different from the one that executes method run().
-        Preconditions.checkArgument(cancelAll, "Can't partially cancel a key-value backup task");
+        Preconditions.checkArgument(
+                cancellationReason != CancellationReason.TIMEOUT,
+                "Key-value backup task cannot time out");
         markCancel();
         waitCancel();
     }
diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
index cb491c6..f1829b6 100644
--- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
+++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
@@ -79,7 +79,7 @@
     }
 
     @Override
-    public void handleCancel(boolean cancelAll) {
+    public void handleCancel(@CancellationReason int cancellationReason) {
         Slog.w(TAG, "adb onRestoreFinished() timed out");
         mLatch.countDown();
         mOperationStorage.removeOperation(mCurrentOpToken);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 707ae03..1263146 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -1307,7 +1307,7 @@
 
         // The app has timed out handling a restoring file
         @Override
-        public void handleCancel(boolean cancelAll) {
+        public void handleCancel(@CancellationReason int cancellationReason) {
             mOperationStorage.removeOperation(mEphemeralOpToken);
             Slog.w(TAG, "Full-data restore target timed out; shutting down");
             Bundle monitoringExtras = addRestoreOperationTypeToEvent(/* extras= */ null);
@@ -1555,7 +1555,7 @@
 
     // A call to agent.doRestore() or agent.doRestoreFinished() has timed out
     @Override
-    public void handleCancel(boolean cancelAll) {
+    public void handleCancel(@CancellationReason int cancellationReason) {
         mOperationStorage.removeOperation(mEphemeralOpToken);
         Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
         Bundle monitoringExtras = addRestoreOperationTypeToEvent(/* extras= */ null);
diff --git a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
index ce7dcd0..0310756 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
@@ -299,14 +299,24 @@
     public void writeLastRemovedAssociation(AssociationInfo association, String reason) {
         Slog.i(TAG, "Writing last removed association=" + association.getId() + " to disk...");
 
+        // Remove indirect identifier i.e. Mac Address
+        AssociationInfo.Builder builder = new AssociationInfo.Builder(association)
+                .setDeviceMacAddress(null);
+        // Set a placeholder display name if it's null because Mac Address and display name can't be
+        // both null.
+        if (association.getDisplayName() == null) {
+            builder.setDisplayName("");
+        }
+        AssociationInfo redactedAssociation = builder.build();
+
         final AtomicFile file = createStorageFileForUser(
-                association.getUserId(), FILE_NAME_LAST_REMOVED_ASSOCIATION);
+                redactedAssociation.getUserId(), FILE_NAME_LAST_REMOVED_ASSOCIATION);
         writeToFileSafely(file, out -> {
             out.write(String.valueOf(System.currentTimeMillis()).getBytes());
             out.write(' ');
             out.write(reason.getBytes());
             out.write(' ');
-            out.write(association.toString().getBytes());
+            out.write(redactedAssociation.toString().getBytes());
         });
     }
 
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 93b4de8..caf535c 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -142,14 +142,6 @@
     @GuardedBy("mVirtualDeviceManagerLock")
     private ArrayMap<String, AssociationInfo> mActiveAssociations = new ArrayMap<>();
 
-    private final CompanionDeviceManager.OnAssociationsChangedListener mCdmAssociationListener =
-            new CompanionDeviceManager.OnAssociationsChangedListener() {
-                @Override
-                public void onAssociationsChanged(@NonNull List<AssociationInfo> associations) {
-                    syncVirtualDevicesToCdmAssociations(associations);
-                }
-            };
-
     private class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
         final Set<Integer> mUsersInLockdown = new ArraySet<>();
 
@@ -348,33 +340,6 @@
         return true;
     }
 
-    private void syncVirtualDevicesToCdmAssociations(List<AssociationInfo> associations) {
-        Set<VirtualDeviceImpl> virtualDevicesToRemove = new HashSet<>();
-        synchronized (mVirtualDeviceManagerLock) {
-            if (mVirtualDevices.size() == 0) {
-                return;
-            }
-
-            Set<Integer> activeAssociationIds = new HashSet<>(associations.size());
-            for (AssociationInfo association : associations) {
-                activeAssociationIds.add(association.getId());
-            }
-
-            for (int i = 0; i < mVirtualDevices.size(); i++) {
-                VirtualDeviceImpl virtualDevice = mVirtualDevices.valueAt(i);
-                int deviceAssociationId = virtualDevice.getAssociationId();
-                if (deviceAssociationId != CDM_ASSOCIATION_ID_NONE
-                        && !activeAssociationIds.contains(deviceAssociationId)) {
-                    virtualDevicesToRemove.add(virtualDevice);
-                }
-            }
-        }
-
-        for (VirtualDeviceImpl virtualDevice : virtualDevicesToRemove) {
-            virtualDevice.close();
-        }
-    }
-
     void onCdmAssociationsChanged(List<AssociationInfo> associations) {
         ArrayMap<String, AssociationInfo> vdmAssociations = new ArrayMap<>();
         for (int i = 0; i < associations.size(); ++i) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 2aaf6a9..14d9d3f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -121,6 +121,13 @@
     out: ["com/android/server/location/contexthub/ContextHubStatsLog.java"],
 }
 
+genrule {
+  name: "statslog-mediarouter-java-gen",
+  tools: ["stats-log-api-gen"],
+  cmd: "$(location stats-log-api-gen) --java $(out) --module mediarouter --javaPackage com.android.server.media --javaClass MediaRouterStatsLog",
+  out: ["com/android/server/media/MediaRouterStatsLog.java"],
+}
+
 java_library_static {
     name: "services.core.unboosted",
     defaults: [
@@ -136,6 +143,7 @@
         ":android.hardware.tv.mediaquality-V1-java-source",
         ":statslog-art-java-gen",
         ":statslog-contexthub-java-gen",
+        ":statslog-mediarouter-java-gen",
         ":services.core-aidl-sources",
         ":services.core-sources",
         ":services.core.protologsrc",
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 296f7cf..f54027e 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -514,6 +514,7 @@
                 mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
                 registerVrStateListener();
                 // register listeners
+                // LINT.IfChange(fi_cb)
                 context.getContentResolver()
                         .registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE),
                                 false, mDarkThemeObserver, 0);
@@ -523,6 +524,7 @@
                                     Secure.getUriFor(ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED),
                                     false, mForceInvertStateObserver, UserHandle.USER_ALL);
                 }
+                // LINT.ThenChange(/core/java/android/view/ViewRootImpl.java:fi_cb)
                 context.getContentResolver().registerContentObserver(
                         Secure.getUriFor(Secure.CONTRAST_LEVEL), false,
                         mContrastObserver, UserHandle.USER_ALL);
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 96b30d4..d60c6c5 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -165,7 +165,6 @@
             "android.hardware.sensors@1.0::ISensors",
             "android.hardware.sensors@2.0::ISensors",
             "android.hardware.sensors@2.1::ISensors",
-            "android.hardware.vibrator@1.0::IVibrator",
             "android.hardware.vr@1.0::IVr",
             "android.system.suspend@1.0::ISystemSuspend"
     );
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 600b124..79fdcca 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -190,6 +190,7 @@
     }
 
     final Context mContext;
+    final PackageMonitor mPackageMonitor;
 
     private static final int[] INTERESTING_APP_OPS = new int[] {
         AppOpsManager.OP_GET_ACCOUNTS,
@@ -373,7 +374,7 @@
         }, UserHandle.ALL, userFilter, null, null);
 
         // Need to cancel account request notifications if the update/install can access the account
-        new PackageMonitor() {
+        mPackageMonitor = new PackageMonitor() {
             @Override
             public void onPackageAdded(String packageName, int uid) {
                 // Called on a handler, and running as the system
@@ -397,7 +398,8 @@
                     return;
                 }
             }
-        }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+        };
+        mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
 
         // Cancel account request notification if an app op was preventing the account access
         for (int i = 0; i < INTERESTING_APP_OPS.length; ++i) {
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index a73a991..658ea4c 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -130,8 +130,6 @@
  */
 public class AdbDebuggingManager {
     private static final String TAG = AdbDebuggingManager.class.getSimpleName();
-    private static final boolean DEBUG = false;
-    private static final boolean MDNS_DEBUG = false;
 
     private static final String ADBD_SOCKET = "adbd";
     private static final String ADB_DIRECTORY = "misc/adb";
@@ -156,8 +154,6 @@
     @Nullable private final File mUserKeyFile;
     @Nullable private final File mTempKeysFile;
 
-    private static final String WIFI_PERSISTENT_CONFIG_PROPERTY =
-            "persist.adb.tls_server.enable";
     private static final String WIFI_PERSISTENT_GUID =
             "persist.adb.wifi.guid";
     private static final int PAIRING_CODE_LENGTH = 6;
@@ -261,12 +257,10 @@
             mHandler.sendMessage(msg);
 
             boolean paired = native_pairing_wait();
-            if (DEBUG) {
-                if (mPublicKey != null) {
-                    Slog.i(TAG, "Pairing succeeded key=" + mPublicKey);
-                } else {
-                    Slog.i(TAG, "Pairing failed");
-                }
+            if (mPublicKey != null) {
+                Slog.i(TAG, "Pairing succeeded key=" + mPublicKey);
+            } else {
+                Slog.i(TAG, "Pairing failed");
             }
 
             mNsdManager.unregisterService(this);
@@ -307,7 +301,7 @@
 
         @Override
         public void onServiceRegistered(NsdServiceInfo serviceInfo) {
-            if (MDNS_DEBUG) Slog.i(TAG, "Registered pairing service: " + serviceInfo);
+            Slog.i(TAG, "Registered pairing service: " + serviceInfo);
         }
 
         @Override
@@ -319,7 +313,7 @@
 
         @Override
         public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
-            if (MDNS_DEBUG) Slog.i(TAG, "Unregistered pairing service: " + serviceInfo);
+            Slog.i(TAG, "Unregistered pairing service: " + serviceInfo);
         }
 
         @Override
@@ -354,7 +348,7 @@
 
         @Override
         public void run() {
-            if (DEBUG) Slog.d(TAG, "Starting adb port property poller");
+            Slog.d(TAG, "Starting adb port property poller");
             // Once adbwifi is enabled, we poll the service.adb.tls.port
             // system property until we get the port, or -1 on failure.
             // Let's also limit the polling to 10 seconds, just in case
@@ -390,7 +384,7 @@
 
     class PortListenerImpl implements AdbConnectionPortListener {
         public void onPortReceived(int port) {
-            if (DEBUG) Slog.d(TAG, "Received tls port=" + port);
+            Slog.d(TAG, "Received tls port=" + port);
             Message msg = mHandler.obtainMessage(port > 0
                      ? AdbDebuggingHandler.MSG_SERVER_CONNECTED
                      : AdbDebuggingHandler.MSG_SERVER_DISCONNECTED);
@@ -419,11 +413,11 @@
 
         @Override
         public void run() {
-            if (DEBUG) Slog.d(TAG, "Entering thread");
+            Slog.d(TAG, "Entering thread");
             while (true) {
                 synchronized (this) {
                     if (mStopped) {
-                        if (DEBUG) Slog.d(TAG, "Exiting thread");
+                        Slog.d(TAG, "Exiting thread");
                         return;
                     }
                     try {
@@ -448,7 +442,7 @@
                         LocalSocketAddress.Namespace.RESERVED);
                 mInputStream = null;
 
-                if (DEBUG) Slog.d(TAG, "Creating socket");
+                Slog.d(TAG, "Creating socket");
                 mSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
                 mSocket.connect(address);
 
@@ -549,7 +543,7 @@
         }
 
         private void closeSocketLocked() {
-            if (DEBUG) Slog.d(TAG, "Closing socket");
+            Slog.d(TAG, "Closing socket");
             try {
                 if (mOutputStream != null) {
                     mOutputStream.close();
@@ -859,7 +853,7 @@
 
         private void startAdbDebuggingThread() {
             ++mAdbEnabledRefCount;
-            if (DEBUG) Slog.i(TAG, "startAdbDebuggingThread ref=" + mAdbEnabledRefCount);
+            Slog.i(TAG, "startAdbDebuggingThread ref=" + mAdbEnabledRefCount);
             if (mAdbEnabledRefCount > 1) {
                 return;
             }
@@ -875,7 +869,7 @@
 
         private void stopAdbDebuggingThread() {
             --mAdbEnabledRefCount;
-            if (DEBUG) Slog.i(TAG, "stopAdbDebuggingThread ref=" + mAdbEnabledRefCount);
+            Slog.i(TAG, "stopAdbDebuggingThread ref=" + mAdbEnabledRefCount);
             if (mAdbEnabledRefCount > 0) {
                 return;
             }
@@ -1093,7 +1087,7 @@
                     intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
                     mContext.registerReceiver(mBroadcastReceiver, intentFilter);
 
-                    SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1");
+                    SystemProperties.set(AdbService.WIFI_PERSISTENT_CONFIG_PROPERTY, "1");
                     mConnectionPortPoller =
                             new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener);
                     mConnectionPortPoller.start();
@@ -1101,7 +1095,7 @@
                     startAdbDebuggingThread();
                     mAdbWifiEnabled = true;
 
-                    if (DEBUG) Slog.i(TAG, "adb start wireless adb");
+                    Slog.i(TAG, "adb start wireless adb");
                     break;
                 }
                 case MSG_ADBDWIFI_DISABLE:
@@ -1143,7 +1137,7 @@
                     intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
                     mContext.registerReceiver(mBroadcastReceiver, intentFilter);
 
-                    SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1");
+                    SystemProperties.set(AdbService.WIFI_PERSISTENT_CONFIG_PROPERTY, "1");
                     mConnectionPortPoller =
                             new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener);
                     mConnectionPortPoller.start();
@@ -1151,7 +1145,7 @@
                     startAdbDebuggingThread();
                     mAdbWifiEnabled = true;
 
-                    if (DEBUG) Slog.i(TAG, "adb start wireless adb");
+                    Slog.i(TAG, "adb start wireless adb");
                     break;
                 case MSG_ADBWIFI_DENY:
                     Settings.Global.putInt(mContentResolver,
@@ -1259,7 +1253,7 @@
                     break;
                 }
                 case MSG_ADBD_SOCKET_CONNECTED: {
-                    if (DEBUG) Slog.d(TAG, "adbd socket connected");
+                    Slog.d(TAG, "adbd socket connected");
                     if (mAdbWifiEnabled) {
                         // In scenarios where adbd is restarted, the tls port may change.
                         mConnectionPortPoller =
@@ -1269,7 +1263,7 @@
                     break;
                 }
                 case MSG_ADBD_SOCKET_DISCONNECTED: {
-                    if (DEBUG) Slog.d(TAG, "adbd socket disconnected");
+                    Slog.d(TAG, "adbd socket disconnected");
                     if (mConnectionPortPoller != null) {
                         mConnectionPortPoller.cancelAndWait();
                         mConnectionPortPoller = null;
@@ -1477,7 +1471,7 @@
         }
 
         private void updateUIPairCode(String code) {
-            if (DEBUG) Slog.i(TAG, "updateUIPairCode: " + code);
+            Slog.i(TAG, "updateUIPairCode: " + code);
 
             Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION);
             intent.putExtra(AdbManager.WIRELESS_PAIRING_CODE_EXTRA, code);
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 55d8dba..aae48da 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -222,15 +222,14 @@
         }
     }
 
-    private static final String TAG = "AdbService";
-    private static final boolean DEBUG = false;
+    private static final String TAG = AdbService.class.getSimpleName();
 
     /**
      * The persistent property which stores whether adb is enabled or not.
      * May also contain vendor-specific default functions for testing purposes.
      */
     private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
-    private static final String WIFI_PERSISTENT_CONFIG_PROPERTY = "persist.adb.tls_server.enable";
+    static final String WIFI_PERSISTENT_CONFIG_PROPERTY = "persist.adb.tls_server.enable";
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
@@ -256,7 +255,7 @@
      * SystemServer}.
      */
     public void systemReady() {
-        if (DEBUG) Slog.d(TAG, "systemReady");
+        Slog.d(TAG, "systemReady");
 
         /*
          * Use the normal bootmode persistent prop to maintain state of adb across
@@ -287,7 +286,7 @@
      * Called in response to {@code SystemService.PHASE_BOOT_COMPLETED} from {@code SystemServer}.
      */
     public void bootCompleted() {
-        if (DEBUG) Slog.d(TAG, "boot completed");
+        Slog.d(TAG, "boot completed");
         if (mDebuggingManager != null) {
             mDebuggingManager.setAdbEnabled(mIsAdbUsbEnabled, AdbTransportType.USB);
             mDebuggingManager.setAdbEnabled(mIsAdbWifiEnabled, AdbTransportType.WIFI);
@@ -429,17 +428,13 @@
 
     @Override
     public void registerCallback(IAdbCallback callback) throws RemoteException {
-        if (DEBUG) {
-            Slog.d(TAG, "Registering callback " + callback);
-        }
+        Slog.d(TAG, "Registering callback " + callback);
         mCallbacks.register(callback);
     }
 
     @Override
     public void unregisterCallback(IAdbCallback callback) throws RemoteException {
-        if (DEBUG) {
-            Slog.d(TAG, "Unregistering callback " + callback);
-        }
+        Slog.d(TAG, "Unregistering callback " + callback);
         mCallbacks.unregister(callback);
     }
     /**
@@ -500,11 +495,8 @@
     }
 
     private void setAdbEnabled(boolean enable, byte transportType) {
-        if (DEBUG) {
-            Slog.d(TAG, "setAdbEnabled(" + enable + "), mIsAdbUsbEnabled=" + mIsAdbUsbEnabled
-                    + ", mIsAdbWifiEnabled=" + mIsAdbWifiEnabled + ", transportType="
-                        + transportType);
-        }
+        Slog.d(TAG, "setAdbEnabled(" + enable + "), mIsAdbUsbEnabled=" + mIsAdbUsbEnabled
+                 + ", mIsAdbWifiEnabled=" + mIsAdbWifiEnabled + ", transportType=" + transportType);
 
         if (transportType == AdbTransportType.USB && enable != mIsAdbUsbEnabled) {
             mIsAdbUsbEnabled = enable;
@@ -549,20 +541,14 @@
             mDebuggingManager.setAdbEnabled(enable, transportType);
         }
 
-        if (DEBUG) {
-            Slog.d(TAG, "Broadcasting enable = " + enable + ", type = " + transportType);
-        }
+        Slog.d(TAG, "Broadcasting enable = " + enable + ", type = " + transportType);
         mCallbacks.broadcast((callback) -> {
-            if (DEBUG) {
-                Slog.d(TAG, "Sending enable = " + enable + ", type = " + transportType
-                        + " to " + callback);
-            }
+            Slog.d(TAG, "Sending enable = " + enable + ", type = " + transportType + " to "
+                    + callback);
             try {
                 callback.onDebuggingChanged(enable, transportType);
             } catch (RemoteException ex) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Unable to send onDebuggingChanged:", ex);
-                }
+                Slog.w(TAG, "Unable to send onDebuggingChanged:", ex);
             }
         });
     }
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index db0562f..508c018 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -810,7 +810,7 @@
      * Return the broadcast being actively dispatched in this process.
      */
     public @NonNull BroadcastRecord getActive() {
-        return Objects.requireNonNull(mActive);
+        return Objects.requireNonNull(mActive, toString());
     }
 
     /**
@@ -818,7 +818,7 @@
      * being actively dispatched in this process.
      */
     public int getActiveIndex() {
-        Objects.requireNonNull(mActive);
+        Objects.requireNonNull(mActive, toString());
         return mActiveIndex;
     }
 
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index c76a0d0..d276b9a 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -606,8 +606,9 @@
         } else {
             mRunningColdStart.reEnqueueActiveBroadcast();
         }
-        demoteFromRunningLocked(mRunningColdStart);
+        final BroadcastProcessQueue queue = mRunningColdStart;
         clearRunningColdStart();
+        demoteFromRunningLocked(queue);
         enqueueUpdateRunningList();
     }
 
@@ -1527,6 +1528,15 @@
 
         final int cookie = traceBegin("demoteFromRunning");
         // We've drained running broadcasts; maybe move back to runnable
+        if (mRunningColdStart == queue) {
+            // TODO: b/399020479 - Remove wtf log once we identify the case where mRunningColdStart
+            // is not getting cleared.
+            // If this queue is mRunningColdStart, then it should have been cleared before
+            // it is demoted. Log a wtf if this isn't the case.
+            Slog.wtf(TAG, "mRunningColdStart has not been cleared; mRunningColdStart.app: "
+                    + mRunningColdStart.app + " , queue.app: " + queue.app,
+                            new IllegalStateException());
+        }
         queue.makeActiveIdle();
         queue.traceProcessEnd();
 
@@ -2332,12 +2342,6 @@
 
     @VisibleForTesting
     @GuardedBy("mService")
-    @Nullable BroadcastProcessQueue removeProcessQueue(@NonNull ProcessRecord app) {
-        return removeProcessQueue(app.processName, app.info.uid);
-    }
-
-    @VisibleForTesting
-    @GuardedBy("mService")
     @Nullable BroadcastProcessQueue removeProcessQueue(@NonNull String processName,
             int uid) {
         BroadcastProcessQueue prev = null;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 2c0366e..ac30be9 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -31,7 +31,6 @@
 
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.window.flags.Flags.balClearAllowlistDuration;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
@@ -330,7 +329,7 @@
         mAllowBgActivityStartsForActivitySender.remove(token);
         mAllowBgActivityStartsForBroadcastSender.remove(token);
         mAllowBgActivityStartsForServiceSender.remove(token);
-        if (mAllowlistDuration != null && balClearAllowlistDuration()) {
+        if (mAllowlistDuration != null) {
             TempAllowListDuration duration = mAllowlistDuration.get(token);
             if (duration != null
                     && duration.type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 1503d88..eea667e 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1443,17 +1443,32 @@
 
     void onProcessFrozen() {
         mProfile.onProcessFrozen();
-        if (mThread != null) mThread.onProcessPaused();
+        final ApplicationThreadDeferred t;
+        synchronized (mService) {
+            t = mThread;
+        }
+        // Release the lock before calling the notifier, in case that calls back into AM.
+        if (t != null) t.onProcessPaused();
     }
 
     void onProcessUnfrozen() {
-        if (mThread != null) mThread.onProcessUnpaused();
+        final ApplicationThreadDeferred t;
+        synchronized (mService) {
+            t = mThread;
+        }
+        // Release the lock before calling the notifier, in case that calls back into AM.
+        if (t != null) t.onProcessUnpaused();
         mProfile.onProcessUnfrozen();
         mServices.onProcessUnfrozen();
     }
 
     void onProcessFrozenCancelled() {
-        if (mThread != null) mThread.onProcessPausedCancelled();
+        final ApplicationThreadDeferred t;
+        synchronized (mService) {
+            t = mThread;
+        }
+        // Release the lock before calling the notifier, in case that calls back into AM.
+        if (t != null) t.onProcessPausedCancelled();
         mServices.onProcessFrozenCancelled();
     }
 
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 3a041fd..cfd22fb 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -187,10 +187,12 @@
         "crumpet",
         "dck_framework",
         "desktop_apps",
+        "desktop_audio",
         "desktop_better_together",
         "desktop_bsp",
         "desktop_camera",
         "desktop_connectivity",
+        "desktop_dev_experience",
         "desktop_display",
         "desktop_commercial",
         "desktop_firmware",
@@ -199,10 +201,14 @@
         "desktop_input",
         "desktop_kernel",
         "desktop_ml",
+        "desktop_networking",
         "desktop_serviceability",
         "desktop_oobe",
         "desktop_peripherals",
+        "desktop_personalization",
         "desktop_pnp",
+        "desktop_privacy",
+        "desktop_release",
         "desktop_security",
         "desktop_stats",
         "desktop_sysui",
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 9dd09ce..40085ed 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -113,7 +113,7 @@
         mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                 parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime,
                 AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE,
-                DiscreteOpsRegistry.ACCESS_TYPE_NOTE_OP, accessCount);
+                accessCount);
     }
 
     /**
@@ -257,8 +257,7 @@
         if (isStarted) {
             mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                     parent.packageName, persistentDeviceId, tag, uidState, flags, startTime,
-                    attributionFlags, attributionChainId,
-                    DiscreteOpsRegistry.ACCESS_TYPE_START_OP, 1);
+                    attributionFlags, attributionChainId, 1);
         }
     }
 
@@ -344,9 +343,7 @@
             mAppOpsService.mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
                     parent.packageName, persistentDeviceId, tag, event.getUidState(),
                     event.getFlags(), finishedEvent.getNoteTime(), finishedEvent.getDuration(),
-                    event.getAttributionFlags(), event.getAttributionChainId(),
-                    isPausing ? DiscreteOpsRegistry.ACCESS_TYPE_PAUSE_OP
-                            : DiscreteOpsRegistry.ACCESS_TYPE_FINISH_OP);
+                    event.getAttributionFlags(), event.getAttributionChainId());
 
             if (!isPausing) {
                 mAppOpsService.mInProgressStartOpEventPool.release(event);
@@ -454,7 +451,7 @@
             mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                     parent.packageName, persistentDeviceId, tag, event.getUidState(),
                     event.getFlags(), startTime, event.getAttributionFlags(),
-                    event.getAttributionChainId(), DiscreteOpsRegistry.ACCESS_TYPE_RESUME_OP, 1);
+                    event.getAttributionChainId(), 1);
             if (shouldSendActive) {
                 mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                         parent.packageName, tag, event.getVirtualDeviceId(), true,
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java b/services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java
index 86f5d9b..c53e4bd 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java
@@ -189,11 +189,11 @@
             @AppOpsManager.HistoricalOpsRequestFilter int requestFilters,
             int uidFilter, @Nullable String packageNameFilter,
             @Nullable String attributionTagFilter, IntArray opCodesFilter, int opFlagsFilter,
-            long beginTime, long endTime, int limit, String orderByColumn) {
+            long beginTime, long endTime, int limit, String orderByColumn, boolean ascending) {
         List<SQLCondition> conditions = prepareConditions(beginTime, endTime, requestFilters,
                 uidFilter, packageNameFilter,
                 attributionTagFilter, opCodesFilter, opFlagsFilter);
-        String sql = buildSql(conditions, orderByColumn, limit);
+        String sql = buildSql(conditions, orderByColumn, ascending, limit);
         long startTime = 0;
         if (Flags.sqliteDiscreteOpEventLoggingEnabled()) {
             startTime = SystemClock.elapsedRealtime();
@@ -249,7 +249,8 @@
         return results;
     }
 
-    private String buildSql(List<SQLCondition> conditions, String orderByColumn, int limit) {
+    private String buildSql(List<SQLCondition> conditions, String orderByColumn, boolean ascending,
+            int limit) {
         StringBuilder sql = new StringBuilder(DiscreteOpsTable.SELECT_TABLE_DATA);
         if (!conditions.isEmpty()) {
             sql.append(" WHERE ");
@@ -264,6 +265,7 @@
 
         if (orderByColumn != null) {
             sql.append(" ORDER BY ").append(orderByColumn);
+            sql.append(ascending ? " ASC " : " DESC ");
         }
         if (limit > 0) {
             sql.append(" LIMIT ").append(limit);
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsMigrationHelper.java b/services/core/java/com/android/server/appop/DiscreteOpsMigrationHelper.java
index c38ee55..29e78be 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsMigrationHelper.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsMigrationHelper.java
@@ -40,7 +40,16 @@
     static void migrateDiscreteOpsToXml(DiscreteOpsSqlRegistry sqlRegistry,
             DiscreteOpsXmlRegistry xmlRegistry) {
         List<DiscreteOpsSqlRegistry.DiscreteOp> sqlOps = sqlRegistry.getAllDiscreteOps();
-        DiscreteOpsXmlRegistry.DiscreteOps xmlOps = getXmlDiscreteOps(sqlOps);
+
+        // Only migrate configured discrete ops. Sqlite may contain all runtime ops, and more.
+        List<DiscreteOpsSqlRegistry.DiscreteOp> filteredList = new ArrayList<>();
+        for (DiscreteOpsSqlRegistry.DiscreteOp opEvent: sqlOps) {
+            if (DiscreteOpsRegistry.isDiscreteOp(opEvent.getOpCode(), opEvent.getOpFlags())) {
+                filteredList.add(opEvent);
+            }
+        }
+
+        DiscreteOpsXmlRegistry.DiscreteOps xmlOps = getXmlDiscreteOps(filteredList);
         xmlRegistry.migrateSqliteData(xmlOps);
         sqlRegistry.deleteDatabase();
     }
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java
index 12c35ae..70b7016 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java
@@ -16,6 +16,9 @@
 
 package com.android.server.appop;
 
+import static android.app.AppOpsManager.OP_ACCESS_ACCESSIBILITY;
+import static android.app.AppOpsManager.OP_ACCESS_NOTIFICATIONS;
+import static android.app.AppOpsManager.OP_BIND_ACCESSIBILITY_SERVICE;
 import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_COARSE_LOCATION;
 import static android.app.AppOpsManager.OP_EMERGENCY_LOCATION;
@@ -23,30 +26,24 @@
 import static android.app.AppOpsManager.OP_FLAG_SELF;
 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY;
+import static android.app.AppOpsManager.OP_GPS;
 import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
 import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
 import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
 import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
-import static android.app.AppOpsManager.OP_PROCESS_OUTGOING_CALLS;
+import static android.app.AppOpsManager.OP_READ_DEVICE_IDENTIFIERS;
 import static android.app.AppOpsManager.OP_READ_HEART_RATE;
-import static android.app.AppOpsManager.OP_READ_ICC_SMS;
 import static android.app.AppOpsManager.OP_READ_OXYGEN_SATURATION;
 import static android.app.AppOpsManager.OP_READ_SKIN_TEMPERATURE;
-import static android.app.AppOpsManager.OP_READ_SMS;
 import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
 import static android.app.AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.OP_RESERVED_FOR_TESTING;
-import static android.app.AppOpsManager.OP_SEND_SMS;
-import static android.app.AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS;
-import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
-import static android.app.AppOpsManager.OP_WRITE_ICC_SMS;
-import static android.app.AppOpsManager.OP_WRITE_SMS;
+import static android.app.AppOpsManager.OP_RUN_IN_BACKGROUND;
 
 import static java.lang.Long.min;
 import static java.lang.Math.max;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
@@ -54,16 +51,13 @@
 import android.os.Build;
 import android.permission.flags.Flags;
 import android.provider.DeviceConfig;
+import android.util.IntArray;
 import android.util.Slog;
 
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FrameworkStatsLog;
-
 import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.text.SimpleDateFormat;
 import java.time.Duration;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.Set;
 
@@ -100,21 +94,37 @@
     static final String PROPERTY_DISCRETE_HISTORY_QUANTIZATION =
             "discrete_history_quantization_millis";
     static final String PROPERTY_DISCRETE_FLAGS = "discrete_history_op_flags";
+    // Comma separated app ops list config for testing i.e. "1,2,3,4"
     static final String PROPERTY_DISCRETE_OPS_LIST = "discrete_history_ops_cslist";
-    static final String DEFAULT_DISCRETE_OPS = OP_FINE_LOCATION + "," + OP_COARSE_LOCATION
+    // These ops are deemed important for detecting a malicious app, and are recorded.
+    static final int[] IMPORTANT_OPS_FOR_SECURITY = new int[] {
+            OP_GPS,
+            OP_ACCESS_NOTIFICATIONS,
+            OP_RUN_IN_BACKGROUND,
+            OP_BIND_ACCESSIBILITY_SERVICE,
+            OP_ACCESS_ACCESSIBILITY,
+            OP_READ_DEVICE_IDENTIFIERS,
+            OP_MONITOR_HIGH_POWER_LOCATION,
+            OP_MONITOR_LOCATION
+    };
+
+    // These are additional ops, which are not backed by runtime permissions, but are recorded.
+    static final int[] ADDITIONAL_DISCRETE_OPS = new int[] {
+            OP_PHONE_CALL_MICROPHONE,
+            OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
+            OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
+            OP_PHONE_CALL_CAMERA,
+            OP_EMERGENCY_LOCATION,
+            OP_RESERVED_FOR_TESTING
+    };
+
+    // Legacy ops captured in discrete database.
+    private static final String LEGACY_OPS = OP_FINE_LOCATION + "," + OP_COARSE_LOCATION
             + "," + OP_EMERGENCY_LOCATION + "," + OP_CAMERA + "," + OP_RECORD_AUDIO + ","
             + OP_PHONE_CALL_MICROPHONE + "," + OP_PHONE_CALL_CAMERA + ","
             + OP_RECEIVE_AMBIENT_TRIGGER_AUDIO + "," + OP_RECEIVE_SANDBOX_TRIGGER_AUDIO
             + "," + OP_READ_HEART_RATE + "," + OP_READ_OXYGEN_SATURATION + ","
             + OP_READ_SKIN_TEMPERATURE + "," + OP_RESERVED_FOR_TESTING;
-    static final int[] sDiscreteOpsToLog =
-            new int[]{OP_FINE_LOCATION, OP_COARSE_LOCATION, OP_EMERGENCY_LOCATION, OP_CAMERA,
-                    OP_RECORD_AUDIO, OP_PHONE_CALL_MICROPHONE, OP_PHONE_CALL_CAMERA,
-                    OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, OP_READ_SMS,
-                    OP_WRITE_SMS, OP_SEND_SMS, OP_READ_ICC_SMS, OP_WRITE_ICC_SMS,
-                    OP_SMS_FINANCIAL_TRANSACTIONS, OP_SYSTEM_ALERT_WINDOW, OP_MONITOR_LOCATION,
-                    OP_MONITOR_HIGH_POWER_LOCATION, OP_PROCESS_OUTGOING_CALLS,
-            };
 
     static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(7).toMillis();
     static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis();
@@ -126,7 +136,7 @@
     // in case of duplicate op events.
     static long sDiscreteHistoryQuantization;
 
-    static int[] sDiscreteOps;
+    static int[] sDiscreteOps = new int[0];
     static int sDiscreteFlags;
 
     static final int OP_FLAGS_DISCRETE = OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED
@@ -134,27 +144,6 @@
 
     boolean mDebugMode = false;
 
-    static final int ACCESS_TYPE_NOTE_OP =
-            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__NOTE_OP;
-    static final int ACCESS_TYPE_START_OP =
-            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__START_OP;
-    static final int ACCESS_TYPE_FINISH_OP =
-            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__FINISH_OP;
-    static final int ACCESS_TYPE_PAUSE_OP =
-            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__PAUSE_OP;
-    static final int ACCESS_TYPE_RESUME_OP =
-            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__RESUME_OP;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"ACCESS_TYPE_"}, value = {
-            ACCESS_TYPE_NOTE_OP,
-            ACCESS_TYPE_START_OP,
-            ACCESS_TYPE_FINISH_OP,
-            ACCESS_TYPE_PAUSE_OP,
-            ACCESS_TYPE_RESUME_OP
-    })
-    @interface AccessType {}
-
     void systemReady() {
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY,
                 AsyncTask.THREAD_POOL_EXECUTOR, (DeviceConfig.Properties p) -> {
@@ -166,8 +155,7 @@
     abstract void recordDiscreteAccess(int uid, String packageName, @NonNull String deviceId,
             int op, @Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
             @AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
-            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
-            @DiscreteOpsRegistry.AccessType int accessType);
+            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId);
 
     /**
      * A periodic callback from {@link AppOpsService} to flush the in memory events to disk.
@@ -218,7 +206,7 @@
     }
 
     static boolean isDiscreteOp(int op, @AppOpsManager.OpFlags int flags) {
-        if (!ArrayUtils.contains(sDiscreteOps, op)) {
+        if (Arrays.binarySearch(sDiscreteOps, op) < 0) {
             return false;
         }
         if ((flags & (sDiscreteFlags)) == 0) {
@@ -227,9 +215,6 @@
         return true;
     }
 
-    // could this be impl detail of discrete registry, just one test is using the method
-    // abstract DiscreteRegistry.DiscreteOps getAllDiscreteOps();
-
     private void setDiscreteHistoryParameters(DeviceConfig.Properties p) {
         if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_CUTOFF)) {
             sDiscreteHistoryCutoff = p.getLong(PROPERTY_DISCRETE_HISTORY_CUTOFF,
@@ -251,11 +236,42 @@
         } else {
             sDiscreteHistoryQuantization = DEFAULT_DISCRETE_HISTORY_QUANTIZATION;
         }
-        sDiscreteFlags = p.getKeyset().contains(PROPERTY_DISCRETE_FLAGS) ? sDiscreteFlags =
-                p.getInt(PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE) : OP_FLAGS_DISCRETE;
-        sDiscreteOps = p.getKeyset().contains(PROPERTY_DISCRETE_OPS_LIST) ? parseOpsList(
-                p.getString(PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)) : parseOpsList(
-                DEFAULT_DISCRETE_OPS);
+        sDiscreteFlags = p.getKeyset().contains(PROPERTY_DISCRETE_FLAGS)
+                ? p.getInt(PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE) : OP_FLAGS_DISCRETE;
+        String opsListConfig = p.getString(PROPERTY_DISCRETE_OPS_LIST, null);
+        sDiscreteOps = opsListConfig == null ? getDefaultOpsList() : parseOpsList(opsListConfig);
+
+        Arrays.sort(sDiscreteOps);
+    }
+
+    // App ops backed by runtime/dangerous permissions.
+    private static IntArray getRuntimePermissionOps() {
+        IntArray runtimeOps = new IntArray();
+        for (int op = 0; op < AppOpsManager._NUM_OP; op++) {
+            if (AppOpsManager.opIsRuntimePermission(op)) {
+                runtimeOps.add(op);
+            }
+        }
+        return runtimeOps;
+    }
+
+    /**
+     * @return an array of app ops captured into discrete database.
+     */
+    private static int[] getDefaultOpsList() {
+        if (!(Flags.recordAllRuntimeAppopsSqlite() && Flags.enableSqliteAppopsAccesses())) {
+            return getDefaultLegacyOps();
+        }
+
+        IntArray discreteOpsArray = getRuntimePermissionOps();
+        discreteOpsArray.addAll(IMPORTANT_OPS_FOR_SECURITY);
+        discreteOpsArray.addAll(ADDITIONAL_DISCRETE_OPS);
+
+        return discreteOpsArray.toArray();
+    }
+
+    private static int[] getDefaultLegacyOps() {
+        return parseOpsList(LEGACY_OPS);
     }
 
     private static int[] parseOpsList(String opsList) {
@@ -273,32 +289,8 @@
             }
         } catch (NumberFormatException e) {
             Slog.e(TAG, "Failed to parse Discrete ops list: " + e.getMessage());
-            return parseOpsList(DEFAULT_DISCRETE_OPS);
+            return getDefaultOpsList();
         }
         return result;
     }
-
-    /**
-     * Whether app op access tacking is enabled and a metric event should be logged.
-     */
-    static boolean shouldLogAccess(int op) {
-        return Flags.appopAccessTrackingLoggingEnabled()
-                && ArrayUtils.contains(sDiscreteOpsToLog, op);
-    }
-
-    String getAttributionTag(String attributionTag, String packageName) {
-        if (attributionTag == null || packageName == null) {
-            return attributionTag;
-        }
-        int firstChar = 0;
-        if (attributionTag.startsWith(packageName)) {
-            firstChar = packageName.length();
-            if (firstChar < attributionTag.length() && attributionTag.charAt(firstChar)
-                    == '.') {
-                firstChar++;
-            }
-        }
-        return attributionTag.substring(firstChar);
-    }
-
 }
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
index dc11be9..0e1fbf3 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
@@ -36,7 +36,6 @@
 import android.util.LongSparseArray;
 import android.util.Slog;
 
-import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.ServiceThread;
 
 import java.io.File;
@@ -97,15 +96,7 @@
     void recordDiscreteAccess(int uid, String packageName,
             @NonNull String deviceId, int op,
             @Nullable String attributionTag, int flags, int uidState,
-            long accessTime, long accessDuration, int attributionFlags, int attributionChainId,
-            int accessType) {
-        if (shouldLogAccess(op)) {
-            FrameworkStatsLog.write(FrameworkStatsLog.APP_OP_ACCESS_TRACKED, uid, op, accessType,
-                    uidState, flags, attributionFlags,
-                    getAttributionTag(attributionTag, packageName),
-                    attributionChainId);
-        }
-
+            long accessTime, long accessDuration, int attributionFlags, int attributionChainId) {
         if (!isDiscreteOp(op, flags)) {
             return;
         }
@@ -189,7 +180,7 @@
                 ChronoUnit.MILLIS).toEpochMilli());
         List<DiscreteOp> discreteOps = mDiscreteOpsDbHelper.getDiscreteOps(filter, uidFilter,
                 packageNameFilter, attributionTagFilter, opCodes, opFlagsFilter, beginTimeMillis,
-                endTimeMillis, -1, null);
+                endTimeMillis, -1, null, false);
 
         LongSparseArray<AttributionChain> attributionChains = null;
         if (assembleChains) {
@@ -222,14 +213,15 @@
             @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp,
             @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix,
             int nDiscreteOps) {
-        writeAndClearOldAccessHistory();
+        // flush the cache into database before dump.
+        mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear());
         IntArray opCodes = new IntArray();
         if (dumpOp != AppOpsManager.OP_NONE) {
             opCodes.add(dumpOp);
         }
         List<DiscreteOp> discreteOps = mDiscreteOpsDbHelper.getDiscreteOps(filter, uidFilter,
                 packageNameFilter, attributionTagFilter, opCodes, 0, -1,
-                -1, nDiscreteOps, DiscreteOpsTable.Columns.ACCESS_TIME);
+                -1, nDiscreteOps, DiscreteOpsTable.Columns.ACCESS_TIME, false);
 
         pw.print(prefix);
         pw.print("Largest chain id: ");
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsTestingShim.java b/services/core/java/com/android/server/appop/DiscreteOpsTestingShim.java
index 1523cca..909a04c 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsTestingShim.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsTestingShim.java
@@ -48,15 +48,13 @@
     @Override
     void recordDiscreteAccess(int uid, String packageName, @NonNull String deviceId, int op,
             @Nullable String attributionTag, int flags, int uidState, long accessTime,
-            long accessDuration, int attributionFlags, int attributionChainId, int accessType) {
+            long accessDuration, int attributionFlags, int attributionChainId) {
         long start = SystemClock.uptimeMillis();
         mXmlRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, attributionTag, flags,
-                uidState, accessTime, accessDuration, attributionFlags, attributionChainId,
-                accessType);
+                uidState, accessTime, accessDuration, attributionFlags, attributionChainId);
         long start2 = SystemClock.uptimeMillis();
         mSqlRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, attributionTag, flags,
-                uidState, accessTime, accessDuration, attributionFlags, attributionChainId,
-                accessType);
+                uidState, accessTime, accessDuration, attributionFlags, attributionChainId);
         long end = SystemClock.uptimeMillis();
         long xmlTimeTaken = start2 - start;
         long sqlTimeTaken = end - start2;
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsXmlRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsXmlRegistry.java
index a6e3fc7..20706b6 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsXmlRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsXmlRegistry.java
@@ -45,7 +45,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -159,15 +158,7 @@
     void recordDiscreteAccess(int uid, String packageName, @NonNull String deviceId, int op,
             @Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
             @AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
-            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
-            @AccessType int accessType) {
-        if (shouldLogAccess(op)) {
-            FrameworkStatsLog.write(FrameworkStatsLog.APP_OP_ACCESS_TRACKED, uid, op, accessType,
-                    uidState, flags, attributionFlags,
-                    getAttributionTag(attributionTag, packageName),
-                    attributionChainId);
-        }
-
+            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
         if (!isDiscreteOp(op, flags)) {
             return;
         }
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index d267e0d..06e43e8 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -497,7 +497,7 @@
             @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
             @OpFlags int flags, long accessTime,
             @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
-            @DiscreteOpsRegistry.AccessType int accessType, int accessCount) {
+            int accessCount) {
         synchronized (mInMemoryLock) {
             if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                 if (!isPersistenceInitializedMLocked()) {
@@ -510,7 +510,7 @@
 
                 mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
                         attributionTag, flags, uidState, accessTime, -1, attributionFlags,
-                        attributionChainId, accessType);
+                        attributionChainId);
             }
         }
     }
@@ -533,8 +533,7 @@
     void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
             @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
             @OpFlags int flags, long eventStartTime, long increment,
-            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
-            @DiscreteOpsRegistry.AccessType int accessType) {
+            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
         synchronized (mInMemoryLock) {
             if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                 if (!isPersistenceInitializedMLocked()) {
@@ -546,7 +545,7 @@
                         attributionTag, uidState, flags, increment);
                 mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
                         attributionTag, flags, uidState, eventStartTime, increment,
-                        attributionFlags, attributionChainId, accessType);
+                        attributionFlags, attributionChainId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 8ef79a91..4b5f06b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1472,8 +1472,8 @@
         mAudioService.postAccessoryPlugMediaUnmute(device);
     }
 
-    /*package*/ int getVssVolumeForDevice(int streamType, int device) {
-        return mAudioService.getVssVolumeForDevice(streamType, device);
+    /*package*/ int getVolumeForDeviceIgnoreMute(int streamType, int device) {
+        return mAudioService.getVolumeForDeviceIgnoreMute(streamType, device);
     }
 
     /*package*/ int getMaxVssVolumeForStream(int streamType) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 829d9ea..2e6d984 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -2482,7 +2482,7 @@
     @GuardedBy("mDevicesLock")
     private void makeHearingAidDeviceAvailable(
             String address, String name, int streamType, String eventSource) {
-        final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
+        final int hearingAidVolIndex = mDeviceBroker.getVolumeForDeviceIgnoreMute(streamType,
                 DEVICE_OUT_HEARING_AID);
         mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
 
@@ -2672,7 +2672,7 @@
             }
 
             final int leAudioVolIndex = (volumeIndex == -1)
-                    ? mDeviceBroker.getVssVolumeForDevice(streamType, device)
+                    ? mDeviceBroker.getVolumeForDeviceIgnoreMute(streamType, device)
                     : volumeIndex;
             final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType);
             mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ada1cd7..a43e4d9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -529,7 +529,7 @@
      */
     private InputDeviceVolumeHelper mInputDeviceVolumeHelper;
 
-    /*package*/ int getVssVolumeForDevice(int stream, int device) {
+    /*package*/ int getVolumeForDeviceIgnoreMute(int stream, int device) {
         final VolumeStreamState streamState = mStreamStates.get(stream);
         return streamState != null ? streamState.getIndex(device) : -1;
     }
@@ -5098,7 +5098,7 @@
         }
 
         final int device = absVolumeDevices.toArray(new Integer[0])[0].intValue();
-        final int index = getStreamVolume(streamType, device);
+        final int index = getVolumeForDeviceIgnoreMute(streamType, device);
 
         if (DEBUG_VOL) {
             Slog.i(TAG, "onUpdateContextualVolumes streamType: " + streamType
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 643f330..67afff7 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -724,7 +724,7 @@
                 int device = mAudioService.getDeviceForStream(AudioSystem.STREAM_MUSIC);
                 if (safeDevicesContains(device) && isStreamActive) {
                     scheduleMusicActiveCheck();
-                    int index = mAudioService.getVssVolumeForDevice(AudioSystem.STREAM_MUSIC,
+                    int index = mAudioService.getVolumeForDeviceIgnoreMute(AudioSystem.STREAM_MUSIC,
                             device);
                     if (index > safeMediaVolumeIndex(device)) {
                         // Approximate cumulative active music time
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 969a684..2d387ea 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -261,6 +261,7 @@
     private final SyncLogger mLogger;
 
     private final AppCloningDeviceConfigHelper mAppCloningDeviceConfigHelper;
+    private final PackageMonitorImpl mPackageMonitor;
 
     private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
         for (int i = 0, size = pendingJobs.size(); i < size; i++) {
@@ -725,8 +726,8 @@
                 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
 
 
-        final PackageMonitor packageMonitor = new PackageMonitorImpl();
-        packageMonitor.register(mContext, null /* thread */, UserHandle.ALL,
+        mPackageMonitor = new PackageMonitorImpl();
+        mPackageMonitor.register(mContext, null /* thread */, UserHandle.ALL,
                 false /* externalStorage */);
 
         intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
diff --git a/services/core/java/com/android/server/display/DisplayControl.java b/services/core/java/com/android/server/display/DisplayControl.java
index ddea285..1d70953 100644
--- a/services/core/java/com/android/server/display/DisplayControl.java
+++ b/services/core/java/com/android/server/display/DisplayControl.java
@@ -29,7 +29,7 @@
  */
 public class DisplayControl {
     private static native IBinder nativeCreateVirtualDisplay(String name, boolean secure,
-            String uniqueId, float requestedRefreshRate);
+            boolean optimizeForPower, String uniqueId, float requestedRefreshRate);
     private static native void nativeDestroyVirtualDisplay(IBinder displayToken);
     private static native void nativeOverrideHdrTypes(IBinder displayToken, int[] modes);
     private static native long[] nativeGetPhysicalDisplayIds();
@@ -49,7 +49,7 @@
      */
     public static IBinder createVirtualDisplay(String name, boolean secure) {
         Objects.requireNonNull(name, "name must not be null");
-        return nativeCreateVirtualDisplay(name, secure, "", 0.0f);
+        return nativeCreateVirtualDisplay(name, secure, true, "", 0.0f);
     }
 
     /**
@@ -57,6 +57,10 @@
      *
      * @param name The name of the virtual display.
      * @param secure Whether this display is secure.
+     * @param optimizeForPower Whether SurfaceFlinger should optimize for power (instead of
+     *                         performance). Such displays will depend on another display for it to
+     *                         be shown and rendered, and that display will optimize for
+     *                         performance when it is on.
      * @param uniqueId The unique ID for the display.
      * @param requestedRefreshRate The requested refresh rate in frames per second.
      * For best results, specify a divisor of the physical refresh rate, e.g., 30 or 60 on
@@ -66,10 +70,11 @@
      * @return The token reference for the display in SurfaceFlinger.
      */
     public static IBinder createVirtualDisplay(String name, boolean secure,
-            String uniqueId, float requestedRefreshRate) {
+            boolean optimizeForPower, String uniqueId, float requestedRefreshRate) {
         Objects.requireNonNull(name, "name must not be null");
         Objects.requireNonNull(uniqueId, "uniqueId must not be null");
-        return nativeCreateVirtualDisplay(name, secure, uniqueId, requestedRefreshRate);
+        return nativeCreateVirtualDisplay(name, secure, optimizeForPower, uniqueId,
+                requestedRefreshRate);
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d402f01..a28069b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -674,9 +674,9 @@
         mConfigParameterProvider = new DeviceConfigParameterProvider(DeviceConfigInterface.REAL);
         mExtraDisplayLoggingPackageName = DisplayProperties.debug_vri_package().orElse(null);
         mExtraDisplayEventLogging = !TextUtils.isEmpty(mExtraDisplayLoggingPackageName);
-
+        // TODO(b/400384229): stats service needs to react to mirror-extended switch
         mExternalDisplayStatsService = new ExternalDisplayStatsService(mContext, mHandler,
-                this::isExtendedDisplayEnabled);
+                this::isExtendedDisplayAllowed);
         mDisplayNotificationManager = new DisplayNotificationManager(mFlags, mContext,
                 mExternalDisplayStatsService);
         mExternalDisplayPolicy = new ExternalDisplayPolicy(new ExternalDisplayPolicyInjector());
@@ -690,7 +690,7 @@
                         deliverTopologyUpdate(update.first);
                     };
             mDisplayTopologyCoordinator = new DisplayTopologyCoordinator(
-                    this::isExtendedDisplayEnabled, topologyChangedCallback,
+                    this::isExtendedDisplayAllowed, topologyChangedCallback,
                     new HandlerExecutor(mHandler), mSyncRoot, backupManager::dataChanged);
         } else {
             mDisplayTopologyCoordinator = null;
@@ -2411,7 +2411,10 @@
         updateLogicalDisplayState(display);
     }
 
-    private boolean isExtendedDisplayEnabled() {
+    private boolean isExtendedDisplayAllowed() {
+        if (mFlags.isDisplayContentModeManagementEnabled()) {
+            return true;
+        }
         try {
             return 0 != Settings.Global.getInt(
                     mContext.getContentResolver(),
@@ -2442,7 +2445,10 @@
             applyDisplayChangedLocked(display);
         }
 
-        if (mDisplayTopologyCoordinator != null) {
+        // The default display should always be added to the topology. Other displays will be added
+        // upon calling onDisplayBelongToTopologyChanged().
+        if (mDisplayTopologyCoordinator != null
+                && display.getDisplayIdLocked() == Display.DEFAULT_DISPLAY) {
             mDisplayTopologyCoordinator.onDisplayAdded(display.getDisplayInfoLocked());
         }
     }
@@ -6037,6 +6043,24 @@
         }
 
         @Override
+        public void onDisplayBelongToTopologyChanged(int displayId, boolean inTopology) {
+            if (mDisplayTopologyCoordinator == null) {
+                return;
+            }
+            if (inTopology) {
+                var info = getDisplayInfo(displayId);
+                if (info == null) {
+                    Slog.w(TAG, "onDisplayBelongToTopologyChanged: cancelled displayId="
+                            + displayId + " info=null");
+                    return;
+                }
+                mDisplayTopologyCoordinator.onDisplayAdded(info);
+            } else {
+                mDisplayTopologyCoordinator.onDisplayRemoved(displayId);
+            }
+        }
+
+        @Override
         public void reloadTopologies(final int userId) {
             // Reload topologies only if the userId matches the current user id.
             if (userId == mCurrentUserId) {
diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
index 2618cf4..b4df1f7 100644
--- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
+++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
@@ -69,9 +69,9 @@
     private final SparseArray<String> mDisplayIdToUniqueIdMapping = new SparseArray<>();
 
     /**
-     * Check if extended displays are enabled. If not, a topology is not needed.
+     * Check if extended displays are allowed. If not, a topology is not needed.
      */
-    private final BooleanSupplier mIsExtendedDisplayEnabled;
+    private final BooleanSupplier mIsExtendedDisplayAllowed;
 
     /**
      * Callback used to send topology updates.
@@ -83,21 +83,21 @@
     private final DisplayManagerService.SyncRoot mSyncRoot;
     private final Runnable mTopologySavedCallback;
 
-    DisplayTopologyCoordinator(BooleanSupplier isExtendedDisplayEnabled,
+    DisplayTopologyCoordinator(BooleanSupplier isExtendedDisplayAllowed,
             Consumer<Pair<DisplayTopology, DisplayTopologyGraph>> onTopologyChangedCallback,
             Executor topologyChangeExecutor, DisplayManagerService.SyncRoot syncRoot,
             Runnable topologySavedCallback) {
-        this(new Injector(), isExtendedDisplayEnabled, onTopologyChangedCallback,
+        this(new Injector(), isExtendedDisplayAllowed, onTopologyChangedCallback,
                 topologyChangeExecutor, syncRoot, topologySavedCallback);
     }
 
     @VisibleForTesting
-    DisplayTopologyCoordinator(Injector injector, BooleanSupplier isExtendedDisplayEnabled,
+    DisplayTopologyCoordinator(Injector injector, BooleanSupplier isExtendedDisplayAllowed,
             Consumer<Pair<DisplayTopology, DisplayTopologyGraph>> onTopologyChangedCallback,
             Executor topologyChangeExecutor, DisplayManagerService.SyncRoot syncRoot,
             Runnable topologySavedCallback) {
         mTopology = injector.getTopology();
-        mIsExtendedDisplayEnabled = isExtendedDisplayEnabled;
+        mIsExtendedDisplayAllowed = isExtendedDisplayAllowed;
         mOnTopologyChangedCallback = onTopologyChangedCallback;
         mTopologyChangeExecutor = topologyChangeExecutor;
         mSyncRoot = syncRoot;
@@ -262,14 +262,9 @@
             return false;
         }
         if ((info.type == Display.TYPE_EXTERNAL || info.type == Display.TYPE_OVERLAY)
-                && !mIsExtendedDisplayEnabled.getAsBoolean()) {
+                && !mIsExtendedDisplayAllowed.getAsBoolean()) {
             Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
-                    + "type is EXTERNAL or OVERLAY and !mIsExtendedDisplayEnabled");
-            return false;
-        }
-        if (info.displayGroupId != Display.DEFAULT_DISPLAY_GROUP) {
-            Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
-                    + "it is not in the default display group");
+                    + "type is EXTERNAL or OVERLAY and !mIsExtendedDisplayAllowed");
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index ac03a93..c2eac86 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -103,10 +103,10 @@
             Context context, Handler handler, Listener listener, DisplayManagerFlags featureFlags) {
         this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() {
             @Override
-            public IBinder createDisplay(String name, boolean secure, String uniqueId,
-                                         float requestedRefreshRate) {
-                return DisplayControl.createVirtualDisplay(name, secure, uniqueId,
-                                                           requestedRefreshRate);
+            public IBinder createDisplay(String name, boolean secure, boolean optimizeForPower,
+                    String uniqueId, float requestedRefreshRate) {
+                return DisplayControl.createVirtualDisplay(name, secure, optimizeForPower, uniqueId,
+                        requestedRefreshRate);
             }
 
             @Override
@@ -182,9 +182,13 @@
 
         String name = virtualDisplayConfig.getName();
         boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
+        boolean neverBlank = isNeverBlank(flags);
 
-        IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure, uniqueId,
-                virtualDisplayConfig.getRequestedRefreshRate());
+        // Never-blank displays are considered to be dependent on another display to be rendered.
+        // As a result, such displays should optimize for power instead of performance when it is
+        // powered on.
+        IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure, neverBlank,
+                uniqueId, virtualDisplayConfig.getRequestedRefreshRate());
         MediaProjectionCallback mediaProjectionCallback =  null;
         if (projection != null) {
             mediaProjectionCallback = new MediaProjectionCallback(appToken);
@@ -318,6 +322,12 @@
         return mVirtualDisplayDevices.remove(appToken);
     }
 
+    private static boolean isNeverBlank(int flags) {
+        // Private non-mirror displays are never blank and always on.
+        return (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0
+                && (flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0;
+    }
+
     private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
         private static final int PENDING_SURFACE_CHANGE = 0x01;
         private static final int PENDING_RESIZE = 0x02;
@@ -377,9 +387,7 @@
             mCallback = callback;
             mProjection = projection;
             mMediaProjectionCallback = mediaProjectionCallback;
-            // Private non-mirror displays are never blank and always on.
-            mNeverBlank = (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0
-                    && (flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0;
+            mNeverBlank = isNeverBlank(flags);
             if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()
                     && !mNeverBlank) {
                 // The display's power state depends on the power state of the state of its
@@ -782,6 +790,10 @@
          *
          * @param name The name of the display.
          * @param secure Whether this display is secure.
+         * @param optimizeForPower Whether SurfaceFlinger should optimize for power (instead of
+         *                         performance). Such displays will depend on another display for
+         *                         it to be shown and rendered, and that display will optimize for
+         *                         performance when it is on.
          * @param uniqueId The unique ID for the display.
          * @param requestedRefreshRate
          *     The refresh rate, frames per second, to request on the virtual display.
@@ -791,8 +803,8 @@
          *     the refresh rate of the leader physical display.
          * @return The token reference for the display in SurfaceFlinger.
          */
-        IBinder createDisplay(String name, boolean secure, String uniqueId,
-                              float requestedRefreshRate);
+        IBinder createDisplay(String name, boolean secure, boolean optimizeForPower,
+                String uniqueId, float requestedRefreshRate);
 
         /**
          * Destroy a display in SurfaceFlinger.
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 6e5e0fd5..af06586 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -193,6 +193,8 @@
     @Nullable
     private UserManagerInternal mUm;
 
+    private final MyPackageMonitor mPackageMonitor;
+
     /**
      * Default constructor.
      *
@@ -289,6 +291,7 @@
                 }
             });
         }
+        mPackageMonitor = new MyPackageMonitor(/* supportsPackageRestartQuery */ true);
         startTrackingPackageChanges();
     }
 
@@ -986,260 +989,264 @@
         }
     }
 
-    private void startTrackingPackageChanges() {
-        final PackageMonitor monitor = new PackageMonitor(true) {
+    private class MyPackageMonitor extends PackageMonitor {
+        MyPackageMonitor(boolean supportsPackageRestartQuery) {
+            super(supportsPackageRestartQuery);
+        }
 
-            @Override
-            public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
-                if (verbose) Slog.v(mTag, "onPackageUpdateStarted(): " + packageName);
+        @Override
+        public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
+            if (verbose) Slog.v(mTag, "onPackageUpdateStarted(): " + packageName);
+            synchronized (mLock) {
                 final String activePackageName = getActiveServicePackageNameLocked();
                 if (!packageName.equals(activePackageName)) return;
 
                 final int userId = getChangingUserId();
-                synchronized (mLock) {
-                    if (mUpdatingPackageNames == null) {
-                        mUpdatingPackageNames = new SparseArray<String>(mServicesCacheList.size());
-                    }
-                    mUpdatingPackageNames.put(userId, packageName);
-                    onServicePackageUpdatingLocked(userId);
-                    if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) {
-                        if (debug) {
-                            Slog.d(mTag, "Holding service for user " + userId + " while package "
-                                    + activePackageName + " is being updated");
-                        }
-                    } else {
-                        if (debug) {
-                            Slog.d(mTag, "Removing service for user " + userId
-                                    + " because package " + activePackageName
-                                    + " is being updated");
-                        }
-                        removeCachedServiceListLocked(userId);
 
-                        if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
-                                != 0) {
-                            if (debug) {
-                                Slog.d(mTag, "Eagerly recreating service for user "
-                                        + userId);
-                            }
-                            getServiceForUserLocked(userId);
-                        }
-                    }
+                if (mUpdatingPackageNames == null) {
+                    mUpdatingPackageNames = new SparseArray<String>(mServicesCacheList.size());
                 }
-            }
-
-            @Override
-            public void onPackageUpdateFinished(@NonNull String packageName, int uid) {
-                if (verbose) Slog.v(mTag, "onPackageUpdateFinished(): " + packageName);
-                final int userId = getChangingUserId();
-                synchronized (mLock) {
-                    final String activePackageName = mUpdatingPackageNames == null ? null
-                            : mUpdatingPackageNames.get(userId);
-                    if (packageName.equals(activePackageName)) {
-                        if (mUpdatingPackageNames != null) {
-                            mUpdatingPackageNames.remove(userId);
-                            if (mUpdatingPackageNames.size() == 0) {
-                                mUpdatingPackageNames = null;
-                            }
-                        }
-                        onServicePackageUpdatedLocked(userId);
-                    } else {
-                        handlePackageUpdateLocked(packageName);
-                    }
-                }
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                if (mServiceNameResolver != null
-                        && mServiceNameResolver.isConfiguredInMultipleMode()) {
-                    final int userId = getChangingUserId();
-                    synchronized (mLock) {
-                        handlePackageRemovedMultiModeLocked(packageName, userId);
-                    }
-                    return;
-                }
-
-                synchronized (mLock) {
-                    final int userId = getChangingUserId();
-                    final S service = peekServiceForUserLocked(userId);
-                    if (service != null) {
-                        final ComponentName componentName = service.getServiceComponentName();
-                        if (componentName != null) {
-                            if (packageName.equals(componentName.getPackageName())) {
-                                handleActiveServiceRemoved(userId);
-                            }
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public boolean onHandleForceStop(Intent intent, String[] packages,
-                    int uid, boolean doit) {
-                synchronized (mLock) {
-                    final String activePackageName = getActiveServicePackageNameLocked();
-                    for (String pkg : packages) {
-                        if (pkg.equals(activePackageName)) {
-                            if (!doit) {
-                                return true;
-                            }
-                            final String action = intent.getAction();
-                            final int userId = getChangingUserId();
-                            if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
-                                handleActiveServiceRestartedLocked(activePackageName, userId);
-                            } else {
-                                removeCachedServiceListLocked(userId);
-                            }
-                        } else {
-                            handlePackageUpdateLocked(pkg);
-                        }
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            public void onPackageDataCleared(String packageName, int uid) {
-                if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName);
-                final int userId = getChangingUserId();
-
-                if (mServiceNameResolver != null
-                        && mServiceNameResolver.isConfiguredInMultipleMode()) {
-                    synchronized (mLock) {
-                        onServicePackageDataClearedMultiModeLocked(packageName, userId);
-                    }
-                    return;
-                }
-
-                synchronized (mLock) {
-                    final S service = peekServiceForUserLocked(userId);
-                    if (service != null) {
-                        final ComponentName componentName = service.getServiceComponentName();
-                        if (componentName != null) {
-                            if (packageName.equals(componentName.getPackageName())) {
-                                onServicePackageDataClearedLocked(userId);
-                            }
-                        }
-                    }
-                }
-            }
-
-            private void handleActiveServiceRemoved(@UserIdInt int userId) {
-                synchronized (mLock) {
-                    removeCachedServiceListLocked(userId);
-                }
-                final String serviceSettingsProperty = getServiceSettingsProperty();
-                if (serviceSettingsProperty != null) {
-                    Settings.Secure.putStringForUser(getContext().getContentResolver(),
-                            serviceSettingsProperty, null, userId);
-                }
-            }
-
-            @GuardedBy("mLock")
-            private void handleActiveServiceRestartedLocked(String activePackageName,
-                    @UserIdInt int userId) {
-                if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
+                mUpdatingPackageNames.put(userId, packageName);
+                onServicePackageUpdatingLocked(userId);
+                if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) {
                     if (debug) {
                         Slog.d(mTag, "Holding service for user " + userId + " while package "
-                                + activePackageName + " is being restarted");
+                                + activePackageName + " is being updated");
                     }
                 } else {
                     if (debug) {
                         Slog.d(mTag, "Removing service for user " + userId
                                 + " because package " + activePackageName
-                                + " is being restarted");
+                                + " is being updated");
                     }
                     removeCachedServiceListLocked(userId);
 
-                    if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
+                    if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
+                            != 0) {
                         if (debug) {
-                            Slog.d(mTag, "Eagerly recreating service for user " + userId);
+                            Slog.d(mTag, "Eagerly recreating service for user "
+                                    + userId);
                         }
-                        updateCachedServiceLocked(userId);
+                        getServiceForUserLocked(userId);
                     }
                 }
-                onServicePackageRestartedLocked(userId);
             }
+        }
 
-            @Override
-            public void onPackageModified(String packageName) {
+        @Override
+        public void onPackageUpdateFinished(@NonNull String packageName, int uid) {
+            if (verbose) Slog.v(mTag, "onPackageUpdateFinished(): " + packageName);
+            final int userId = getChangingUserId();
+            synchronized (mLock) {
+                final String activePackageName = mUpdatingPackageNames == null ? null
+                        : mUpdatingPackageNames.get(userId);
+                if (packageName.equals(activePackageName)) {
+                    if (mUpdatingPackageNames != null) {
+                        mUpdatingPackageNames.remove(userId);
+                        if (mUpdatingPackageNames.size() == 0) {
+                            mUpdatingPackageNames = null;
+                        }
+                    }
+                    onServicePackageUpdatedLocked(userId);
+                } else {
+                    handlePackageUpdateLocked(packageName);
+                }
+            }
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            if (mServiceNameResolver != null
+                    && mServiceNameResolver.isConfiguredInMultipleMode()) {
+                final int userId = getChangingUserId();
                 synchronized (mLock) {
-                    if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
-
-                    if (mServiceNameResolver == null) {
-                        return;
-                    }
-
-                    final int userId = getChangingUserId();
-                    final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList(
-                            userId);
-                    if (serviceNames != null) {
-                        if (Flags.packageUpdateFixEnabled()) {
-                            if (mServiceNameResolver.isConfiguredInMultipleMode()) {
-                                // Remove any service that is in the cache but is no longer valid
-                                // after this modification for this particular package
-                                removeInvalidCachedServicesLocked(serviceNames, packageName,
-                                        userId);
-                            }
-                        }
-
-                        // Update services that are still valid
-                        for (int i = 0; i < serviceNames.length; i++) {
-                            peekAndUpdateCachedServiceLocked(packageName, userId,
-                                    serviceNames[i]);
-                        }
-                    }
+                    handlePackageRemovedMultiModeLocked(packageName, userId);
                 }
+                return;
             }
 
-            @GuardedBy("mLock")
-            private void peekAndUpdateCachedServiceLocked(String packageName, int userId,
-                    String serviceName) {
-                if (serviceName == null) {
-                    return;
-                }
-
-                final ComponentName serviceComponentName =
-                        ComponentName.unflattenFromString(serviceName);
-                if (serviceComponentName == null
-                        || !serviceComponentName.getPackageName().equals(packageName)) {
-                    return;
-                }
-
-                // The default service package has changed, update the cached if the service
-                // exists but no active component.
+            synchronized (mLock) {
+                final int userId = getChangingUserId();
                 final S service = peekServiceForUserLocked(userId);
                 if (service != null) {
                     final ComponentName componentName = service.getServiceComponentName();
-                    if (componentName == null) {
-                        if (verbose) Slog.v(mTag, "update cached");
-                        updateCachedServiceLocked(userId);
+                    if (componentName != null) {
+                        if (packageName.equals(componentName.getPackageName())) {
+                            handleActiveServiceRemoved(userId);
+                        }
                     }
                 }
             }
+        }
 
-            @GuardedBy("mLock")
-            private String getActiveServicePackageNameLocked() {
-                final int userId = getChangingUserId();
+        @Override
+        public boolean onHandleForceStop(Intent intent, String[] packages,
+                int uid, boolean doit) {
+            synchronized (mLock) {
+                final String activePackageName = getActiveServicePackageNameLocked();
+                for (String pkg : packages) {
+                    if (pkg.equals(activePackageName)) {
+                        if (!doit) {
+                            return true;
+                        }
+                        final String action = intent.getAction();
+                        final int userId = getChangingUserId();
+                        if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
+                            handleActiveServiceRestartedLocked(activePackageName, userId);
+                        } else {
+                            removeCachedServiceListLocked(userId);
+                        }
+                    } else {
+                        handlePackageUpdateLocked(pkg);
+                    }
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void onPackageDataCleared(String packageName, int uid) {
+            if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName);
+            final int userId = getChangingUserId();
+
+            if (mServiceNameResolver != null
+                    && mServiceNameResolver.isConfiguredInMultipleMode()) {
+                synchronized (mLock) {
+                    onServicePackageDataClearedMultiModeLocked(packageName, userId);
+                }
+                return;
+            }
+
+            synchronized (mLock) {
                 final S service = peekServiceForUserLocked(userId);
-                if (service == null) {
-                    return null;
+                if (service != null) {
+                    final ComponentName componentName = service.getServiceComponentName();
+                    if (componentName != null) {
+                        if (packageName.equals(componentName.getPackageName())) {
+                            onServicePackageDataClearedLocked(userId);
+                        }
+                    }
                 }
-                final ComponentName serviceComponent = service.getServiceComponentName();
-                if (serviceComponent == null) {
-                    return null;
+            }
+        }
+
+        private void handleActiveServiceRemoved(@UserIdInt int userId) {
+            synchronized (mLock) {
+                removeCachedServiceListLocked(userId);
+            }
+            final String serviceSettingsProperty = getServiceSettingsProperty();
+            if (serviceSettingsProperty != null) {
+                Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                        serviceSettingsProperty, null, userId);
+            }
+        }
+
+        @GuardedBy("mLock")
+        private void handleActiveServiceRestartedLocked(String activePackageName,
+                @UserIdInt int userId) {
+            if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
+                if (debug) {
+                    Slog.d(mTag, "Holding service for user " + userId + " while package "
+                            + activePackageName + " is being restarted");
                 }
-                return serviceComponent.getPackageName();
+            } else {
+                if (debug) {
+                    Slog.d(mTag, "Removing service for user " + userId
+                            + " because package " + activePackageName
+                            + " is being restarted");
+                }
+                removeCachedServiceListLocked(userId);
+
+                if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
+                    if (debug) {
+                        Slog.d(mTag, "Eagerly recreating service for user " + userId);
+                    }
+                    updateCachedServiceLocked(userId);
+                }
+            }
+            onServicePackageRestartedLocked(userId);
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
+            synchronized (mLock) {
+                if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
+
+                if (mServiceNameResolver == null) {
+                    return;
+                }
+
+                final int userId = getChangingUserId();
+                final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList(
+                        userId);
+                if (serviceNames != null) {
+                    if (Flags.packageUpdateFixEnabled()) {
+                        if (mServiceNameResolver.isConfiguredInMultipleMode()) {
+                            // Remove any service that is in the cache but is no longer valid
+                            // after this modification for this particular package
+                            removeInvalidCachedServicesLocked(serviceNames, packageName,
+                                    userId);
+                        }
+                    }
+
+                    // Update services that are still valid
+                    for (int i = 0; i < serviceNames.length; i++) {
+                        peekAndUpdateCachedServiceLocked(packageName, userId,
+                                serviceNames[i]);
+                    }
+                }
+            }
+        }
+
+        @GuardedBy("mLock")
+        private void peekAndUpdateCachedServiceLocked(String packageName, int userId,
+                String serviceName) {
+            if (serviceName == null) {
+                return;
             }
 
-            @GuardedBy("mLock")
-            private void handlePackageUpdateLocked(String packageName) {
-                visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName));
+            final ComponentName serviceComponentName =
+                    ComponentName.unflattenFromString(serviceName);
+            if (serviceComponentName == null
+                    || !serviceComponentName.getPackageName().equals(packageName)) {
+                return;
             }
-        };
 
+            // The default service package has changed, update the cached if the service
+            // exists but no active component.
+            final S service = peekServiceForUserLocked(userId);
+            if (service != null) {
+                final ComponentName componentName = service.getServiceComponentName();
+                if (componentName == null) {
+                    if (verbose) Slog.v(mTag, "update cached");
+                    updateCachedServiceLocked(userId);
+                }
+            }
+        }
+
+        @GuardedBy("mLock")
+        private String getActiveServicePackageNameLocked() {
+            final int userId = getChangingUserId();
+            final S service = peekServiceForUserLocked(userId);
+            if (service == null) {
+                return null;
+            }
+            final ComponentName serviceComponent = service.getServiceComponentName();
+            if (serviceComponent == null) {
+                return null;
+            }
+            return serviceComponent.getPackageName();
+        }
+
+        @GuardedBy("mLock")
+        private void handlePackageUpdateLocked(String packageName) {
+            visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName));
+        }
+    }
+
+    private void startTrackingPackageChanges() {
         // package changes
-        monitor.register(getContext(), null, UserHandle.ALL, true);
+        mPackageMonitor.register(getContext(), null, UserHandle.ALL, true);
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index 600cf7f..1a4ead2 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -22,6 +22,7 @@
 import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS;
 import static com.android.server.EventLogTags.IMF_HIDE_IME;
 import static com.android.server.EventLogTags.IMF_SHOW_IME;
+import static com.android.server.inputmethod.ImeProtoLogGroup.IME_VISIBILITY_APPLIER_DEBUG;
 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;
@@ -36,7 +37,6 @@
 import android.os.IBinder;
 import android.os.ResultReceiver;
 import android.util.EventLog;
-import android.util.Slog;
 import android.view.MotionEvent;
 import android.view.inputmethod.Flags;
 import android.view.inputmethod.ImeTracker;
@@ -46,6 +46,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.protolog.ProtoLog;
 import com.android.server.LocalServices;
 import com.android.server.wm.ImeTargetVisibilityPolicy;
 import com.android.server.wm.WindowManagerInternal;
@@ -58,9 +59,7 @@
  */
 final class DefaultImeVisibilityApplier {
 
-    private static final String TAG = "DefaultImeVisibilityApplier";
-
-    private static final boolean DEBUG = InputMethodManagerService.DEBUG;
+    static final String TAG = "DefaultImeVisibilityApplier";
 
     private InputMethodManagerService mService;
 
@@ -93,11 +92,10 @@
         final var bindingController = userData.mBindingController;
         final IInputMethodInvoker curMethod = bindingController.getCurMethod();
         if (curMethod != null) {
-            if (DEBUG) {
-                Slog.v(TAG, "Calling " + curMethod + ".showSoftInput(" + showInputToken
-                        + ", " + showFlags + ", " + resultReceiver + ") for reason: "
-                        + InputMethodDebug.softInputDisplayReasonToString(reason));
-            }
+            ProtoLog.v(IME_VISIBILITY_APPLIER_DEBUG,
+                    "Calling %s.showSoftInput(%s, %s, %s) for reason: %s", curMethod,
+                    showInputToken, showFlags, resultReceiver,
+                    InputMethodDebug.softInputDisplayReasonToString(reason));
             // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
             if (curMethod.showSoftInput(showInputToken, statsToken, showFlags, resultReceiver)) {
                 if (DEBUG_IME_VISIBILITY) {
@@ -136,11 +134,9 @@
             // delivered to the IME process as an IPC.  Hence the inconsistency between
             // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
             // the final state.
-            if (DEBUG) {
-                Slog.v(TAG, "Calling " + curMethod + ".hideSoftInput(0, " + hideInputToken
-                        + ", " + resultReceiver + ") for reason: "
-                        + InputMethodDebug.softInputDisplayReasonToString(reason));
-            }
+            ProtoLog.v(IME_VISIBILITY_APPLIER_DEBUG,
+                    "Calling %s.hideSoftInput(0, %s, %s) for reason: %s", curMethod, hideInputToken,
+                    resultReceiver, InputMethodDebug.softInputDisplayReasonToString(reason));
             // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
             if (curMethod.hideSoftInput(hideInputToken, statsToken, 0, resultReceiver)) {
                 if (DEBUG_IME_VISIBILITY) {
diff --git a/services/core/java/com/android/server/inputmethod/ImeProtoLogGroup.java b/services/core/java/com/android/server/inputmethod/ImeProtoLogGroup.java
index f9a56ef..ea4e295 100644
--- a/services/core/java/com/android/server/inputmethod/ImeProtoLogGroup.java
+++ b/services/core/java/com/android/server/inputmethod/ImeProtoLogGroup.java
@@ -23,7 +23,11 @@
 public enum ImeProtoLogGroup implements IProtoLogGroup {
     // TODO(b/393561240): add info/warn/error log level and replace in IMMS
     IMMS_DEBUG(Consts.ENABLE_DEBUG, false, false,
-            InputMethodManagerService.TAG);
+            InputMethodManagerService.TAG),
+    IME_VISIBILITY_APPLIER_DEBUG(Consts.ENABLE_DEBUG, false, false,
+            DefaultImeVisibilityApplier.TAG),
+    IME_VIS_STATE_COMPUTER_DEBUG(Consts.ENABLE_DEBUG, false, false,
+            ImeVisibilityStateComputer.TAG);
 
     private final boolean mEnabled;
     private volatile boolean mLogToProto;
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index 5fe8318..69353be 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -32,6 +32,7 @@
 import static com.android.internal.inputmethod.InputMethodDebug.softInputModeToString;
 import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS;
 import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS;
+import static com.android.server.inputmethod.ImeProtoLogGroup.IME_VIS_STATE_COMPUTER_DEBUG;
 import static com.android.server.inputmethod.InputMethodManagerService.computeImeDisplayIdForTarget;
 
 import android.accessibilityservice.AccessibilityService;
@@ -58,6 +59,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.protolog.ProtoLog;
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
@@ -72,9 +74,7 @@
  */
 public final class ImeVisibilityStateComputer {
 
-    private static final String TAG = "ImeVisibilityStateComputer";
-
-    private static final boolean DEBUG = InputMethodManagerService.DEBUG;
+    static final String TAG = "ImeVisibilityStateComputer";
 
     @UserIdInt
     private final int mUserId;
@@ -292,12 +292,14 @@
             @InputMethodManager.HideFlags int hideFlags) {
         if ((hideFlags & InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
                 && (mRequestedShowExplicitly || mShowForced)) {
-            if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
+            ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
+                    "Not hiding: explicit show not cancelled by non-explicit hide");
             ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
             return false;
         }
         if (mShowForced && (hideFlags & InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
-            if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
+            ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
+                    "Not hiding: forced show not cancelled by not-always hide");
             ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
             return false;
         }
@@ -417,8 +419,8 @@
 
     @GuardedBy("ImfLock.class")
     private void setWindowStateInner(IBinder windowToken, @NonNull ImeTargetWindowState newState) {
-        if (DEBUG) Slog.d(TAG, "setWindowStateInner, windowToken=" + windowToken
-                + ", state=" + newState);
+        ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "setWindowStateInner, windowToken=%s, state=%s",
+                windowToken, newState);
         mRequestWindowStateMap.put(windowToken, newState);
     }
 
@@ -466,7 +468,7 @@
         // Because the app might leverage these flags to hide soft-keyboard with showing their own
         // UI for input.
         if (state.hasEditorFocused() && shouldRestoreImeVisibility(state)) {
-            if (DEBUG) Slog.v(TAG, "Will show input to restore visibility");
+            ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "Will show input to restore visibility");
             // Inherit the last requested IME visible state when the target window is still
             // focused with an editor.
             state.setRequestedImeVisible(true);
@@ -483,7 +485,8 @@
                         // There is no focus view, and this window will
                         // be behind any soft input window, so hide the
                         // soft input window if it is shown.
-                        if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
+                        ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
+                                "Unspecified window will hide input");
                         return new ImeVisibilityResult(STATE_HIDE_IME_NOT_ALWAYS,
                                 SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW);
                     }
@@ -495,7 +498,7 @@
                     // them good context without input information being obscured
                     // by the IME) or if running on a large screen where there
                     // is more room for the target window + IME.
-                    if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
+                    ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "Unspecified window will show input");
                     return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
                             SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV);
                 }
@@ -513,7 +516,8 @@
                     // the WindowState, as they're already in the correct state
                     break;
                 } else if (isForwardNavigation) {
-                    if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
+                    ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
+                            "Window asks to hide input going forward");
                     return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
                             SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV);
                 }
@@ -524,7 +528,7 @@
                     // the WindowState, as they're already in the correct state
                     break;
                 } else if (state.hasImeFocusChanged()) {
-                    if (DEBUG) Slog.v(TAG, "Window asks to hide input");
+                    ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "Window asks to hide input");
                     return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
                             SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
                 }
@@ -532,7 +536,8 @@
             case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
                 if (isForwardNavigation) {
                     if (allowVisible) {
-                        if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
+                        ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
+                                "Window asks to show input going forward");
                         return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
                                 SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV);
                     } else {
@@ -543,7 +548,7 @@
                 }
                 break;
             case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
-                if (DEBUG) Slog.v(TAG, "Window asks to always show input");
+                ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "Window asks to always show input");
                 if (allowVisible) {
                     if (state.hasImeFocusChanged()) {
                         return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
@@ -565,7 +570,8 @@
             // To maintain compatibility, we are now hiding the IME when we don't have
             // an editor upon refocusing a window.
             if (state.isStartInputByGainFocus()) {
-                if (DEBUG) Slog.v(TAG, "Same window without editor will hide input");
+                ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
+                        "Same window without editor will hide input");
                 return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
                         SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
             }
@@ -579,7 +585,7 @@
             // 1) SOFT_INPUT_STATE_UNCHANGED state without an editor
             // 2) SOFT_INPUT_STATE_VISIBLE state without an editor
             // 3) SOFT_INPUT_STATE_ALWAYS_VISIBLE state without an editor
-            if (DEBUG) Slog.v(TAG, "Window without editor will hide input");
+            ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "Window without editor will hide input");
             if (Flags.refactorInsetsController()) {
                 state.setRequestedImeVisible(false);
             }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index af726bd..68ad8f7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2902,12 +2902,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             if (windowPerceptible != null && !windowPerceptible) {
-                if ((vis & InputMethodService.IME_VISIBLE) != 0) {
-                    vis &= ~InputMethodService.IME_VISIBLE;
-                    vis |= InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
-                }
-            } else {
-                vis &= ~InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
+                vis &= ~InputMethodService.IME_VISIBLE;
             }
             final var curId = bindingController.getCurId();
             // TODO(b/305849394): Make mMenuController multi-user aware.
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a0e5433..42d0a5c 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -3618,6 +3618,12 @@
             return;
         }
 
+        UserInfo userInfo = mInjector.getUserManagerInternal().getUserInfo(userId);
+        if (userInfo != null && userInfo.isForTesting()) {
+            Slog.i(TAG, "Keeping escrow data for test-only user");
+            return;
+        }
+
         // Disable escrow token permanently on all other device/user types.
         Slogf.i(TAG, "Permanently disabling support for escrow tokens on user %d", userId);
         mSpManager.destroyEscrowData(userId);
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index debac94..f137de1 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -25,8 +25,20 @@
 import static android.media.MediaRouter2.SCANNING_STATE_WHILE_INTERACTIVE;
 import static android.media.MediaRouter2Utils.getOriginalId;
 import static android.media.MediaRouter2Utils.getProviderId;
-
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_RELEASE_SESSION;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SELECT_ROUTE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_TRANSFER_TO_ROUTE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_ROUTE_ID;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_SESSION_ID;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_MANAGER_RECORD_NOT_FOUND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_PERMISSION_DENIED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -64,14 +76,12 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.media.flags.Flags;
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
-
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -130,9 +140,14 @@
     private final ArrayMap<IBinder, RouterRecord> mAllRouterRecords = new ArrayMap<>();
     @GuardedBy("mLock")
     private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
+
     @GuardedBy("mLock")
     private int mCurrentActiveUserId = -1;
 
+    @GuardedBy("mLock")
+    private static final MediaRouterMetricLogger mMediaRouterMetricLogger =
+            new MediaRouterMetricLogger();
+
     private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
             (uid, importance) -> {
                 synchronized (mLock) {
@@ -350,8 +365,8 @@
         }
     }
 
-    public void setDiscoveryRequestWithRouter2(@NonNull IMediaRouter2 router,
-            @NonNull RouteDiscoveryPreference preference) {
+    public void setDiscoveryRequestWithRouter2(
+            @NonNull IMediaRouter2 router, @NonNull RouteDiscoveryPreference preference) {
         Objects.requireNonNull(router, "router must not be null");
         Objects.requireNonNull(preference, "preference must not be null");
 
@@ -409,8 +424,8 @@
         }
     }
 
-    public void setRouteVolumeWithRouter2(@NonNull IMediaRouter2 router,
-            @NonNull MediaRoute2Info route, int volume) {
+    public void setRouteVolumeWithRouter2(
+            @NonNull IMediaRouter2 router, @NonNull MediaRoute2Info route, int volume) {
         Objects.requireNonNull(router, "router must not be null");
         Objects.requireNonNull(route, "route must not be null");
 
@@ -439,12 +454,7 @@
         try {
             synchronized (mLock) {
                 requestCreateSessionWithRouter2Locked(
-                        requestId,
-                        managerRequestId,
-                        router,
-                        oldSession,
-                        route,
-                        sessionHints);
+                        requestId, managerRequestId, router, oldSession, route, sessionHints);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -1326,6 +1336,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1344,15 +1357,22 @@
         if (managerRequestId != MediaRoute2ProviderService.REQUEST_ID_NONE) {
             ManagerRecord manager = userHandler.findManagerWithId(toRequesterId(managerRequestId));
             if (manager == null || manager.mLastSessionCreationRequest == null) {
-                Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
-                        + "Ignoring unknown request.");
+                Slog.w(TAG, "requestCreateSessionWithRouter2Locked: Ignoring unknown request.");
+                mMediaRouterMetricLogger.logOperationFailure(
+                        MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_MANAGER_RECORD_NOT_FOUND);
                 routerRecord.notifySessionCreationFailed(requestId);
                 return;
             }
-            if (!TextUtils.equals(manager.mLastSessionCreationRequest.mOldSession.getId(),
-                    oldSession.getId())) {
-                Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
-                        + "Ignoring unmatched routing session.");
+            if (!TextUtils.equals(
+                    manager.mLastSessionCreationRequest.mOldSession.getId(), oldSession.getId())) {
+                Slog.w(
+                        TAG,
+                        "requestCreateSessionWithRouter2Locked: "
+                                + "Ignoring unmatched routing session.");
+                mMediaRouterMetricLogger.logOperationFailure(
+                        MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_SESSION_ID);
                 routerRecord.notifySessionCreationFailed(requestId);
                 return;
             }
@@ -1364,8 +1384,13 @@
                         && route.isSystemRoute()) {
                     route = manager.mLastSessionCreationRequest.mRoute;
                 } else {
-                    Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
-                            + "Ignoring unmatched route.");
+                    Slog.w(
+                            TAG,
+                            "requestCreateSessionWithRouter2Locked: "
+                                    + "Ignoring unmatched route.");
+                    mMediaRouterMetricLogger.logOperationFailure(
+                            MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                            MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_ROUTE_ID);
                     routerRecord.notifySessionCreationFailed(requestId);
                     return;
                 }
@@ -1376,14 +1401,19 @@
             if (route.isSystemRoute()
                     && !routerRecord.hasSystemRoutingPermission()
                     && !TextUtils.equals(route.getId(), defaultRouteId)) {
-                Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
-                        + route);
+                Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to" + route);
+                mMediaRouterMetricLogger.logOperationFailure(
+                        MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_PERMISSION_DENIED);
                 routerRecord.notifySessionCreationFailed(requestId);
                 return;
             }
         }
 
         long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
+        mMediaRouterMetricLogger.addRequestInfo(
+                uniqueRequestId,
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION);
         userHandler.sendMessage(
                 obtainMessage(
                         UserHandler::requestCreateSessionWithRouter2OnHandler,
@@ -1403,6 +1433,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SELECT_ROUTE,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1411,6 +1444,9 @@
                 TextUtils.formatSimple(
                         "selectRouteWithRouter2 | router: %s(id: %d), route: %s",
                         routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
+        mMediaRouterMetricLogger.logOperationTriggered(
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SELECT_ROUTE,
+                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::selectRouteOnHandler,
@@ -1425,6 +1461,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1433,6 +1472,9 @@
                 TextUtils.formatSimple(
                         "deselectRouteWithRouter2 | router: %s(id: %d), route: %s",
                         routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
+        mMediaRouterMetricLogger.logOperationTriggered(
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE,
+                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::deselectRouteOnHandler,
@@ -1450,6 +1492,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_TRANSFER_TO_ROUTE,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1458,6 +1503,9 @@
                 TextUtils.formatSimple(
                         "transferToRouteWithRouter2 | router: %s(id: %d), route: %s",
                         routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
+        mMediaRouterMetricLogger.logOperationTriggered(
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_TRANSFER_TO_ROUTE,
+                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
 
         UserHandler userHandler = routerRecord.mUserRecord.mHandler;
         String defaultRouteId = userHandler.getSystemProvider().getDefaultRoute().getId();
@@ -1516,6 +1564,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_RELEASE_SESSION,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1794,6 +1845,9 @@
                 .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
+        mMediaRouterMetricLogger.addRequestInfo(
+                uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SELECT_ROUTE);
+
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::selectRouteOnHandler,
                         managerRecord.mUserRecord.mHandler,
@@ -1820,6 +1874,10 @@
                 .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
+        mMediaRouterMetricLogger.addRequestInfo(
+                uniqueRequestId,
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE);
+
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::deselectRouteOnHandler,
                         managerRecord.mUserRecord.mHandler,
@@ -1851,6 +1909,10 @@
                 .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
+        mMediaRouterMetricLogger.addRequestInfo(
+                uniqueRequestId,
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_TRANSFER_TO_ROUTE);
+
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(
                         UserHandler::transferToRouteOnHandler,
@@ -2792,7 +2854,8 @@
 
             if (!addedRoutes.isEmpty()) {
                 // If routes were added, newInfo cannot be null.
-                Slog.i(TAG,
+                Slog.i(
+                        TAG,
                         toLoggingMessage(
                                 /* source= */ "addProviderRoutes",
                                 newInfo.getUniqueId(),
@@ -2954,7 +3017,7 @@
         private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
                 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
-                    "selecting")) {
+                    "selecting", uniqueRequestId)) {
                 return;
             }
 
@@ -2963,8 +3026,12 @@
             if (provider == null) {
                 return;
             }
-            provider.selectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
-                    route.getOriginalId());
+            provider.selectRoute(
+                    uniqueRequestId, getOriginalId(uniqueSessionId), route.getOriginalId());
+
+            // Log the success result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
         }
 
         // routerRecord can be null if the session is system's or RCN.
@@ -2972,7 +3039,7 @@
                 @Nullable RouterRecord routerRecord,
                 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
-                    "deselecting")) {
+                    "deselecting", uniqueRequestId)) {
                 return;
             }
 
@@ -2982,8 +3049,12 @@
                 return;
             }
 
-            provider.deselectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
-                    route.getOriginalId());
+            provider.deselectRoute(
+                    uniqueRequestId, getOriginalId(uniqueSessionId), route.getOriginalId());
+
+            // Log the success result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
         }
 
         // routerRecord can be null if the session is system's or RCN.
@@ -2996,7 +3067,7 @@
                 @NonNull MediaRoute2Info route,
                 @RoutingSessionInfo.TransferReason int transferReason) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
-                    "transferring to")) {
+                    "transferring to", uniqueRequestId)) {
                 return;
             }
 
@@ -3016,18 +3087,25 @@
                     getOriginalId(uniqueSessionId),
                     route.getOriginalId(),
                     transferReason);
+
+            // Log the success result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
         }
 
         // routerRecord is null if and only if the session is created without the request, which
         // includes the system's session and RCN cases.
         private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord,
                 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route,
-                @NonNull String description) {
+                @NonNull String description, long uniqueRequestId) {
             final String providerId = route.getProviderId();
             final MediaRoute2Provider provider = findProvider(providerId);
             if (provider == null) {
                 Slog.w(TAG, "Ignoring " + description + " route since no provider found for "
                         + "given route=" + route);
+                mMediaRouterMetricLogger.logRequestResult(
+                        uniqueRequestId,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND);
                 return false;
             }
 
@@ -3050,6 +3128,9 @@
                                 + getPackageNameFromNullableRecord(matchingRecord)
                                 + " route="
                                 + route);
+                mMediaRouterMetricLogger.logRequestResult(
+                        uniqueRequestId,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
                 return false;
             }
 
@@ -3057,6 +3138,9 @@
             if (sessionId == null) {
                 Slog.w(TAG, "Failed to get original session id from unique session id. "
                         + "uniqueSessionId=" + uniqueSessionId);
+                mMediaRouterMetricLogger.logRequestResult(
+                        uniqueRequestId,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_SESSION_ID);
                 return false;
             }
 
@@ -3168,6 +3252,10 @@
             }
             matchingRequest.mRouterRecord.notifySessionCreated(
                     toOriginalRequestId(uniqueRequestId), sessionInfo);
+
+            // Log the success result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
         }
 
         /**
@@ -3255,10 +3343,14 @@
 
             // Currently, only manager records can get notified of failures.
             // TODO(b/282936553): Notify regular routers of request failures.
+
+            // Log the request result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MediaRouterMetricLogger.convertResultFromReason(reason));
         }
 
-        private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
-                long uniqueRequestId, int reason) {
+        private boolean handleSessionCreationRequestFailed(
+                @NonNull MediaRoute2Provider provider, long uniqueRequestId, int reason) {
             // Check whether the failure is about creating a session
             SessionCreationRequest matchingRequest = null;
             for (SessionCreationRequest request : mSessionCreationRequests) {
@@ -3385,8 +3477,8 @@
             }
         }
 
-        private void notifySessionCreatedToManagers(long managerRequestId,
-                @NonNull RoutingSessionInfo session) {
+        private void notifySessionCreatedToManagers(
+                long managerRequestId, @NonNull RoutingSessionInfo session) {
             int requesterId = toRequesterId(managerRequestId);
             int originalRequestId = toOriginalRequestId(managerRequestId);
 
diff --git a/services/core/java/com/android/server/media/MediaRouterMetricLogger.java b/services/core/java/com/android/server/media/MediaRouterMetricLogger.java
new file mode 100644
index 0000000..56d2a1b
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaRouterMetricLogger.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
+
+import android.annotation.NonNull;
+import android.media.MediaRoute2ProviderService;
+import android.util.Log;
+import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+import java.io.PrintWriter;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Logs metrics for MediaRouter2.
+ *
+ * @hide
+ */
+final class MediaRouterMetricLogger {
+    private static final String TAG = "MediaRouterMetricLogger";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final int REQUEST_INFO_CACHE_CAPACITY = 100;
+
+    /** LRU cache to store request info. */
+    private final RequestInfoCache mRequestInfoCache;
+
+    /** Constructor for {@link MediaRouterMetricLogger}. */
+    public MediaRouterMetricLogger() {
+        mRequestInfoCache = new RequestInfoCache(REQUEST_INFO_CACHE_CAPACITY);
+    }
+
+    /**
+     * Adds a new request info to the cache.
+     *
+     * @param uniqueRequestId The unique request id.
+     * @param eventType The event type.
+     */
+    public void addRequestInfo(long uniqueRequestId, int eventType) {
+        RequestInfo requestInfo = new RequestInfo(uniqueRequestId, eventType);
+        mRequestInfoCache.put(requestInfo.mUniqueRequestId, requestInfo);
+    }
+
+    /**
+     * Removes a request info from the cache.
+     *
+     * @param uniqueRequestId The unique request id.
+     */
+    public void removeRequestInfo(long uniqueRequestId) {
+        mRequestInfoCache.remove(uniqueRequestId);
+    }
+
+    /**
+     * Logs an operation failure.
+     *
+     * @param eventType The event type.
+     * @param result The result of the operation.
+     */
+    public void logOperationFailure(int eventType, int result) {
+        logMediaRouterEvent(eventType, result);
+    }
+
+    /**
+     * Logs an operation triggered.
+     *
+     * @param eventType The event type.
+     */
+    public void logOperationTriggered(int eventType, int result) {
+        logMediaRouterEvent(eventType, result);
+    }
+
+    /**
+     * Logs the result of a request.
+     *
+     * @param uniqueRequestId The unique request id.
+     * @param result The result of the request.
+     */
+    public void logRequestResult(long uniqueRequestId, int result) {
+        RequestInfo requestInfo = mRequestInfoCache.get(uniqueRequestId);
+        if (requestInfo == null) {
+            Slog.w(
+                    TAG,
+                    "logRequestResult: No RequestInfo found for uniqueRequestId="
+                            + uniqueRequestId);
+            return;
+        }
+
+        int eventType = requestInfo.mEventType;
+        logMediaRouterEvent(eventType, result);
+
+        removeRequestInfo(uniqueRequestId);
+    }
+
+    /**
+     * Converts a reason code from {@link MediaRoute2ProviderService} to a result code for logging.
+     *
+     * @param reason The reason code from {@link MediaRoute2ProviderService}.
+     * @return The result code for logging.
+     */
+    public static int convertResultFromReason(int reason) {
+        switch (reason) {
+            case MediaRoute2ProviderService.REASON_UNKNOWN_ERROR:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
+            case MediaRoute2ProviderService.REASON_REJECTED:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
+            case MediaRoute2ProviderService.REASON_NETWORK_ERROR:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
+            case MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE;
+            case MediaRoute2ProviderService.REASON_INVALID_COMMAND:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
+            case MediaRoute2ProviderService.REASON_UNIMPLEMENTED:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
+            case MediaRoute2ProviderService.REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
+            default:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
+        }
+    }
+
+    /**
+     * Gets the size of the request info cache.
+     *
+     * @return The size of the request info cache.
+     */
+    @VisibleForTesting
+    public int getRequestCacheSize() {
+        return mRequestInfoCache.size();
+    }
+
+    private void logMediaRouterEvent(int eventType, int result) {
+        MediaRouterStatsLog.write(
+                MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED, eventType, result);
+
+        if (DEBUG) {
+            Slog.d(TAG, "logMediaRouterEvent: " + eventType + " " + result);
+        }
+    }
+
+    /** A cache for storing request info that evicts entries when it reaches its capacity. */
+    class RequestInfoCache extends LinkedHashMap<Long, RequestInfo> {
+
+        public final int capacity;
+
+        /**
+         * Constructor for {@link RequestInfoCache}.
+         *
+         * @param capacity The maximum capacity of the cache.
+         */
+        public RequestInfoCache(int capacity) {
+            super(capacity, 1.0f, true);
+            this.capacity = capacity;
+        }
+
+        @Override
+        protected boolean removeEldestEntry(Map.Entry<Long, RequestInfo> eldest) {
+            boolean shouldRemove = size() > capacity;
+            if (shouldRemove) {
+                Slog.d(TAG, "Evicted request info: " + eldest.getValue());
+                logOperationTriggered(
+                        eldest.getValue().mEventType,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
+            }
+            return shouldRemove;
+        }
+    }
+
+    /** Class to store request info. */
+    static class RequestInfo {
+        public final long mUniqueRequestId;
+        public final int mEventType;
+
+        /**
+         * Constructor for {@link RequestInfo}.
+         *
+         * @param uniqueRequestId The unique request id.
+         * @param eventType The event type.
+         */
+        RequestInfo(long uniqueRequestId, int eventType) {
+            mUniqueRequestId = uniqueRequestId;
+            mEventType = eventType;
+        }
+
+        /**
+         * Dumps the request info.
+         *
+         * @param pw The print writer.
+         * @param prefix The prefix for the output.
+         */
+        public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+            pw.println(prefix + "RequestInfo");
+            String indent = prefix + "  ";
+            pw.println(indent + "mUniqueRequestId=" + mUniqueRequestId);
+            pw.println(indent + "mEventType=" + mEventType);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 91a2843..9e38435 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -48,7 +48,6 @@
 import android.media.quality.IPictureProfileCallback;
 import android.media.quality.ISoundProfileCallback;
 import android.media.quality.MediaQualityContract.BaseParameters;
-import android.media.quality.MediaQualityManager;
 import android.media.quality.ParameterCapability;
 import android.media.quality.PictureProfile;
 import android.media.quality.PictureProfileHandle;
@@ -187,7 +186,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public PictureProfile createPictureProfile(PictureProfile pp, UserHandle user) {
+        public PictureProfile createPictureProfile(PictureProfile pp, int userId) {
             if ((pp.getPackageName() != null && !pp.getPackageName().isEmpty()
                     && !incomingPackageEqualsCallingUidPackage(pp.getPackageName()))
                     && !hasGlobalPictureQualityServicePermission()) {
@@ -221,7 +220,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public void updatePictureProfile(String id, PictureProfile pp, UserHandle user) {
+        public void updatePictureProfile(String id, PictureProfile pp, int userId) {
             Long dbId = mPictureProfileTempIdMap.getKey(id);
             if (!hasPermissionToUpdatePictureProfile(dbId, pp)) {
                 mMqManagerNotifier.notifyOnPictureProfileError(id,
@@ -249,7 +248,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public void removePictureProfile(String id, UserHandle user) {
+        public void removePictureProfile(String id, int userId) {
             synchronized (mPictureProfileLock) {
                 Long dbId = mPictureProfileTempIdMap.getKey(id);
 
@@ -290,10 +289,8 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public PictureProfile getPictureProfile(int type, String name, Bundle options,
-                UserHandle user) {
-            boolean includeParams =
-                    options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false);
+        public PictureProfile getPictureProfile(int type, String name, boolean includeParams,
+                int userId) {
             String selection = BaseParameters.PARAMETER_TYPE + " = ? AND "
                     + BaseParameters.PARAMETER_NAME + " = ? AND "
                     + BaseParameters.PARAMETER_PACKAGE + " = ?";
@@ -327,7 +324,7 @@
         @GuardedBy("mPictureProfileLock")
         @Override
         public List<PictureProfile> getPictureProfilesByPackage(
-                String packageName, Bundle options, UserHandle user) {
+                String packageName, boolean includeParams, int userId) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnPictureProfileError(null,
                         PictureProfile.ERROR_NO_PERMISSION,
@@ -335,8 +332,6 @@
             }
 
             synchronized (mPictureProfileLock) {
-                boolean includeParams =
-                        options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false);
                 String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
                 String[] selectionArguments = {packageName};
                 return mMqDatabaseUtils.getPictureProfilesBasedOnConditions(MediaQualityUtils
@@ -347,17 +342,17 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public List<PictureProfile> getAvailablePictureProfiles(Bundle options, UserHandle user) {
+        public List<PictureProfile> getAvailablePictureProfiles(boolean includeParams, int userId) {
             String packageName = getPackageOfCallingUid();
             if (packageName != null) {
-                return getPictureProfilesByPackage(packageName, options, user);
+                return getPictureProfilesByPackage(packageName, includeParams, userId);
             }
             return new ArrayList<>();
         }
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public boolean setDefaultPictureProfile(String profileId, UserHandle user) {
+        public boolean setDefaultPictureProfile(String profileId, int userId) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnPictureProfileError(profileId,
                         PictureProfile.ERROR_NO_PERMISSION,
@@ -387,7 +382,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public List<String> getPictureProfilePackageNames(UserHandle user) {
+        public List<String> getPictureProfilePackageNames(int userId) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnPictureProfileError(null,
                         PictureProfile.ERROR_NO_PERMISSION,
@@ -406,7 +401,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public List<PictureProfileHandle> getPictureProfileHandle(String[] ids, UserHandle user) {
+        public List<PictureProfileHandle> getPictureProfileHandle(String[] ids, int userId) {
             List<PictureProfileHandle> toReturn = new ArrayList<>();
             synchronized (mPictureProfileLock) {
                 for (String id : ids) {
@@ -423,13 +418,13 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public List<SoundProfileHandle> getSoundProfileHandle(String[] ids, UserHandle user) {
+        public List<SoundProfileHandle> getSoundProfileHandle(String[] ids, int userId) {
             List<SoundProfileHandle> toReturn = new ArrayList<>();
             synchronized (mSoundProfileLock) {
                 for (String id : ids) {
                     Long key = mSoundProfileTempIdMap.getKey(id);
                     if (key != null) {
-                        toReturn.add(new SoundProfileHandle(key));
+                        toReturn.add(MediaQualityUtils.SOUND_PROFILE_HANDLE_NONE);
                     } else {
                         toReturn.add(null);
                     }
@@ -440,7 +435,7 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public SoundProfile createSoundProfile(SoundProfile sp, UserHandle user) {
+        public SoundProfile createSoundProfile(SoundProfile sp, int userId) {
             if ((sp.getPackageName() != null && !sp.getPackageName().isEmpty()
                     && !incomingPackageEqualsCallingUidPackage(sp.getPackageName()))
                     && !hasGlobalPictureQualityServicePermission()) {
@@ -473,7 +468,7 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public void updateSoundProfile(String id, SoundProfile sp, UserHandle user) {
+        public void updateSoundProfile(String id, SoundProfile sp, int userId) {
             Long dbId = mSoundProfileTempIdMap.getKey(id);
             if (!hasPermissionToUpdateSoundProfile(dbId, sp)) {
                 mMqManagerNotifier.notifyOnSoundProfileError(id, SoundProfile.ERROR_NO_PERMISSION,
@@ -502,7 +497,7 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public void removeSoundProfile(String id, UserHandle user) {
+        public void removeSoundProfile(String id, int userId) {
             synchronized (mSoundProfileLock) {
                 Long dbId = mSoundProfileTempIdMap.getKey(id);
                 SoundProfile toDelete = mMqDatabaseUtils.getSoundProfile(dbId);
@@ -542,10 +537,8 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public SoundProfile getSoundProfile(int type, String name, Bundle options,
-                UserHandle user) {
-            boolean includeParams =
-                    options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false);
+        public SoundProfile getSoundProfile(int type, String name, boolean includeParams,
+                int userId) {
             String selection = BaseParameters.PARAMETER_TYPE + " = ? AND "
                     + BaseParameters.PARAMETER_NAME + " = ? AND "
                     + BaseParameters.PARAMETER_PACKAGE + " = ?";
@@ -579,15 +572,13 @@
         @GuardedBy("mSoundProfileLock")
         @Override
         public List<SoundProfile> getSoundProfilesByPackage(
-                String packageName, Bundle options, UserHandle user) {
+                String packageName, boolean includeParams, int userId) {
             if (!hasGlobalSoundQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
 
             synchronized (mSoundProfileLock) {
-                boolean includeParams =
-                        options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false);
                 String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
                 String[] selectionArguments = {packageName};
                 return mMqDatabaseUtils.getSoundProfilesBasedOnConditions(MediaQualityUtils
@@ -598,17 +589,17 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public List<SoundProfile> getAvailableSoundProfiles(Bundle options, UserHandle user) {
+        public List<SoundProfile> getAvailableSoundProfiles(boolean includeParams, int userId) {
             String packageName = getPackageOfCallingUid();
             if (packageName != null) {
-                return getSoundProfilesByPackage(packageName, options, user);
+                return getSoundProfilesByPackage(packageName, includeParams, userId);
             }
             return new ArrayList<>();
         }
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public boolean setDefaultSoundProfile(String profileId, UserHandle user) {
+        public boolean setDefaultSoundProfile(String profileId, int userId) {
             if (!hasGlobalSoundQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnSoundProfileError(profileId,
                         SoundProfile.ERROR_NO_PERMISSION,
@@ -638,7 +629,7 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public List<String> getSoundProfilePackageNames(UserHandle user) {
+        public List<String> getSoundProfilePackageNames(int userId) {
             if (!hasGlobalSoundQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
                         Binder.getCallingUid(), Binder.getCallingPid());
@@ -737,7 +728,7 @@
         @GuardedBy("mAmbientBacklightLock")
         @Override
         public void setAmbientBacklightSettings(
-                AmbientBacklightSettings settings, UserHandle user) {
+                AmbientBacklightSettings settings, int userId) {
             if (DEBUG) {
                 Slogf.d(TAG, "setAmbientBacklightSettings " + settings);
             }
@@ -775,7 +766,7 @@
 
         @GuardedBy("mAmbientBacklightLock")
         @Override
-        public void setAmbientBacklightEnabled(boolean enabled, UserHandle user) {
+        public void setAmbientBacklightEnabled(boolean enabled, int userId) {
             if (DEBUG) {
                 Slogf.d(TAG, "setAmbientBacklightEnabled " + enabled);
             }
@@ -795,7 +786,7 @@
 
         @Override
         public List<ParameterCapability> getParameterCapabilities(
-                List<String> names, UserHandle user) {
+                List<String> names, int userId) {
             byte[] byteArray = MediaQualityUtils.convertParameterToByteArray(names);
             ParamCapability[] caps = new ParamCapability[byteArray.length];
             try {
@@ -828,7 +819,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public List<String> getPictureProfileAllowList(UserHandle user) {
+        public List<String> getPictureProfileAllowList(int userId) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnPictureProfileError(null,
                         PictureProfile.ERROR_NO_PERMISSION,
@@ -844,7 +835,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public void setPictureProfileAllowList(List<String> packages, UserHandle user) {
+        public void setPictureProfileAllowList(List<String> packages, int userId) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnPictureProfileError(null,
                         PictureProfile.ERROR_NO_PERMISSION,
@@ -857,7 +848,7 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public List<String> getSoundProfileAllowList(UserHandle user) {
+        public List<String> getSoundProfileAllowList(int userId) {
             if (!hasGlobalSoundQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
                         Binder.getCallingUid(), Binder.getCallingPid());
@@ -872,7 +863,7 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public void setSoundProfileAllowList(List<String> packages, UserHandle user) {
+        public void setSoundProfileAllowList(List<String> packages, int userId) {
             if (!hasGlobalSoundQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
                         Binder.getCallingUid(), Binder.getCallingPid());
@@ -883,13 +874,13 @@
         }
 
         @Override
-        public boolean isSupported(UserHandle user) {
+        public boolean isSupported(int userId) {
             return false;
         }
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public void setAutoPictureQualityEnabled(boolean enabled, UserHandle user) {
+        public void setAutoPictureQualityEnabled(boolean enabled, int userId) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnPictureProfileError(null,
                         PictureProfile.ERROR_NO_PERMISSION,
@@ -910,7 +901,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public boolean isAutoPictureQualityEnabled(UserHandle user) {
+        public boolean isAutoPictureQualityEnabled(int userId) {
             synchronized (mPictureProfileLock) {
                 try {
                     if (mMediaQuality != null) {
@@ -927,7 +918,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public void setSuperResolutionEnabled(boolean enabled, UserHandle user) {
+        public void setSuperResolutionEnabled(boolean enabled, int userId) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnPictureProfileError(null,
                         PictureProfile.ERROR_NO_PERMISSION,
@@ -948,7 +939,7 @@
 
         @GuardedBy("mPictureProfileLock")
         @Override
-        public boolean isSuperResolutionEnabled(UserHandle user) {
+        public boolean isSuperResolutionEnabled(int userId) {
             synchronized (mPictureProfileLock) {
                 try {
                     if (mMediaQuality != null) {
@@ -965,7 +956,7 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public void setAutoSoundQualityEnabled(boolean enabled, UserHandle user) {
+        public void setAutoSoundQualityEnabled(boolean enabled, int userId) {
             if (!hasGlobalSoundQualityServicePermission()) {
                 mMqManagerNotifier.notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
                         Binder.getCallingUid(), Binder.getCallingPid());
@@ -986,7 +977,7 @@
 
         @GuardedBy("mSoundProfileLock")
         @Override
-        public boolean isAutoSoundQualityEnabled(UserHandle user) {
+        public boolean isAutoSoundQualityEnabled(int userId) {
             synchronized (mSoundProfileLock) {
                 try {
                     if (mMediaQuality != null) {
@@ -1003,7 +994,7 @@
 
         @GuardedBy("mAmbientBacklightLock")
         @Override
-        public boolean isAmbientBacklightEnabled(UserHandle user) {
+        public boolean isAmbientBacklightEnabled(int userId) {
             return false;
         }
     }
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityUtils.java b/services/core/java/com/android/server/media/quality/MediaQualityUtils.java
index 88d3f1f..303c967 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityUtils.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityUtils.java
@@ -60,6 +60,11 @@
     private static final String TAG = "MediaQualityUtils";
     public static final String SETTINGS = "settings";
 
+    public static final SoundProfileHandle SOUND_PROFILE_HANDLE_NONE = new SoundProfileHandle();
+    static {
+        SOUND_PROFILE_HANDLE_NONE.id = -10000;
+    }
+
     /**
      * Convert PictureParameter List to PersistableBundle.
      */
@@ -1022,7 +1027,7 @@
                 getInputId(cursor),
                 getPackageName(cursor),
                 jsonToPersistableBundle(getSettingsString(cursor)),
-                SoundProfileHandle.NONE
+                SOUND_PROFILE_HANDLE_NONE
         );
     }
 
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 6e5308e..3f4df1d 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -1002,8 +1002,7 @@
     private FullyQualifiedGroupKey getSectionGroupKeyWithFallback(final NotificationRecord record) {
         final NotificationSectioner sectioner = getSection(record);
         if (sectioner != null) {
-            return new FullyQualifiedGroupKey(record.getUserId(), record.getSbn().getPackageName(),
-                sectioner);
+            return FullyQualifiedGroupKey.forRecord(record, sectioner);
         } else {
             return getPreviousValidSectionKey(record);
         }
@@ -1105,6 +1104,49 @@
         }
     }
 
+    /**
+     * Called when a group summary is posted. If there are any ungrouped notifications that are
+     * in that group, remove them as they are no longer candidates for autogrouping.
+     *
+     * @param summaryRecord the NotificationRecord for the newly posted group summary
+     * @param notificationList the full notification list from NotificationManagerService
+     */
+    @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING)
+    protected void onGroupSummaryAdded(final NotificationRecord summaryRecord,
+            final List<NotificationRecord> notificationList) {
+        String groupKey = summaryRecord.getSbn().getGroup();
+        synchronized (mAggregatedNotifications) {
+            final NotificationSectioner sectioner = getSection(summaryRecord);
+            if (sectioner == null) {
+                Slog.w(TAG, "onGroupSummaryAdded " + summaryRecord + ": no valid section found");
+                return;
+            }
+
+            FullyQualifiedGroupKey aggregateGroupKey = FullyQualifiedGroupKey.forRecord(
+                    summaryRecord, sectioner);
+            ArrayMap<String, NotificationAttributes> ungrouped =
+                    mUngroupedAbuseNotifications.getOrDefault(aggregateGroupKey,
+                            new ArrayMap<>());
+            if (ungrouped.isEmpty()) {
+                // don't bother looking through the notification list if there are no pending
+                // ungrouped notifications in this section (likely to be the most common case)
+                return;
+            }
+
+            // Look through full notification list for any notifications belonging to this group;
+            // remove from ungrouped map if needed, as the presence of the summary means they will
+            // now be grouped
+            for (NotificationRecord r : notificationList) {
+                if (!r.getNotification().isGroupSummary()
+                        && groupKey.equals(r.getSbn().getGroup())
+                        && ungrouped.containsKey(r.getKey())) {
+                    ungrouped.remove(r.getKey());
+                }
+            }
+            mUngroupedAbuseNotifications.put(aggregateGroupKey, ungrouped);
+        }
+    }
+
     private record NotificationMoveOp(NotificationRecord record, FullyQualifiedGroupKey oldGroup,
                                       FullyQualifiedGroupKey newGroup) { }
 
@@ -1496,8 +1538,8 @@
 
     private boolean isNotificationAggregatedInSection(NotificationRecord record,
             NotificationSectioner sectioner) {
-        final FullyQualifiedGroupKey fullAggregateGroupKey = new FullyQualifiedGroupKey(
-                record.getUserId(), record.getSbn().getPackageName(), sectioner);
+        final FullyQualifiedGroupKey fullAggregateGroupKey = FullyQualifiedGroupKey.forRecord(
+                record, sectioner);
         return record.getGroupKey().equals(fullAggregateGroupKey.toString());
     }
 
@@ -1895,6 +1937,12 @@
             this(userId, pkg, AGGREGATE_GROUP_KEY + (sectioner != null ? sectioner.mName : ""));
         }
 
+        static FullyQualifiedGroupKey forRecord(NotificationRecord record,
+                @Nullable NotificationSectioner sectioner) {
+            return new FullyQualifiedGroupKey(record.getUserId(), record.getSbn().getPackageName(),
+                    sectioner);
+        }
+
         @Override
         public String toString() {
             return userId + "|" + pkg + "|" + "g:" + groupName;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0f1d28d..7a544cf 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1075,6 +1075,7 @@
                         summary.getSbn().getNotification().getGroupAlertBehavior();
 
         if (notificationForceGrouping()) {
+            summary.getNotification().flags |= Notification.FLAG_SILENT;
             if (!summary.getChannel().getId().equals(summaryAttr.channelId)) {
                 NotificationChannel newChannel = mPreferencesHelper.getNotificationChannel(pkg,
                         summary.getUid(), summaryAttr.channelId, false);
@@ -7450,6 +7451,7 @@
                     // Override group key early for forced grouped notifications
                     r.setOverrideGroupKey(groupName);
                 }
+                r.getNotification().flags |= Notification.FLAG_SILENT;
             }
 
             addAutoGroupAdjustment(r, groupName);
@@ -10196,6 +10198,12 @@
         }
         if (isSummary) {
             mSummaryByGroupKey.put(group, r);
+
+            if (notificationForceGrouping()) {
+                // If any formerly-ungrouped notifications will be grouped by this summary, update
+                // accordingly.
+                mGroupHelper.onGroupSummaryAdded(r, mNotificationList);
+            }
         }
 
         FlagChecker childrenFlagChecker = (flags) -> {
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index ee29849..737d943 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -308,7 +308,9 @@
             Slog.d(TAG, "onPackageRemoved pkgName=" + pkgName + " userId=" + userId);
         }
         // Update the state of all overlays that target this package.
-        final Set<UserPackage> targets = updateOverlaysForTarget(pkgName, userId, 0 /* flags */);
+        Set<UserPackage> targets = Collections.emptySet();
+        targets = CollectionUtils.addAll(targets,
+                updateOverlaysForTarget(pkgName, userId, 0 /* flags */));
 
         // Remove all the overlays this package declares.
         return CollectionUtils.addAll(targets,
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 7349204..3361dbc 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -644,20 +644,6 @@
         return mScanResult.mPkgSetting;
     }
 
-    @Nullable
-    public PackageSetting getRealPackageSetting() {
-        // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous
-        //  setting needs to be passed to have a comparison, hide it behind an immutable
-        //  interface. There's no good reason to have 3 different ways to access the real
-        //  PackageSetting object, only one of which is actually correct.
-        PackageSetting realPkgSetting = isExistingSettingCopied()
-                ? getScanRequestPackageSetting() : getScannedPackageSetting();
-        if (realPkgSetting == null) {
-            realPkgSetting = getScannedPackageSetting();
-        }
-        return realPkgSetting;
-    }
-
     public boolean isExistingSettingCopied() {
         assertScanResultExists();
         return mScanResult.mExistingSettingCopied;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 635ef06..af788ea 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -21,6 +21,7 @@
 import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDATED_BY_DO;
 import static android.content.pm.DataLoaderType.INCREMENTAL;
 import static android.content.pm.DataLoaderType.STREAMING;
+import static android.content.pm.Flags.cloudCompilationVerification;
 import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
 import static android.content.pm.PackageInstaller.UNARCHIVAL_OK;
 import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET;
@@ -3687,6 +3688,10 @@
             CollectionUtils.addAll(stagedSplitTypes, apk.getSplitTypes());
         }
 
+        if (cloudCompilationVerification()) {
+            verifySdmSignatures(artManagedFilePaths, mSigningDetails);
+        }
+
         if (removeSplitList.size() > 0) {
             if (pkgInfo == null) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -4028,6 +4033,14 @@
             File targetArtManagedFile = new File(
                     ArtManagedInstallFileHelper.getTargetPathForApk(path, targetFile.getPath()));
             stageFileLocked(artManagedFile, targetArtManagedFile);
+            if (!artManagedFile.equals(targetArtManagedFile)) {
+                // The file has been renamed. Update the list to reflect the change.
+                for (int i = 0; i < artManagedFilePaths.size(); ++i) {
+                    if (artManagedFilePaths.get(i).equals(path)) {
+                        artManagedFilePaths.set(i, targetArtManagedFile.getAbsolutePath());
+                    }
+                }
+            }
         }
     }
 
@@ -4309,6 +4322,37 @@
     }
 
     /**
+     * Verifies the signatures of SDM files.
+     *
+     * SDM is a file format that contains the cloud compilation artifacts. As a requirement, the SDM
+     * file should be signed with the same key as the APK.
+     *
+     * TODO(b/377474232): Move this logic to ART Service.
+     */
+    private static void verifySdmSignatures(List<String> artManagedFilePaths,
+            SigningDetails expectedSigningDetails) throws PackageManagerException {
+        ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+        for (String path : artManagedFilePaths) {
+            if (!path.endsWith(".sdm")) {
+                continue;
+            }
+            // SDM is a format introduced in Android 16, so we don't need to support older
+            // signature schemes.
+            int minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3;
+            ParseResult<SigningDetails> verified =
+                    ApkSignatureVerifier.verify(input, path, minSignatureScheme);
+            if (verified.isError()) {
+                throw new PackageManagerException(
+                        INSTALL_FAILED_INVALID_APK, "Failed to verify SDM signatures");
+            }
+            if (!expectedSigningDetails.signaturesMatchExactly(verified.getResult())) {
+                throw new PackageManagerException(
+                        INSTALL_FAILED_INVALID_APK, "SDM signatures are inconsistent with APK");
+            }
+        }
+    }
+
+    /**
      * @return the uid of the owner this session
      */
     public int getInstallerUid() {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 93837b3..092ec8e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -7490,6 +7490,7 @@
         final long now = System.currentTimeMillis();
         final long nowRealtime = SystemClock.elapsedRealtime();
         final StringBuilder sb = new StringBuilder();
+        final Resources resources = Resources.getSystem();
 
         if (args != null && args.length > 0) {
             switch (args[0]) {
@@ -7570,10 +7571,15 @@
 
         // Dump some capabilities
         pw.println();
-        pw.print("  Max users: " + UserManager.getMaxSupportedUsers());
+        int effectiveMaxSupportedUsers = UserManager.getMaxSupportedUsers();
+        pw.print("  Max users: " + effectiveMaxSupportedUsers);
+        int defaultMaxSupportedUsers = resources.getInteger(R.integer.config_multiuserMaximumUsers);
+        if (effectiveMaxSupportedUsers != defaultMaxSupportedUsers) {
+            pw.print(" (built-in value: " + defaultMaxSupportedUsers + ")");
+        }
         pw.println(" (limit reached: " + isUserLimitReached() + ")");
         pw.println("  Supports switchable users: " + UserManager.supportsMultipleUsers());
-        pw.println("  All guests ephemeral: " + Resources.getSystem().getBoolean(
+        pw.println("  All guests ephemeral: " + resources.getBoolean(
                 com.android.internal.R.bool.config_guestUserEphemeral));
         pw.println("  Force ephemeral users: " + mForceEphemeralUsers);
         final boolean isHeadlessSystemUserMode = isHeadlessSystemUserMode();
@@ -7588,7 +7594,7 @@
             }
         }
         if (isHeadlessSystemUserMode) {
-            pw.println("  Can switch to headless system user: " + Resources.getSystem()
+            pw.println("  Can switch to headless system user: " + resources
                     .getBoolean(com.android.internal.R.bool.config_canSwitchToHeadlessSystemUser));
         }
         pw.println("  User version: " + mUserVersion);
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 58c5b1c..5798aa9 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -36,6 +36,7 @@
 import static android.os.UserManager.USER_TYPE_PROFILE_COMMUNAL;
 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
+import static android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING;
 import static android.os.UserManager.USER_TYPE_PROFILE_TEST;
 import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS;
 
@@ -111,6 +112,7 @@
         builders.put(USER_TYPE_PROFILE_CLONE, getDefaultTypeProfileClone());
         builders.put(USER_TYPE_PROFILE_COMMUNAL, getDefaultTypeProfileCommunal());
         builders.put(USER_TYPE_PROFILE_PRIVATE, getDefaultTypeProfilePrivate());
+        builders.put(USER_TYPE_PROFILE_SUPERVISING, getDefaultTypeProfileSupervising());
         if (Build.IS_DEBUGGABLE) {
             builders.put(USER_TYPE_PROFILE_TEST, getDefaultTypeProfileTest());
         }
@@ -343,6 +345,29 @@
     }
 
     /**
+     * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_SUPERVISING}
+     * configuration.
+     */
+    private static UserTypeDetails.Builder getDefaultTypeProfileSupervising() {
+        return new UserTypeDetails.Builder()
+                .setName(USER_TYPE_PROFILE_SUPERVISING)
+                .setBaseType(FLAG_PROFILE)
+                .setMaxAllowed(1)
+                .setProfileParentRequired(false)
+                .setEnabled(android.multiuser.Flags.allowSupervisingProfile() ? 1 : 0)
+                .setLabels(R.string.profile_label_supervising)
+                .setDefaultRestrictions(getDefaultSupervisingProfileRestrictions())
+                .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings())
+                .setDefaultUserProperties(new UserProperties.Builder()
+                        .setStartWithParent(false)
+                        .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_NO)
+                        .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_NO)
+                        .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
+                        .setCredentialShareableWithParent(false)
+                        .setAlwaysVisible(true));
+    }
+
+    /**
      * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_SECONDARY}
      * configuration.
      */
@@ -449,6 +474,12 @@
         return restrictions;
     }
 
+    private static Bundle getDefaultSupervisingProfileRestrictions() {
+        final Bundle restrictions = getDefaultProfileRestrictions();
+        restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true);
+        return restrictions;
+    }
+
     private static Bundle getDefaultManagedProfileSecureSettings() {
         // Only add String values to the bundle, settings are written as Strings eventually
         final Bundle settings = new Bundle();
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6ab3059..098f113 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -897,7 +897,7 @@
                     SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId);
             grantPermissionsToSystemPackage(pm, voiceSearchPackage,
                     userId, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS, NEARBY_DEVICES_PERMISSIONS,
-                    COARSE_BACKGROUND_LOCATION_PERMISSIONS);
+                    COARSE_BACKGROUND_LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
             revokeRuntimePermissions(pm, voiceSearchPackage,
                 FINE_LOCATION_PERMISSIONS, false, userId);
         }
diff --git a/services/core/java/com/android/server/power/ScreenUndimDetector.java b/services/core/java/com/android/server/power/ScreenUndimDetector.java
index c4929c2..b376417 100644
--- a/services/core/java/com/android/server/power/ScreenUndimDetector.java
+++ b/services/core/java/com/android/server/power/ScreenUndimDetector.java
@@ -30,11 +30,11 @@
 import android.util.Slog;
 import android.view.Display;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FrameworkStatsLog;
 
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Detects when user manually undims the screen (x times) and acquires a wakelock to keep the screen
@@ -48,7 +48,6 @@
 
     /** DeviceConfig flag: is keep screen on feature enabled. */
     static final String KEY_KEEP_SCREEN_ON_ENABLED = "keep_screen_on_enabled";
-    private static final boolean DEFAULT_KEEP_SCREEN_ON_ENABLED = true;
     private static final int OUTCOME_POWER_BUTTON =
             FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__POWER_BUTTON;
     private static final int OUTCOME_TIMEOUT =
@@ -58,15 +57,11 @@
     /** DeviceConfig flag: how long should we keep the screen on. */
     @VisibleForTesting
     static final String KEY_KEEP_SCREEN_ON_FOR_MILLIS = "keep_screen_on_for_millis";
-    @VisibleForTesting
-    static final long DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS = TimeUnit.MINUTES.toMillis(10);
     private long mKeepScreenOnForMillis;
 
     /** DeviceConfig flag: how many user undims required to trigger keeping the screen on. */
     @VisibleForTesting
     static final String KEY_UNDIMS_REQUIRED = "undims_required";
-    @VisibleForTesting
-    static final int DEFAULT_UNDIMS_REQUIRED = 2;
     private int mUndimsRequired;
 
     /**
@@ -76,8 +71,6 @@
     @VisibleForTesting
     static final String KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS =
             "max_duration_between_undims_millis";
-    @VisibleForTesting
-    static final long DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS = TimeUnit.MINUTES.toMillis(5);
     private long mMaxDurationBetweenUndimsMillis;
 
     @VisibleForTesting
@@ -92,6 +85,7 @@
     private long mUndimOccurredTime = -1;
     private long mInteractionAfterUndimTime = -1;
     private InternalClock mClock;
+    private Context mContext;
 
     public ScreenUndimDetector() {
         mClock = new InternalClock();
@@ -109,12 +103,13 @@
 
     /** Should be called in parent's systemReady() */
     public void systemReady(Context context) {
+        mContext = context;
         readValuesFromDeviceConfig();
         DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE,
-                context.getMainExecutor(),
+                mContext.getMainExecutor(),
                 (properties) -> onDeviceConfigChange(properties.getKeyset()));
 
-        final PowerManager powerManager = context.getSystemService(PowerManager.class);
+        final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
         mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
                         | PowerManager.ON_AFTER_RELEASE,
                 UNDIM_DETECTOR_WAKE_LOCK);
@@ -203,36 +198,44 @@
         }
     }
 
-    private boolean readKeepScreenOnNotificationEnabled() {
+    private boolean readKeepScreenOnEnabled() {
+        boolean defaultKeepScreenOnEnabled = mContext.getResources().getBoolean(
+                R.bool.config_defaultPreventScreenTimeoutEnabled);
         return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE,
                 KEY_KEEP_SCREEN_ON_ENABLED,
-                DEFAULT_KEEP_SCREEN_ON_ENABLED);
+                defaultKeepScreenOnEnabled);
     }
 
     private long readKeepScreenOnForMillis() {
+        long defaultKeepScreenOnDuration = mContext.getResources().getInteger(
+                R.integer.config_defaultPreventScreenTimeoutForMillis);
         return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
                 KEY_KEEP_SCREEN_ON_FOR_MILLIS,
-                DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS);
+                defaultKeepScreenOnDuration);
     }
 
     private int readUndimsRequired() {
+        int defaultUndimsRequired = mContext.getResources().getInteger(
+                R.integer.config_defaultUndimsRequired);
         int undimsRequired = DeviceConfig.getInt(NAMESPACE_ATTENTION_MANAGER_SERVICE,
                 KEY_UNDIMS_REQUIRED,
-                DEFAULT_UNDIMS_REQUIRED);
+                defaultUndimsRequired);
 
         if (undimsRequired < 1 || undimsRequired > 5) {
             Slog.e(TAG, "Provided undimsRequired=" + undimsRequired
-                    + " is not allowed [1, 5]; using the default=" + DEFAULT_UNDIMS_REQUIRED);
-            return DEFAULT_UNDIMS_REQUIRED;
+                    + " is not allowed [1, 5]; using the default=" + defaultUndimsRequired);
+            return defaultUndimsRequired;
         }
 
         return undimsRequired;
     }
 
     private long readMaxDurationBetweenUndimsMillis() {
+        long defaultMaxDurationBetweenUndimsMillis = mContext.getResources().getInteger(
+                R.integer.config_defaultMaxDurationBetweenUndimsMillis);
         return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
                 KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS,
-                DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS);
+                defaultMaxDurationBetweenUndimsMillis);
     }
 
     private void onDeviceConfigChange(@NonNull Set<String> keys) {
@@ -253,15 +256,16 @@
 
     @VisibleForTesting
     void readValuesFromDeviceConfig() {
-        mKeepScreenOnEnabled = readKeepScreenOnNotificationEnabled();
+        mKeepScreenOnEnabled = readKeepScreenOnEnabled();
         mKeepScreenOnForMillis = readKeepScreenOnForMillis();
         mUndimsRequired = readUndimsRequired();
         mMaxDurationBetweenUndimsMillis = readMaxDurationBetweenUndimsMillis();
 
         Slog.i(TAG, "readValuesFromDeviceConfig():"
                 + "\nmKeepScreenOnForMillis=" + mKeepScreenOnForMillis
-                + "\nmKeepScreenOnNotificationEnabled=" + mKeepScreenOnEnabled
-                + "\nmUndimsRequired=" + mUndimsRequired);
+                + "\nmKeepScreenOnEnabled=" + mKeepScreenOnEnabled
+                + "\nmUndimsRequired=" + mUndimsRequired
+                + "\nmMaxDurationBetweenUndimsMillis=" + mMaxDurationBetweenUndimsMillis);
 
     }
 
diff --git a/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java b/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
index 5563f98..7cd9bdb 100644
--- a/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
+++ b/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
@@ -374,6 +374,10 @@
     @SuppressWarnings("unchecked")
     @Override
     public List<BatteryHistoryFragment> getFragments() {
+        if (!mLock.isHeldByCurrentThread()) {
+            throw new IllegalStateException("Reading battery history without a lock");
+        }
+
         ensureInitialized();
         return (List<BatteryHistoryFragment>)
                 (List<? extends BatteryHistoryFragment>) mHistoryFiles;
@@ -443,44 +447,6 @@
     }
 
     @Override
-    public BatteryHistoryFragment getNextFragment(BatteryHistoryFragment current, long startTimeMs,
-            long endTimeMs) {
-        ensureInitialized();
-
-        if (!mLock.isHeldByCurrentThread()) {
-            throw new IllegalStateException("Iterating battery history without a lock");
-        }
-
-        int nextFileIndex = 0;
-        int firstFileIndex = 0;
-        // skip the last file because its data is in history buffer.
-        int lastFileIndex = mHistoryFiles.size() - 2;
-        for (int i = lastFileIndex; i >= 0; i--) {
-            BatteryHistoryFragment fragment = mHistoryFiles.get(i);
-            if (current != null && fragment.monotonicTimeMs == current.monotonicTimeMs) {
-                nextFileIndex = i + 1;
-            }
-            if (fragment.monotonicTimeMs > endTimeMs) {
-                lastFileIndex = i - 1;
-            }
-            if (fragment.monotonicTimeMs <= startTimeMs) {
-                firstFileIndex = i;
-                break;
-            }
-        }
-
-        if (nextFileIndex < firstFileIndex) {
-            nextFileIndex = firstFileIndex;
-        }
-
-        if (nextFileIndex <= lastFileIndex) {
-            return mHistoryFiles.get(nextFileIndex);
-        }
-
-        return null;
-    }
-
-    @Override
     public boolean hasCompletedFragments() {
         ensureInitialized();
 
diff --git a/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java b/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java
index 54365ff..c5a43a5 100644
--- a/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java
+++ b/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java
@@ -72,14 +72,20 @@
     }
 
     SelinuxAuditLogsCollector(RateLimiter rateLimiter, QuotaLimiter quotaLimiter) {
-        this(
-                () ->
-                        DeviceConfig.getString(
-                                DeviceConfig.NAMESPACE_ADSERVICES,
-                                CONFIG_SELINUX_AUDIT_DOMAIN,
-                                DEFAULT_SELINUX_AUDIT_DOMAIN),
-                rateLimiter,
-                quotaLimiter);
+        this(new DefaultDomainSupplier(), rateLimiter, quotaLimiter);
+    }
+
+    private static class DefaultDomainSupplier implements Supplier<String> {
+        @Override
+        public String get() {
+            if (SelinuxAuditLogsService.enabledForAllDomains()) {
+                return "\\w+";
+            }
+            return DeviceConfig.getString(
+                    DeviceConfig.NAMESPACE_ADSERVICES,
+                    CONFIG_SELINUX_AUDIT_DOMAIN,
+                    DEFAULT_SELINUX_AUDIT_DOMAIN);
+        }
     }
 
     public void setStopRequested(boolean stopRequested) {
diff --git a/services/core/java/com/android/server/selinux/SelinuxAuditLogsService.java b/services/core/java/com/android/server/selinux/SelinuxAuditLogsService.java
index d46e891..9dc457c 100644
--- a/services/core/java/com/android/server/selinux/SelinuxAuditLogsService.java
+++ b/services/core/java/com/android/server/selinux/SelinuxAuditLogsService.java
@@ -16,6 +16,7 @@
 package com.android.server.selinux;
 
 import static com.android.sdksandbox.flags.Flags.selinuxSdkSandboxAudit;
+import static com.android.server.selinux.flags.Flags.selinuxLogsCollect;
 
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
@@ -49,6 +50,9 @@
             "selinux_audit_job_frequency_hours";
     private static final String CONFIG_SELINUX_ENABLE_AUDIT_JOB = "selinux_enable_audit_job";
     private static final String CONFIG_SELINUX_AUDIT_CAP = "selinux_audit_cap";
+    private static final String DEVICE_CONFIG_SECURITY_NAMESPACE = "security";
+    private static final String CONFIG_SECURITY_SELINUX_AUDIT_JOB_ENABLED =
+            "selinux_audit_job_enabled";
     private static final int MAX_PERMITS_CAP_DEFAULT = 50000;
 
     private static final int SELINUX_AUDIT_JOB_ID = 25327386;
@@ -76,7 +80,7 @@
 
     /** Schedule jobs with the {@link JobScheduler}. */
     public static void schedule(Context context) {
-        if (!selinuxSdkSandboxAudit()) {
+        if (!selinuxSdkSandboxAudit() && !enabledForAllDomains()) {
             Slog.d(TAG, "SelinuxAuditLogsService not enabled");
             return;
         }
@@ -86,13 +90,20 @@
             return;
         }
 
-        LogsCollectorJobScheduler propertiesListener =
+        LogsCollectorJobScheduler scheduler =
                 new LogsCollectorJobScheduler(
                         context.getSystemService(JobScheduler.class)
                                 .forNamespace(SELINUX_AUDIT_NAMESPACE));
-        propertiesListener.schedule();
+        scheduler.schedule();
+
+        AdServicesPropertyMonitor adServicesProperties = new AdServicesPropertyMonitor(scheduler);
         DeviceConfig.addOnPropertiesChangedListener(
-                DeviceConfig.NAMESPACE_ADSERVICES, context.getMainExecutor(), propertiesListener);
+                DeviceConfig.NAMESPACE_ADSERVICES, context.getMainExecutor(), adServicesProperties);
+
+        SecurityPropertyMonitor securityProperties = new SecurityPropertyMonitor(scheduler);
+        DeviceConfig.addOnPropertiesChangedListener(
+                DEVICE_CONFIG_SECURITY_NAMESPACE, context.getMainExecutor(), securityProperties);
+
     }
 
     @Override
@@ -101,7 +112,7 @@
             Slog.e(TAG, "The job id does not match the expected selinux job id.");
             return false;
         }
-        if (!selinuxSdkSandboxAudit()) {
+        if (!selinuxSdkSandboxAudit() && !enabledForAllDomains()) {
             Slog.i(TAG, "Selinux audit job disabled.");
             return false;
         }
@@ -123,17 +134,33 @@
         return false;
     }
 
-    /**
-     * This class is in charge of scheduling the job service, and keeping the scheduling up to date
-     * when the parameters change.
-     */
-    private static final class LogsCollectorJobScheduler
+    /** Checks if the service is enabled for all domains */
+    public static final boolean enabledForAllDomains() {
+        if (selinuxLogsCollect()) {
+            return DeviceConfig.getBoolean(
+                    DEVICE_CONFIG_SECURITY_NAMESPACE,
+                    CONFIG_SECURITY_SELINUX_AUDIT_JOB_ENABLED,
+                    false);
+        }
+        return false;
+    }
+
+    /** Checks if the service is enabled for SDK Sandbox */
+    public static final boolean enabledForSdkSandbox() {
+        if (selinuxSdkSandboxAudit()) {
+            return DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_ADSERVICES, CONFIG_SELINUX_ENABLE_AUDIT_JOB, false);
+        }
+        return false;
+    }
+
+    private static final class AdServicesPropertyMonitor
             implements DeviceConfig.OnPropertiesChangedListener {
 
-        private final JobScheduler mJobScheduler;
+        private final LogsCollectorJobScheduler mScheduler;
 
-        private LogsCollectorJobScheduler(JobScheduler jobScheduler) {
-            mJobScheduler = jobScheduler;
+        private AdServicesPropertyMonitor(LogsCollectorJobScheduler scheduler) {
+            mScheduler = scheduler;
         }
 
         @Override
@@ -149,19 +176,65 @@
             if (keyset.contains(CONFIG_SELINUX_ENABLE_AUDIT_JOB)) {
                 boolean enabled =
                         changedProperties.getBoolean(
-                                CONFIG_SELINUX_ENABLE_AUDIT_JOB, /* defaultValue= */ false);
+                                CONFIG_SELINUX_ENABLE_AUDIT_JOB, /* defaultValue= */ false)
+                        || enabledForAllDomains();
                 if (enabled) {
-                    schedule();
+                    mScheduler.schedule();
                 } else {
-                    mJobScheduler.cancel(SELINUX_AUDIT_JOB_ID);
+                    mScheduler.cancel();
                 }
             } else if (keyset.contains(CONFIG_SELINUX_AUDIT_JOB_FREQUENCY_HOURS)) {
                 // The job frequency changed, reschedule.
-                schedule();
+                mScheduler.schedule();
             }
         }
+    }
 
-        private void schedule() {
+    private static final class SecurityPropertyMonitor
+            implements DeviceConfig.OnPropertiesChangedListener {
+
+        private final LogsCollectorJobScheduler mScheduler;
+
+        private SecurityPropertyMonitor(LogsCollectorJobScheduler scheduler) {
+            mScheduler = scheduler;
+        }
+
+        @Override
+        public void onPropertiesChanged(Properties changedProperties) {
+            Set<String> keyset = changedProperties.getKeyset();
+
+            if (keyset.contains(CONFIG_SECURITY_SELINUX_AUDIT_JOB_ENABLED)) {
+                boolean enabled =
+                        changedProperties.getBoolean(
+                                CONFIG_SECURITY_SELINUX_AUDIT_JOB_ENABLED,
+                                /* defaultValue= */ false)
+                        || enabledForSdkSandbox();
+                if (enabled) {
+                    mScheduler.schedule();
+                } else {
+                    mScheduler.cancel();
+                }
+            }
+        }
+    }
+
+    /**
+     * This class is in charge of scheduling the job service, and keeping the scheduling up to date
+     * when the parameters change.
+     */
+    private static final class LogsCollectorJobScheduler {
+
+        private final JobScheduler mJobScheduler;
+
+        private LogsCollectorJobScheduler(JobScheduler jobScheduler) {
+            mJobScheduler = jobScheduler;
+        }
+
+        public void cancel() {
+            mJobScheduler.cancel(SELINUX_AUDIT_JOB_ID);
+        }
+
+        public void schedule() {
             long frequencyMillis =
                     TimeUnit.HOURS.toMillis(
                             DeviceConfig.getInt(
diff --git a/services/core/java/com/android/server/selinux/flags.aconfig b/services/core/java/com/android/server/selinux/flags.aconfig
new file mode 100644
index 0000000..3bb5a6b
--- /dev/null
+++ b/services/core/java/com/android/server/selinux/flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.server.selinux.flags"
+container: "system"
+
+flag {
+    name: "selinux_logs_collect"
+    namespace: "network_security"
+    description: "Enable collection of SELinux denials based on selinux_audit_job_enabled"
+    bug: "372950125"
+}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 31348cd..17980c0 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -177,6 +177,7 @@
     private final String mDefaultTextClassifierPackage;
     @Nullable
     private final String mSystemTextClassifierPackage;
+    private final MyPackageMonitor mPackageMonitor;
 
     private TextClassificationManagerService(Context context) {
         mContext = Objects.requireNonNull(context);
@@ -187,50 +188,50 @@
         mDefaultTextClassifierPackage = packageManager.getDefaultTextClassifierPackageName();
         mSystemTextClassifierPackage = packageManager.getSystemTextClassifierPackageName();
         mSessionCache = new SessionCache(mLock);
+        mPackageMonitor = new MyPackageMonitor();
     }
 
     private void startListenSettings() {
         mSettingsListener.registerObserver();
     }
 
+    private class MyPackageMonitor extends PackageMonitor {
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            notifyPackageInstallStatusChange(packageName, /* installed*/ true);
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            notifyPackageInstallStatusChange(packageName, /* installed= */ false);
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
+            final int userId = getChangingUserId();
+            synchronized (mLock) {
+                final UserState userState = getUserStateLocked(userId);
+                final ServiceState serviceState = userState.getServiceStateLocked(packageName);
+                if (serviceState != null) {
+                    serviceState.onPackageModifiedLocked();
+                }
+            }
+        }
+
+        private void notifyPackageInstallStatusChange(String packageName, boolean installed) {
+            final int userId = getChangingUserId();
+            synchronized (mLock) {
+                final UserState userState = getUserStateLocked(userId);
+                final ServiceState serviceState = userState.getServiceStateLocked(packageName);
+                if (serviceState != null) {
+                    serviceState.onPackageInstallStatusChangeLocked(installed);
+                }
+            }
+        }
+    }
+
     void startTrackingPackageChanges() {
-        final PackageMonitor monitor = new PackageMonitor() {
-
-            @Override
-            public void onPackageAdded(String packageName, int uid) {
-                notifyPackageInstallStatusChange(packageName, /* installed*/ true);
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                notifyPackageInstallStatusChange(packageName, /* installed= */ false);
-            }
-
-            @Override
-            public void onPackageModified(String packageName) {
-                final int userId = getChangingUserId();
-                synchronized (mLock) {
-                    final UserState userState = getUserStateLocked(userId);
-                    final ServiceState serviceState = userState.getServiceStateLocked(packageName);
-                    if (serviceState != null) {
-                        serviceState.onPackageModifiedLocked();
-                    }
-                }
-            }
-
-            private void notifyPackageInstallStatusChange(String packageName, boolean installed) {
-                final int userId = getChangingUserId();
-                synchronized (mLock) {
-                    final UserState userState = getUserStateLocked(userId);
-                    final ServiceState serviceState = userState.getServiceStateLocked(packageName);
-                    if (serviceState != null) {
-                        serviceState.onPackageInstallStatusChangeLocked(installed);
-                    }
-                }
-            }
-        };
-
-        monitor.register(mContext, null,  UserHandle.ALL, true);
+       mPackageMonitor.register(mContext, null,  UserHandle.ALL, true);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 8bcf1a9..47d6879 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -183,7 +183,7 @@
     private final Map<String, SessionState> mSessionIdToSessionStateMap = new HashMap<>();
 
     private final MessageHandler mMessageHandler;
-
+    private final MyPackageMonitor mPackageMonitor;
     private final ActivityManager mActivityManager;
 
     private boolean mExternalInputLoggingDisplayNameFilterEnabled = false;
@@ -200,6 +200,7 @@
         mMessageHandler =
                 new MessageHandler(mContext.getContentResolver(), IoThread.get().getLooper());
         mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
+        mPackageMonitor = new MyPackageMonitor(/* supportsPackageRestartQuery */ true);
 
         mActivityManager =
                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
@@ -298,74 +299,79 @@
         mExternalInputLoggingDeviceBrandNames.addAll(Arrays.asList(deviceBrandNames));
     }
 
+    private class MyPackageMonitor extends PackageMonitor {
+        MyPackageMonitor(boolean supportsPackageRestartQuery) {
+            super(supportsPackageRestartQuery);
+        }
+
+        private void buildTvInputList(String[] packages) {
+            int userId = getChangingUserId();
+            synchronized (mLock) {
+                if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
+                    buildTvInputListLocked(userId, packages);
+                    buildTvContentRatingSystemListLocked(userId);
+                }
+            }
+        }
+
+        @Override
+        public void onPackageUpdateFinished(String packageName, int uid) {
+            if (DEBUG) Slog.d(TAG, "onPackageUpdateFinished(packageName=" + packageName + ")");
+            // This callback is invoked when the TV input is reinstalled.
+            // In this case, isReplacing() always returns true.
+            buildTvInputList(new String[] { packageName });
+        }
+
+        @Override
+        public void onPackagesAvailable(String[] packages) {
+            if (DEBUG) {
+                Slog.d(TAG, "onPackagesAvailable(packages=" + Arrays.toString(packages) + ")");
+            }
+            // This callback is invoked when the media on which some packages exist become
+            // available.
+            if (isReplacing()) {
+                buildTvInputList(packages);
+            }
+        }
+
+        @Override
+        public void onPackagesUnavailable(String[] packages) {
+            // This callback is invoked when the media on which some packages exist become
+            // unavailable.
+            if (DEBUG)  {
+                Slog.d(TAG, "onPackagesUnavailable(packages=" + Arrays.toString(packages)
+                        + ")");
+            }
+            if (isReplacing()) {
+                buildTvInputList(packages);
+            }
+        }
+
+        @Override
+        public void onSomePackagesChanged() {
+            // TODO: Use finer-grained methods(e.g. onPackageAdded, onPackageRemoved) to manage
+            // the TV inputs.
+            if (DEBUG) Slog.d(TAG, "onSomePackagesChanged()");
+            if (isReplacing()) {
+                if (DEBUG) Slog.d(TAG, "Skipped building TV input list due to replacing");
+                // When the package is updated, buildTvInputListLocked is called in other
+                // methods instead.
+                return;
+            }
+            buildTvInputList(null);
+        }
+
+        @Override
+        public boolean onPackageChanged(String packageName, int uid, String[] components) {
+            // The input list needs to be updated in any cases, regardless of whether
+            // it happened to the whole package or a specific component. Returning true so that
+            // the update can be handled in {@link #onSomePackagesChanged}.
+            return true;
+        }
+    }
+
     private void registerBroadcastReceivers() {
-        PackageMonitor monitor = new PackageMonitor(/* supportsPackageRestartQuery */ true) {
-            private void buildTvInputList(String[] packages) {
-                int userId = getChangingUserId();
-                synchronized (mLock) {
-                    if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
-                        buildTvInputListLocked(userId, packages);
-                        buildTvContentRatingSystemListLocked(userId);
-                    }
-                }
-            }
-
-            @Override
-            public void onPackageUpdateFinished(String packageName, int uid) {
-                if (DEBUG) Slog.d(TAG, "onPackageUpdateFinished(packageName=" + packageName + ")");
-                // This callback is invoked when the TV input is reinstalled.
-                // In this case, isReplacing() always returns true.
-                buildTvInputList(new String[] { packageName });
-            }
-
-            @Override
-            public void onPackagesAvailable(String[] packages) {
-                if (DEBUG) {
-                    Slog.d(TAG, "onPackagesAvailable(packages=" + Arrays.toString(packages) + ")");
-                }
-                // This callback is invoked when the media on which some packages exist become
-                // available.
-                if (isReplacing()) {
-                    buildTvInputList(packages);
-                }
-            }
-
-            @Override
-            public void onPackagesUnavailable(String[] packages) {
-                // This callback is invoked when the media on which some packages exist become
-                // unavailable.
-                if (DEBUG)  {
-                    Slog.d(TAG, "onPackagesUnavailable(packages=" + Arrays.toString(packages)
-                            + ")");
-                }
-                if (isReplacing()) {
-                    buildTvInputList(packages);
-                }
-            }
-
-            @Override
-            public void onSomePackagesChanged() {
-                // TODO: Use finer-grained methods(e.g. onPackageAdded, onPackageRemoved) to manage
-                // the TV inputs.
-                if (DEBUG) Slog.d(TAG, "onSomePackagesChanged()");
-                if (isReplacing()) {
-                    if (DEBUG) Slog.d(TAG, "Skipped building TV input list due to replacing");
-                    // When the package is updated, buildTvInputListLocked is called in other
-                    // methods instead.
-                    return;
-                }
-                buildTvInputList(null);
-            }
-
-            @Override
-            public boolean onPackageChanged(String packageName, int uid, String[] components) {
-                // The input list needs to be updated in any cases, regardless of whether
-                // it happened to the whole package or a specific component. Returning true so that
-                // the update can be handled in {@link #onSomePackagesChanged}.
-                return true;
-            }
-        };
-        monitor.register(mContext, null, UserHandle.ALL, true);
+        mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
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 6a7fc6d..42013fa 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -105,6 +105,7 @@
     // A global lock.
     private final Object mLock = new Object();
     private final Context mContext;
+    private final MyPackageMonitor mPackageMonitor;
     // ID of the current user.
     @GuardedBy("mLock")
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
@@ -138,6 +139,7 @@
         super(context);
         mContext = context;
         mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+        mPackageMonitor = new MyPackageMonitor(/* supportsPackageRestartQuery */ true);
     }
 
     @GuardedBy("mLock")
@@ -518,86 +520,91 @@
         }
     }
 
-    private void registerBroadcastReceivers() {
-        PackageMonitor monitor = new PackageMonitor(/* supportsPackageRestartQuery */ true) {
-            private void buildTvInteractiveAppServiceList(String[] packages) {
-                int userId = getChangingUserId();
-                synchronized (mLock) {
-                    if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
-                        buildTvInteractiveAppServiceListLocked(userId, packages);
-                        buildAppLinkInfoLocked(userId);
-                    }
+    private class MyPackageMonitor extends PackageMonitor {
+        MyPackageMonitor(boolean supportsPackageRestartQuery) {
+            super(supportsPackageRestartQuery);
+        }
+
+        private void buildTvInteractiveAppServiceList(String[] packages) {
+            int userId = getChangingUserId();
+            synchronized (mLock) {
+                if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
+                    buildTvInteractiveAppServiceListLocked(userId, packages);
+                    buildAppLinkInfoLocked(userId);
                 }
             }
-            private void buildTvAdServiceList(String[] packages) {
-                int userId = getChangingUserId();
-                synchronized (mLock) {
-                    if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
-                        buildTvAdServiceListLocked(userId, packages);
-                    }
+        }
+        private void buildTvAdServiceList(String[] packages) {
+            int userId = getChangingUserId();
+            synchronized (mLock) {
+                if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
+                    buildTvAdServiceListLocked(userId, packages);
                 }
             }
+        }
 
-            @Override
-            public void onPackageUpdateFinished(String packageName, int uid) {
-                if (DEBUG) Slogf.d(TAG, "onPackageUpdateFinished(packageName=" + packageName + ")");
-                // This callback is invoked when the TV interactive App service is reinstalled.
-                // In this case, isReplacing() always returns true.
-                buildTvInteractiveAppServiceList(new String[] { packageName });
-                buildTvAdServiceList(new String[] { packageName });
+        @Override
+        public void onPackageUpdateFinished(String packageName, int uid) {
+            if (DEBUG) Slogf.d(TAG, "onPackageUpdateFinished(packageName=" + packageName + ")");
+            // This callback is invoked when the TV interactive App service is reinstalled.
+            // In this case, isReplacing() always returns true.
+            buildTvInteractiveAppServiceList(new String[] { packageName });
+            buildTvAdServiceList(new String[] { packageName });
+        }
+
+        @Override
+        public void onPackagesAvailable(String[] packages) {
+            if (DEBUG) {
+                Slogf.d(TAG, "onPackagesAvailable(packages=" + Arrays.toString(packages) + ")");
             }
+            // This callback is invoked when the media on which some packages exist become
+            // available.
+            if (isReplacing()) {
+                buildTvInteractiveAppServiceList(packages);
+                buildTvAdServiceList(packages);
+            }
+        }
 
-            @Override
-            public void onPackagesAvailable(String[] packages) {
+        @Override
+        public void onPackagesUnavailable(String[] packages) {
+            // This callback is invoked when the media on which some packages exist become
+            // unavailable.
+            if (DEBUG)  {
+                Slogf.d(TAG, "onPackagesUnavailable(packages=" + Arrays.toString(packages)
+                        + ")");
+            }
+            if (isReplacing()) {
+                buildTvInteractiveAppServiceList(packages);
+                buildTvAdServiceList(packages);
+            }
+        }
+
+        @Override
+        public void onSomePackagesChanged() {
+            if (DEBUG) Slogf.d(TAG, "onSomePackagesChanged()");
+            if (isReplacing()) {
                 if (DEBUG) {
-                    Slogf.d(TAG, "onPackagesAvailable(packages=" + Arrays.toString(packages) + ")");
+                    Slogf.d(TAG, "Skipped building TV interactive App list due to replacing");
                 }
-                // This callback is invoked when the media on which some packages exist become
-                // available.
-                if (isReplacing()) {
-                    buildTvInteractiveAppServiceList(packages);
-                    buildTvAdServiceList(packages);
-                }
+                // When the package is updated, buildTvInteractiveAppServiceListLocked is called
+                // in other methods instead.
+                return;
             }
+            buildTvInteractiveAppServiceList(null);
+            buildTvAdServiceList(null);
+        }
 
-            @Override
-            public void onPackagesUnavailable(String[] packages) {
-                // This callback is invoked when the media on which some packages exist become
-                // unavailable.
-                if (DEBUG)  {
-                    Slogf.d(TAG, "onPackagesUnavailable(packages=" + Arrays.toString(packages)
-                            + ")");
-                }
-                if (isReplacing()) {
-                    buildTvInteractiveAppServiceList(packages);
-                    buildTvAdServiceList(packages);
-                }
-            }
+        @Override
+        public boolean onPackageChanged(String packageName, int uid, String[] components) {
+            // The interactive App list needs to be updated in any cases, regardless of whether
+            // it happened to the whole package or a specific component. Returning true so that
+            // the update can be handled in {@link #onSomePackagesChanged}.
+            return true;
+        }
+    }
 
-            @Override
-            public void onSomePackagesChanged() {
-                if (DEBUG) Slogf.d(TAG, "onSomePackagesChanged()");
-                if (isReplacing()) {
-                    if (DEBUG) {
-                        Slogf.d(TAG, "Skipped building TV interactive App list due to replacing");
-                    }
-                    // When the package is updated, buildTvInteractiveAppServiceListLocked is called
-                    // in other methods instead.
-                    return;
-                }
-                buildTvInteractiveAppServiceList(null);
-                buildTvAdServiceList(null);
-            }
-
-            @Override
-            public boolean onPackageChanged(String packageName, int uid, String[] components) {
-                // The interactive App list needs to be updated in any cases, regardless of whether
-                // it happened to the whole package or a specific component. Returning true so that
-                // the update can be handled in {@link #onSomePackagesChanged}.
-                return true;
-            }
-        };
-        monitor.register(mContext, null, UserHandle.ALL, true);
+    private void registerBroadcastReceivers() {
+        mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
diff --git a/services/core/java/com/android/server/updates/CertPinInstallReceiver.java b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
index c8e7a8d..250e99b 100644
--- a/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
@@ -19,10 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 
-import java.io.File;
-
 public class CertPinInstallReceiver extends ConfigUpdateInstallReceiver {
-    private static final String KEYCHAIN_DIR = "/data/misc/keychain/";
 
     public CertPinInstallReceiver() {
         super("/data/misc/keychain/", "pins", "metadata/", "version");
@@ -30,22 +27,7 @@
 
     @Override
     public void onReceive(final Context context, final Intent intent) {
-        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
-            if (com.android.server.flags.Flags.certpininstallerRemoval()) {
-                File pins = new File(KEYCHAIN_DIR + "pins");
-                if (pins.exists()) {
-                    pins.delete();
-                }
-                File version = new File(KEYCHAIN_DIR + "metadata/version");
-                if (version.exists()) {
-                    version.delete();
-                }
-                File metadata = new File(KEYCHAIN_DIR + "metadata");
-                if (metadata.exists()) {
-                    metadata.delete();
-                }
-            }
-        } else if (!com.android.server.flags.Flags.certpininstallerRemoval()) {
+        if (!com.android.server.flags.Flags.certpininstallerRemoval()) {
             super.onReceive(context, intent);
         }
     }
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 7c2ce64..458cb02 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -58,6 +58,7 @@
 
     private final Object mLock;
     private final Context mContext;
+    private final PackageMonitor mPackageMonitor;
     private final String mSettingName;
     private final String mServiceName;
     private final String mServicePermission;
@@ -78,13 +79,39 @@
 
     private EnabledComponentsObserver(@NonNull Context context, @NonNull String settingName,
             @NonNull String servicePermission, @NonNull String serviceName, @NonNull Object lock,
-            @NonNull Collection<EnabledComponentChangeListener> listeners) {
+            @NonNull Collection<EnabledComponentChangeListener> listeners,
+            @NonNull Looper looper) {
         mLock = lock;
         mContext = context;
         mSettingName = settingName;
         mServiceName = serviceName;
         mServicePermission = servicePermission;
         mEnabledComponentListeners.addAll(listeners);
+        mPackageMonitor = new PackageMonitor(true) {
+            @Override
+            public void onSomePackagesChanged() {
+                onPackagesChanged();
+            }
+
+            @Override
+            public void onPackageDisappeared(String packageName, int reason) {
+                onPackagesChanged();
+            }
+
+            @Override
+            public void onPackageModified(String packageName) {
+                onPackagesChanged();
+            }
+
+            @Override
+            public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
+                    boolean doit) {
+                onPackagesChanged();
+                return super.onHandleForceStop(intent, packages, uid, doit);
+            }
+        };
+
+        mPackageMonitor.register(context, looper, UserHandle.ALL, true);;
     }
 
     /**
@@ -108,38 +135,7 @@
         SettingsObserver s = SettingsObserver.build(context, handler, settingName);
 
         final EnabledComponentsObserver o = new EnabledComponentsObserver(context, settingName,
-                servicePermission, serviceName, lock, listeners);
-
-        PackageMonitor packageMonitor = new PackageMonitor(true) {
-            @Override
-            public void onSomePackagesChanged() {
-                o.onPackagesChanged();
-
-            }
-
-            @Override
-            public void onPackageDisappeared(String packageName, int reason) {
-                o.onPackagesChanged();
-
-            }
-
-            @Override
-            public void onPackageModified(String packageName) {
-                o.onPackagesChanged();
-
-            }
-
-            @Override
-            public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
-                    boolean doit) {
-                o.onPackagesChanged();
-
-                return super.onHandleForceStop(intent, packages, uid, doit);
-            }
-        };
-
-        packageMonitor.register(context, looper, UserHandle.ALL, true);
-
+                servicePermission, serviceName, lock, listeners, looper);
         s.addListener(o);
 
         return o;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d620e98..bac7326 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1173,12 +1173,19 @@
                     return;
                 }
 
-                final ComponentName wpService = mWallpaper.getComponent();
                 // The broadcast of package update could be delayed after service disconnected. Try
                 // to re-bind the service for 10 seconds.
                 mWallpaper.mBindSource = BindSource.CONNECTION_TRY_TO_REBIND;
-                if (bindWallpaperComponentLocked(
-                        wpService, true, false, mWallpaper, null)) {
+                boolean success;
+                if (liveWallpaperContentHandling()) {
+                    success = bindWallpaperDescriptionLocked(
+                            mWallpaper.getDescription(), /* force= */ true,
+                            /* fromUser= */ false, mWallpaper, /* reply= */ null);
+                } else {
+                    success = bindWallpaperComponentLocked(mWallpaper.getComponent(), /* force= */
+                            true, /* fromUser= */false, mWallpaper, /* reply= */ null);
+                }
+                if (success) {
                     mWallpaper.connection.scheduleTimeoutLocked();
                 } else if (SystemClock.uptimeMillis() - mWallpaper.lastDiedTime
                         < WALLPAPER_RECONNECT_TIMEOUT_MS) {
@@ -1189,7 +1196,7 @@
                     // Timeout
                     Slog.w(TAG, "Reverting to built-in wallpaper!");
                     clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, false, null);
-                    final String flattened = wpService.flattenToString();
+                    final String flattened = mWallpaper.getComponent().flattenToString();
                     EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
                             flattened.substring(0, Math.min(flattened.length(),
                                     MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 58534b9..1299a4d 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -294,19 +294,6 @@
         }
     }
 
-    void onAppWindowTransition(int displayId, int transition) {
-        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
-            mAccessibilityTracing.logTrace(TAG + ".onAppWindowTransition",
-                    FLAGS_MAGNIFICATION_CALLBACK,
-                    "displayId=" + displayId + "; transition=" + transition);
-        }
-        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
-        if (displayMagnifier != null) {
-            displayMagnifier.onAppWindowTransition(displayId, transition);
-        }
-        // Not relevant for the window observer.
-    }
-
     void onWMTransition(int displayId, @TransitionType int type, @TransitionFlags int flags) {
         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
             mAccessibilityTracing.logTrace(TAG + ".onWMTransition",
@@ -670,34 +657,6 @@
             mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED);
         }
 
-        void onAppWindowTransition(int displayId, int transition) {
-            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
-                mAccessibilityTracing.logTrace(LOG_TAG + ".onAppWindowTransition",
-                        FLAGS_MAGNIFICATION_CALLBACK,
-                        "displayId=" + displayId + "; transition=" + transition);
-            }
-            if (DEBUG_WINDOW_TRANSITIONS) {
-                Slog.i(LOG_TAG, "Window transition: "
-                        + AppTransition.appTransitionOldToString(transition)
-                        + " displayId: " + displayId);
-            }
-            final boolean isMagnifierActivated = isFullscreenMagnificationActivated();
-            if (!isMagnifierActivated) {
-                return;
-            }
-            switch (transition) {
-                case WindowManager.TRANSIT_OLD_ACTIVITY_OPEN:
-                case WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN:
-                case WindowManager.TRANSIT_OLD_TASK_OPEN:
-                case WindowManager.TRANSIT_OLD_TASK_TO_FRONT:
-                case WindowManager.TRANSIT_OLD_WALLPAPER_OPEN:
-                case WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE:
-                case WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN: {
-                    mUserContextChangedNotifier.onAppWindowTransition(transition);
-                }
-            }
-        }
-
         void onWMTransition(int displayId, @TransitionType int type, @TransitionFlags int flags) {
             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                 mAccessibilityTracing.logTrace(LOG_TAG + ".onWMTransition",
@@ -734,7 +693,7 @@
             }
             if (DEBUG_WINDOW_TRANSITIONS) {
                 Slog.i(LOG_TAG, "Window transition: "
-                        + AppTransition.appTransitionOldToString(transition)
+                        + WindowManager.transitTypeToString(transition)
                         + " displayId: " + windowState.getDisplayId());
             }
             final boolean isMagnifierActivated = isFullscreenMagnificationActivated();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 199a6d8..3cd4db7 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -673,9 +673,6 @@
     // TODO(b/317000737): Replace it with visibility states lookup.
     int mTransitionChangeFlags;
 
-    /** Whether we need to setup the animation to animate only within the letterbox. */
-    private boolean mNeedsLetterboxedAnimation;
-
     /**
      * @see #currentLaunchCanTurnScreenOn()
      */
@@ -5606,18 +5603,6 @@
         commitVisibility(visible, performLayout, false /* fromTransition */);
     }
 
-    void setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation) {
-        mNeedsLetterboxedAnimation = needsLetterboxedAnimation;
-    }
-
-    boolean isNeedsLetterboxedAnimation() {
-        return mNeedsLetterboxedAnimation;
-    }
-
-    boolean isInLetterboxAnimation() {
-        return mNeedsLetterboxedAnimation && isAnimating();
-    }
-
     /** Updates draw state and shows drawn windows. */
     void commitFinishDrawing(SurfaceControl.Transaction t) {
         boolean committed = false;
@@ -7287,10 +7272,6 @@
                 .setParent(getAnimationLeashParent())
                 .setName(getSurfaceControl() + " - animation-bounds")
                 .setCallsite("ActivityRecord.createAnimationBoundsLayer");
-        if (mNeedsLetterboxedAnimation) {
-            // Needs to be an effect layer to support rounded corners
-            builder.setEffectLayer();
-        }
         final SurfaceControl boundsLayer = builder.build();
         t.show(boundsLayer);
         return boundsLayer;
@@ -7308,11 +7289,6 @@
 
     @Override
     public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) {
-        if (mNeedsLetterboxedAnimation) {
-            updateLetterboxSurfaceIfNeeded(findMainWindow(), t);
-            mNeedsAnimationBoundsLayer = true;
-        }
-
         // If the animation needs to be cropped then an animation bounds layer is created as a
         // child of the root pinned task or animation layer. The leash is then reparented to this
         // new layer.
@@ -7325,17 +7301,6 @@
             t.setLayer(leash, 0);
             t.setLayer(mAnimationBoundsLayer, getLastLayer());
 
-            if (mNeedsLetterboxedAnimation) {
-                final int cornerRadius = mAppCompatController.getLetterboxPolicy()
-                        .getRoundedCornersRadius(findMainWindow());
-
-                final Rect letterboxInnerBounds = new Rect();
-                getLetterboxInnerBounds(letterboxInnerBounds);
-
-                t.setCornerRadius(mAnimationBoundsLayer, cornerRadius)
-                        .setCrop(mAnimationBoundsLayer, letterboxInnerBounds);
-            }
-
             // Reparent leash to animation bounds layer.
             t.reparent(leash, mAnimationBoundsLayer);
         }
@@ -7389,10 +7354,6 @@
         }
 
         mNeedsAnimationBoundsLayer = false;
-        if (mNeedsLetterboxedAnimation) {
-            mNeedsLetterboxedAnimation = false;
-            updateLetterboxSurfaceIfNeeded(findMainWindow(), t);
-        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
index 2162834..cb122f2 100644
--- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java
+++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
@@ -107,8 +107,7 @@
                 && !ActivityManager.isLowRamDeviceStatic(); // Don't support Android Go
         setSnapshotEnabled(snapshotEnabled);
         mSnapshotPersistQueue = persistQueue;
-        mPersistInfoProvider = createPersistInfoProvider(service,
-                Environment::getDataSystemCeDirectory);
+        mPersistInfoProvider = createPersistInfoProvider(service);
         mPersister = new TaskSnapshotPersister(
                 persistQueue,
                 mPersistInfoProvider,
@@ -117,6 +116,11 @@
         initialize(new ActivitySnapshotCache());
     }
 
+    @VisibleForTesting
+    PersistInfoProvider createPersistInfoProvider(WindowManagerService service) {
+        return createPersistInfoProvider(service, Environment::getDataSystemCeDirectory);
+    }
+
     @Override
     protected float initSnapshotScale() {
         final float config = mService.mContext.getResources().getFloat(
diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
index 6873270..27511b2 100644
--- a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
@@ -217,7 +217,7 @@
         }
 
         final boolean shouldShowLetterboxUi =
-                (mActivityRecord.isInLetterboxAnimation() || mActivityRecord.isVisible()
+                (mActivityRecord.isVisible()
                         || mActivityRecord.isVisibleRequested())
                         && mainWindow.areAppWindowBoundsLetterboxed()
                         // Check for FLAG_SHOW_WALLPAPER explicitly instead of using
@@ -360,8 +360,7 @@
                         .mAppCompatController.getReachabilityPolicy();
                 mLetterbox = new Letterbox(() -> mActivityRecord.makeChildSurface(null),
                         mActivityRecord.mWmService.mTransactionFactory,
-                        reachabilityPolicy, letterboxOverrides,
-                        this::getLetterboxParentSurface);
+                        reachabilityPolicy, letterboxOverrides);
                 mActivityRecord.mAppCompatController.getReachabilityPolicy()
                         .setLetterboxInnerBoundsSupplier(mLetterbox::getInnerFrame);
             }
@@ -469,15 +468,6 @@
         public boolean isFullyTransparentBarAllowed(@NonNull Rect rect) {
             return !isRunning() || mLetterbox.notIntersectsOrFullyContains(rect);
         }
-
-        @Nullable
-        private SurfaceControl getLetterboxParentSurface() {
-            if (mActivityRecord.isInLetterboxAnimation()) {
-                return mActivityRecord.getTask().getSurfaceControl();
-            }
-            return mActivityRecord.getSurfaceControl();
-        }
-
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxUtils.java b/services/core/java/com/android/server/wm/AppCompatLetterboxUtils.java
index 83d7cb7..e5b61db 100644
--- a/services/core/java/com/android/server/wm/AppCompatLetterboxUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatLetterboxUtils.java
@@ -36,12 +36,7 @@
             outLetterboxPosition.set(0, 0);
             return;
         }
-        if (activity.isInLetterboxAnimation()) {
-            // In this case we attach the letterbox to the task instead of the activity.
-            activity.getTask().getPosition(outLetterboxPosition);
-        } else {
-            activity.getPosition(outLetterboxPosition);
-        }
+        activity.getPosition(outLetterboxPosition);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
index 8165638..92b91464 100644
--- a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
+++ b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
@@ -58,7 +58,7 @@
     @VisibleForTesting
     @Nullable
     Rect getCropBoundsIfNeeded(@NonNull final WindowState mainWindow) {
-        if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) {
+        if (!requiresRoundedCorners(mainWindow)) {
             // We don't want corner radius on the window.
             // In the case the ActivityRecord requires a letterboxed animation we never want
             // rounded corners on the window because rounded corners are applied at the
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
deleted file mode 100644
index 12d4a21..0000000
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ /dev/null
@@ -1,1587 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.view.WindowManager.LayoutParams;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_RELAUNCH;
-import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
-import static android.view.WindowManager.TRANSIT_OLD_NONE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
-import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_UNSET;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_OPEN;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_RELAUNCH;
-import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-
-import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS_ANIM;
-import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
-import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
-import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
-import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
-
-import android.annotation.ColorInt;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.hardware.HardwareBuffer;
-import android.os.Binder;
-import android.os.Debug;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IRemoteCallback;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.proto.ProtoOutputStream;
-import android.view.AppTransitionAnimationSpec;
-import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.RemoteAnimationAdapter;
-import android.view.WindowManager.TransitionFlags;
-import android.view.WindowManager.TransitionOldType;
-import android.view.WindowManager.TransitionType;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.TranslateAnimation;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.ProtoLog;
-import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.util.DumpUtils.Dump;
-import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.internal.util.function.pooled.PooledPredicate;
-import com.android.server.wm.ActivityRecord.CustomAppTransition;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-// State management of app transitions.  When we are preparing for a
-// transition, mNextAppTransition will be the kind of transition to
-// perform or TRANSIT_NONE if we are not waiting.  If we are waiting,
-// mOpeningApps and mClosingApps are the lists of tokens that will be
-// made visible or hidden at the next transition.
-public class AppTransition implements Dump {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
-
-    static final int DEFAULT_APP_TRANSITION_DURATION = 336;
-
-    /**
-     * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
-     * involved, to make it more understandable.
-     */
-    private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
-    static final int MAX_APP_TRANSITION_DURATION = 3 * 1000; // 3 secs.
-
-    private final Context mContext;
-    private final WindowManagerService mService;
-    private final DisplayContent mDisplayContent;
-
-    @VisibleForTesting
-    final TransitionAnimation mTransitionAnimation;
-
-    private @TransitionFlags int mNextAppTransitionFlags = 0;
-    private final ArrayList<Integer> mNextAppTransitionRequests = new ArrayList<>();
-    private @TransitionOldType int mLastUsedAppTransition = TRANSIT_OLD_UNSET;
-    private String mLastOpeningApp;
-    private String mLastClosingApp;
-    private String mLastChangingApp;
-
-    private static final int NEXT_TRANSIT_TYPE_NONE = 0;
-    private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
-    private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
-    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
-    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
-    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
-    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
-    private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
-    private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
-
-    /**
-     * Refers to the transition to activity started by using {@link
-     * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle)
-     * }.
-     */
-    private static final int NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS = 9;
-    private static final int NEXT_TRANSIT_TYPE_REMOTE = 10;
-
-    private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
-    private boolean mNextAppTransitionOverrideRequested;
-
-    private String mNextAppTransitionPackage;
-    // Used for thumbnail transitions. True if we're scaling up, false if scaling down
-    private boolean mNextAppTransitionScaleUp;
-    private IRemoteCallback mNextAppTransitionCallback;
-    private IRemoteCallback mNextAppTransitionFutureCallback;
-    private IRemoteCallback mAnimationFinishedCallback;
-    private int mNextAppTransitionEnter;
-    private int mNextAppTransitionExit;
-    private @ColorInt int mNextAppTransitionBackgroundColor;
-    private int mNextAppTransitionInPlace;
-    private boolean mNextAppTransitionIsSync;
-
-    // Keyed by WindowContainer hashCode.
-    private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
-            = new SparseArray<>();
-    private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
-    private boolean mNextAppTransitionAnimationsSpecsPending;
-    private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
-
-    private final Rect mTmpRect = new Rect();
-
-    private final static int APP_STATE_IDLE = 0;
-    private final static int APP_STATE_READY = 1;
-    private final static int APP_STATE_RUNNING = 2;
-    private final static int APP_STATE_TIMEOUT = 3;
-    private int mAppTransitionState = APP_STATE_IDLE;
-
-    private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
-    private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
-
-    private final int mDefaultWindowAnimationStyleResId;
-    private boolean mOverrideTaskTransition;
-
-    final Handler mHandler;
-    final Runnable mHandleAppTransitionTimeoutRunnable = () -> handleAppTransitionTimeout();
-
-    AppTransition(Context context, WindowManagerService service, DisplayContent displayContent) {
-        mContext = context;
-        mService = service;
-        mHandler = new Handler(service.mH.getLooper());
-        mDisplayContent = displayContent;
-        mTransitionAnimation = new TransitionAnimation(
-                context, ProtoLog.isEnabled(WM_DEBUG_ANIM, LogLevel.DEBUG), TAG);
-
-        final TypedArray windowStyle = mContext.getTheme().obtainStyledAttributes(
-                com.android.internal.R.styleable.Window);
-        mDefaultWindowAnimationStyleResId = windowStyle.getResourceId(
-                com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
-        windowStyle.recycle();
-    }
-
-    boolean isTransitionSet() {
-        return !mNextAppTransitionRequests.isEmpty();
-    }
-
-    boolean isUnoccluding() {
-        return mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_UNOCCLUDE);
-    }
-
-    boolean transferFrom(AppTransition other) {
-        mNextAppTransitionRequests.addAll(other.mNextAppTransitionRequests);
-        return prepare();
-    }
-
-    void setLastAppTransition(@TransitionOldType int transit, ActivityRecord openingApp,
-            ActivityRecord closingApp, ActivityRecord changingApp) {
-        mLastUsedAppTransition = transit;
-        mLastOpeningApp = "" + openingApp;
-        mLastClosingApp = "" + closingApp;
-        mLastChangingApp = "" + changingApp;
-    }
-
-    boolean isReady() {
-        return mAppTransitionState == APP_STATE_READY
-                || mAppTransitionState == APP_STATE_TIMEOUT;
-    }
-
-    void setReady() {
-        setAppTransitionState(APP_STATE_READY);
-        fetchAppTransitionSpecsFromFuture();
-    }
-
-    boolean isRunning() {
-        return mAppTransitionState == APP_STATE_RUNNING;
-    }
-
-    void setIdle() {
-        setAppTransitionState(APP_STATE_IDLE);
-    }
-
-    boolean isIdle() {
-        return mAppTransitionState == APP_STATE_IDLE;
-    }
-
-    boolean isTimeout() {
-        return mAppTransitionState == APP_STATE_TIMEOUT;
-    }
-
-    void setTimeout() {
-        setAppTransitionState(APP_STATE_TIMEOUT);
-    }
-
-    /**
-     * Gets the animation overridden by app via {@link #overridePendingAppTransition}.
-     */
-    @Nullable
-    Animation getNextAppRequestedAnimation(boolean enter) {
-        final Animation a = mTransitionAnimation.loadAppTransitionAnimation(
-                mNextAppTransitionPackage,
-                enter ? mNextAppTransitionEnter : mNextAppTransitionExit);
-        if (mNextAppTransitionBackgroundColor != 0 && a != null) {
-            a.setBackdropColor(mNextAppTransitionBackgroundColor);
-        }
-        return a;
-    }
-
-    /**
-     * Gets the animation background color overridden by app via
-     * {@link #overridePendingAppTransition}.
-     */
-    @ColorInt int getNextAppTransitionBackgroundColor() {
-        return mNextAppTransitionBackgroundColor;
-    }
-
-    @VisibleForTesting
-    boolean isNextAppTransitionOverrideRequested() {
-        return mNextAppTransitionOverrideRequested;
-    }
-
-    HardwareBuffer getAppTransitionThumbnailHeader(WindowContainer container) {
-        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
-                container.hashCode());
-        if (spec == null) {
-            spec = mDefaultNextAppTransitionAnimationSpec;
-        }
-        return spec != null ? spec.buffer : null;
-    }
-
-    /** Returns whether the next thumbnail transition is aspect scaled up. */
-    boolean isNextThumbnailTransitionAspectScaled() {
-        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-    }
-
-    /** Returns whether the next thumbnail transition is scaling up. */
-    boolean isNextThumbnailTransitionScaleUp() {
-        return mNextAppTransitionScaleUp;
-    }
-
-    boolean isNextAppTransitionThumbnailUp() {
-        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP;
-    }
-
-    boolean isNextAppTransitionThumbnailDown() {
-        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-    }
-
-    boolean isNextAppTransitionOpenCrossProfileApps() {
-        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
-    }
-
-    /**
-     * @return true if and only if we are currently fetching app transition specs from the future
-     *         passed into {@link #overridePendingAppTransitionMultiThumbFuture}
-     */
-    boolean isFetchingAppTransitionsSpecs() {
-        return mNextAppTransitionAnimationsSpecsPending;
-    }
-
-    private boolean prepare() {
-        if (!isRunning()) {
-            setAppTransitionState(APP_STATE_IDLE);
-            notifyAppTransitionPendingLocked();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
-     *         layout pass needs to be done
-     */
-    int goodToGo(@TransitionOldType int transit, ActivityRecord topOpeningApp) {
-        mNextAppTransitionFlags = 0;
-        mNextAppTransitionRequests.clear();
-        setAppTransitionState(APP_STATE_RUNNING);
-        final WindowContainer wc =
-                topOpeningApp != null ? topOpeningApp.getAnimatingContainer() : null;
-        final AnimationAdapter topOpeningAnim = wc != null ? wc.getAnimation() : null;
-
-        int redoLayout = notifyAppTransitionStartingLocked(
-                topOpeningAnim != null
-                        ? topOpeningAnim.getStatusBarTransitionsStartTime()
-                        : SystemClock.uptimeMillis(),
-                AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
-
-        if ((isTaskOpenTransitOld(transit) || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
-                && topOpeningAnim != null) {
-            if (mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()) {
-                final NavBarFadeAnimationController controller =
-                        new NavBarFadeAnimationController(mDisplayContent);
-                // For remote animation case, the nav bar fades out and in is controlled by the
-                // remote side. For non-remote animation case, we play the fade out/in animation
-                // here. We play the nav bar fade-out animation when the app transition animation
-                // starts and play the fade-in animation sequentially once the fade-out is finished.
-                controller.fadeOutAndInSequentially(topOpeningAnim.getDurationHint(),
-                        null /* fadeOutParent */, topOpeningApp.getSurfaceControl());
-            }
-        }
-        return redoLayout;
-    }
-
-    void clear() {
-        clear(true /* clearAppOverride */);
-    }
-
-    private void clear(boolean clearAppOverride) {
-        mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
-        mNextAppTransitionOverrideRequested = false;
-        mNextAppTransitionAnimationsSpecs.clear();
-        mNextAppTransitionAnimationsSpecsFuture = null;
-        mDefaultNextAppTransitionAnimationSpec = null;
-        mAnimationFinishedCallback = null;
-        mOverrideTaskTransition = false;
-        mNextAppTransitionIsSync = false;
-        if (clearAppOverride) {
-            mNextAppTransitionPackage = null;
-            mNextAppTransitionEnter = 0;
-            mNextAppTransitionExit = 0;
-            mNextAppTransitionBackgroundColor = 0;
-        }
-    }
-
-    void freeze() {
-        final boolean keyguardGoingAwayCancelled = mNextAppTransitionRequests.contains(
-                TRANSIT_KEYGUARD_GOING_AWAY);
-
-        mNextAppTransitionRequests.clear();
-        clear();
-        setReady();
-        notifyAppTransitionCancelledLocked(keyguardGoingAwayCancelled);
-    }
-
-    private void setAppTransitionState(int state) {
-        mAppTransitionState = state;
-        updateBooster();
-    }
-
-    /**
-     * Updates whether we currently boost wm locked sections and the animation thread. We want to
-     * boost the priorities to a more important value whenever an app transition is going to happen
-     * soon or an app transition is running.
-     */
-    void updateBooster() {
-        WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning(needsBoosting());
-    }
-
-    private boolean needsBoosting() {
-        return !mNextAppTransitionRequests.isEmpty()
-                || mAppTransitionState == APP_STATE_READY
-                || mAppTransitionState == APP_STATE_RUNNING;
-    }
-
-    void registerListenerLocked(AppTransitionListener listener) {
-        mListeners.add(listener);
-    }
-
-    void unregisterListener(AppTransitionListener listener) {
-        mListeners.remove(listener);
-    }
-
-    public void notifyAppTransitionFinishedLocked(IBinder token) {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionFinishedLocked(token);
-        }
-    }
-
-    private void notifyAppTransitionPendingLocked() {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionPendingLocked();
-        }
-    }
-
-    private void notifyAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionCancelledLocked(keyguardGoingAwayCancelled);
-        }
-    }
-
-    private void notifyAppTransitionTimeoutLocked() {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionTimeoutLocked();
-        }
-    }
-
-    private int notifyAppTransitionStartingLocked(long statusBarAnimationStartTime,
-            long statusBarAnimationDuration) {
-        int redoLayout = 0;
-        for (int i = 0; i < mListeners.size(); i++) {
-            redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(
-                    statusBarAnimationStartTime, statusBarAnimationDuration);
-        }
-        return redoLayout;
-    }
-
-    @VisibleForTesting
-    int getDefaultWindowAnimationStyleResId() {
-        return mDefaultWindowAnimationStyleResId;
-    }
-
-    /** Returns window animation style ID from {@link LayoutParams} or from system in some cases */
-    @VisibleForTesting
-    int getAnimationStyleResId(@NonNull LayoutParams lp) {
-        return mTransitionAnimation.getAnimationStyleResId(lp);
-    }
-
-    @VisibleForTesting
-    @Nullable
-    Animation loadAnimationSafely(Context context, int resId) {
-        return TransitionAnimation.loadAnimationSafely(context, resId, TAG);
-    }
-
-    private static int mapOpenCloseTransitTypes(int transit, boolean enter) {
-        int animAttr = 0;
-        switch (transit) {
-            case TRANSIT_OLD_ACTIVITY_OPEN:
-            case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_activityOpenEnterAnimation
-                        : WindowAnimation_activityOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_ACTIVITY_CLOSE:
-            case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_activityCloseEnterAnimation
-                        : WindowAnimation_activityCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_taskOpenEnterAnimation
-                        : WindowAnimation_taskOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_taskCloseEnterAnimation
-                        : WindowAnimation_taskCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_TO_FRONT:
-                animAttr = enter
-                        ? WindowAnimation_taskToFrontEnterAnimation
-                        : WindowAnimation_taskToFrontExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_TO_BACK:
-                animAttr = enter
-                        ? WindowAnimation_taskToBackEnterAnimation
-                        : WindowAnimation_taskToBackExitAnimation;
-                break;
-            case TRANSIT_OLD_WALLPAPER_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_wallpaperOpenEnterAnimation
-                        : WindowAnimation_wallpaperOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_WALLPAPER_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_wallpaperCloseEnterAnimation
-                        : WindowAnimation_wallpaperCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_WALLPAPER_INTRA_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_wallpaperIntraOpenEnterAnimation
-                        : WindowAnimation_wallpaperIntraOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_WALLPAPER_INTRA_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_wallpaperIntraCloseEnterAnimation
-                        : WindowAnimation_wallpaperIntraCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_OPEN_BEHIND:
-                animAttr = enter
-                        ? WindowAnimation_launchTaskBehindSourceAnimation
-                        : WindowAnimation_launchTaskBehindTargetAnimation;
-                break;
-            // TODO(b/189386466): Use activity transition as the fallback. Investigate if we
-            //  need new TaskFragment transition.
-            case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_activityOpenEnterAnimation
-                        : WindowAnimation_activityOpenExitAnimation;
-                break;
-            // TODO(b/189386466): Use activity transition as the fallback. Investigate if we
-            //  need new TaskFragment transition.
-            case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_activityCloseEnterAnimation
-                        : WindowAnimation_activityCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_DREAM_ACTIVITY_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_dreamActivityOpenEnterAnimation
-                        : WindowAnimation_dreamActivityOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_DREAM_ACTIVITY_CLOSE:
-                animAttr = enter
-                        ? 0
-                        : WindowAnimation_dreamActivityCloseExitAnimation;
-                break;
-        }
-
-        return animAttr;
-    }
-
-    @Nullable
-    Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
-        return mTransitionAnimation.loadAnimationAttr(lp, animAttr, transit);
-    }
-
-    private void getDefaultNextAppTransitionStartRect(Rect rect) {
-        if (mDefaultNextAppTransitionAnimationSpec == null ||
-                mDefaultNextAppTransitionAnimationSpec.rect == null) {
-            Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable());
-            rect.setEmpty();
-        } else {
-            rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
-        }
-    }
-
-    private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
-            HardwareBuffer buffer) {
-        mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
-                buffer, new Rect(left, top, left + width, top + height));
-    }
-
-    /**
-     * Creates an overlay with a background color and a thumbnail for the cross profile apps
-     * animation.
-     */
-    HardwareBuffer createCrossProfileAppsThumbnail(
-            Drawable thumbnailDrawable, Rect frame) {
-        return mTransitionAnimation.createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
-    }
-
-    Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
-        return mTransitionAnimation.createCrossProfileAppsThumbnailAnimationLocked(appRect);
-    }
-
-    /**
-     * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
-     * when a thumbnail is specified with the pending animation override.
-     */
-    Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
-            HardwareBuffer thumbnailHeader, WindowContainer container, int orientation) {
-        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
-                container.hashCode());
-        return mTransitionAnimation.createThumbnailAspectScaleAnimationLocked(appRect,
-                contentInsets, thumbnailHeader, orientation, spec != null ? spec.rect : null,
-                mDefaultNextAppTransitionAnimationSpec != null
-                        ? mDefaultNextAppTransitionAnimationSpec.rect : null,
-                mNextAppTransitionScaleUp);
-    }
-
-    private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
-            Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
-        final float sourceWidth = sourceFrame.width();
-        final float sourceHeight = sourceFrame.height();
-        final float destWidth = destFrame.width();
-        final float destHeight = destFrame.height();
-        final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
-        final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
-        AnimationSet set = new AnimationSet(true);
-        final int surfaceInsetsH = surfaceInsets == null
-                ? 0 : surfaceInsets.left + surfaceInsets.right;
-        final int surfaceInsetsV = surfaceInsets == null
-                ? 0 : surfaceInsets.top + surfaceInsets.bottom;
-        // We want the scaling to happen from the center of the surface. In order to achieve that,
-        // we need to account for surface insets that will be used to enlarge the surface.
-        final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
-        final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
-        final ScaleAnimation scale = enter ?
-                new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
-                : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
-        final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
-        final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
-        final int destHCenter = destFrame.left + destFrame.width() / 2;
-        final int destVCenter = destFrame.top + destFrame.height() / 2;
-        final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
-        final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
-        final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
-                : new TranslateAnimation(0, fromX, 0, fromY);
-        set.addAnimation(scale);
-        set.addAnimation(translation);
-        setAppTransitionFinishedCallbackIfNeeded(set);
-        return set;
-    }
-
-    /**
-     * @return true if and only if the first frame of the transition can be skipped, i.e. the first
-     *         frame of the transition doesn't change the visuals on screen, so we can start
-     *         directly with the second one
-     */
-    boolean canSkipFirstFrame() {
-        return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
-                && !mNextAppTransitionOverrideRequested
-                && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
-                && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
-                && !mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_GOING_AWAY);
-    }
-
-    /**
-     *
-     * @param frame These are the bounds of the window when it finishes the animation. This is where
-     *              the animation must usually finish in entrance animation, as the next frame will
-     *              display the window at these coordinates. In case of exit animation, this is
-     *              where the animation must start, as the frame before the animation is displaying
-     *              the window at these bounds.
-     * @param insets Knowing where the window will be positioned is not enough. Some parts of the
-     *               window might be obscured, usually by the system windows (status bar and
-     *               navigation bar) and we use content insets to convey that information. This
-     *               usually affects the animation aspects vertically, as the system decoration is
-     *               at the top and the bottom. For example when we animate from full screen to
-     *               recents, we want to exclude the covered parts, because they won't match the
-     *               thumbnail after the last frame is executed.
-     * @param surfaceInsets In rare situation the surface is larger than the content and we need to
-     *                      know about this to make the animation frames match. We currently use
-     *                      this for freeform windows, which have larger surfaces to display
-     *                      shadows. When we animate them from recents, we want to match the content
-     *                      to the recents thumbnail and hence need to account for the surface being
-     *                      bigger.
-     */
-    @Nullable
-    Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
-            int orientation, Rect frame, Rect displayFrame, Rect insets,
-            @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
-            boolean freeform, WindowContainer container) {
-
-        final boolean canCustomizeAppTransition = container.canCustomizeAppTransition();
-
-        if (mNextAppTransitionOverrideRequested) {
-            if (canCustomizeAppTransition || mOverrideTaskTransition) {
-                mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
-            } else {
-                ProtoLog.e(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: "
-                        + " override requested, but it is prohibited by policy.");
-            }
-        }
-
-        Animation a;
-        if (isKeyguardGoingAwayTransitOld(transit) && enter) {
-            a = mTransitionAnimation.loadKeyguardExitAnimation(mNextAppTransitionFlags,
-                    transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
-        } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
-                || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM) {
-            a = null;
-        } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE && !enter) {
-            a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
-        } else if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) {
-            a = null;
-        } else if (isVoiceInteraction && (transit == TRANSIT_OLD_ACTIVITY_OPEN
-                || transit == TRANSIT_OLD_TASK_OPEN
-                || transit == TRANSIT_OLD_TASK_TO_FRONT)) {
-            a = mTransitionAnimation.loadVoiceActivityOpenAnimation(enter);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
-                    appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (isVoiceInteraction && (transit == TRANSIT_OLD_ACTIVITY_CLOSE
-                || transit == TRANSIT_OLD_TASK_CLOSE
-                || transit == TRANSIT_OLD_TASK_TO_BACK)) {
-            a = mTransitionAnimation.loadVoiceActivityExitAnimation(enter);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
-                    appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (transit == TRANSIT_OLD_ACTIVITY_RELAUNCH) {
-            a = mTransitionAnimation.createRelaunchAnimation(frame, insets,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s transit=%s Callers=%s", a,
-                    appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
-            a = getNextAppRequestedAnimation(enter);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
-                            + "isEntrance=%b Callers=%s",
-                    a, appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
-            a = mTransitionAnimation.loadAppTransitionAnimation(
-                    mNextAppTransitionPackage, mNextAppTransitionInPlace);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE "
-                            + "transit=%s Callers=%s",
-                    a, appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
-            a = mTransitionAnimation.createClipRevealAnimationLockedCompat(
-                    transit, enter, frame, displayFrame,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL "
-                            + "transit=%s Callers=%s",
-                    a, appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
-            a = mTransitionAnimation.createScaleUpAnimationLockedCompat(transit, enter, frame,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s "
-                            + "isEntrance=%s Callers=%s",
-                    a, appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
-            mNextAppTransitionScaleUp =
-                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
-            final HardwareBuffer thumbnailHeader = getAppTransitionThumbnailHeader(container);
-            a = mTransitionAnimation.createThumbnailEnterExitAnimationLockedCompat(enter,
-                    mNextAppTransitionScaleUp, frame, transit, thumbnailHeader,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
-                            + "Callers=%s",
-                    a,  mNextAppTransitionScaleUp
-                            ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN",
-                    appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
-            mNextAppTransitionScaleUp =
-                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
-            AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
-                    container.hashCode());
-            a = mTransitionAnimation.createAspectScaledThumbnailEnterExitAnimationLocked(enter,
-                    mNextAppTransitionScaleUp, orientation, transit, frame, insets, surfaceInsets,
-                    stableInsets, freeform, spec != null ? spec.rect : null,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
-                            + "Callers=%s",
-                    a, mNextAppTransitionScaleUp
-                            ? "ANIM_THUMBNAIL_ASPECT_SCALE_UP"
-                        : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN",
-                    appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
-            a = mTransitionAnimation.loadCrossProfileAppEnterAnimation();
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: "
-                            + "anim=%s transit=%s isEntrance=true Callers=%s",
-                    a, appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (isChangeTransitOld(transit)) {
-            // In the absence of a specific adapter, we just want to keep everything stationary.
-            a = new AlphaAnimation(1.f, 1.f);
-            a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
-                    a, appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else {
-            int animAttr = mapOpenCloseTransitTypes(transit, enter);
-            if (animAttr != 0) {
-                final CustomAppTransition customAppTransition =
-                        getCustomAppTransition(animAttr, container);
-                if (customAppTransition != null) {
-                    a = loadCustomActivityAnimation(customAppTransition, enter, container);
-                } else {
-                    if (canCustomizeAppTransition) {
-                        a = loadAnimationAttr(lp, animAttr, transit);
-                    } else {
-                        a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit);
-                    }
-                }
-            } else {
-                a = null;
-            }
-
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
-                            + " canCustomizeAppTransition=%b Callers=%s",
-                    a, animAttr, appTransitionOldToString(transit), enter,
-                    canCustomizeAppTransition, Debug.getCallers(3));
-        }
-        setAppTransitionFinishedCallbackIfNeeded(a);
-
-        return a;
-    }
-
-    CustomAppTransition getCustomAppTransition(int animAttr, WindowContainer container) {
-        ActivityRecord customAnimationSource = container.asActivityRecord();
-        if (customAnimationSource == null) {
-            return null;
-        }
-
-        // Only top activity can customize activity animation.
-        // If the animation is for the one below, try to get from the above activity.
-        if (animAttr == WindowAnimation_activityOpenExitAnimation
-                || animAttr == WindowAnimation_activityCloseEnterAnimation) {
-            customAnimationSource = customAnimationSource.getTask()
-                    .getActivityAbove(customAnimationSource);
-            if (customAnimationSource == null) {
-                return null;
-            }
-        }
-        switch (animAttr) {
-            case WindowAnimation_activityOpenEnterAnimation:
-            case WindowAnimation_activityOpenExitAnimation:
-                return customAnimationSource.getCustomAnimation(true /* open */);
-            case WindowAnimation_activityCloseEnterAnimation:
-            case WindowAnimation_activityCloseExitAnimation:
-                return customAnimationSource.getCustomAnimation(false /* open */);
-        }
-        return null;
-    }
-    private Animation loadCustomActivityAnimation(@NonNull CustomAppTransition custom,
-            boolean enter, WindowContainer container) {
-        final ActivityRecord customAnimationSource = container.asActivityRecord();
-        final Animation a = mTransitionAnimation.loadAppTransitionAnimation(
-                customAnimationSource.packageName, enter
-                        ? custom.mEnterAnim : custom.mExitAnim);
-        if (a != null && custom.mBackgroundColor != 0) {
-            a.setBackdropColor(custom.mBackgroundColor);
-            a.setShowBackdrop(true);
-        }
-        return a;
-    }
-
-    int getAppRootTaskClipMode() {
-        return mNextAppTransitionRequests.contains(TRANSIT_RELAUNCH)
-                || mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_GOING_AWAY)
-                || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
-                ? ROOT_TASK_CLIP_NONE
-                : ROOT_TASK_CLIP_AFTER_ANIM;
-    }
-
-    @TransitionFlags
-    public int getTransitFlags() {
-        return mNextAppTransitionFlags;
-    }
-
-    void postAnimationCallback() {
-        if (mNextAppTransitionCallback != null) {
-            mHandler.sendMessage(PooledLambda.obtainMessage(AppTransition::doAnimationCallback,
-                    mNextAppTransitionCallback));
-            mNextAppTransitionCallback = null;
-        }
-    }
-
-    void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
-            @ColorInt int backgroundColor, IRemoteCallback startedCallback,
-            IRemoteCallback endedCallback, boolean overrideTaskTransaction) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionOverrideRequested = true;
-            mNextAppTransitionPackage = packageName;
-            mNextAppTransitionEnter = enterAnim;
-            mNextAppTransitionExit = exitAnim;
-            mNextAppTransitionBackgroundColor = backgroundColor;
-            postAnimationCallback();
-            mNextAppTransitionCallback = startedCallback;
-            mAnimationFinishedCallback = endedCallback;
-            mOverrideTaskTransition = overrideTaskTransaction;
-        }
-    }
-
-    void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
-            int startHeight) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
-            putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
-            postAnimationCallback();
-        }
-    }
-
-    void overridePendingAppTransitionClipReveal(int startX, int startY,
-                                                int startWidth, int startHeight) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
-            putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
-            postAnimationCallback();
-        }
-    }
-
-    void overridePendingAppTransitionThumb(HardwareBuffer srcThumb, int startX, int startY,
-                                           IRemoteCallback startedCallback, boolean scaleUp) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
-                    : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
-            mNextAppTransitionScaleUp = scaleUp;
-            putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
-            postAnimationCallback();
-            mNextAppTransitionCallback = startedCallback;
-        }
-    }
-
-    void overridePendingAppTransitionAspectScaledThumb(HardwareBuffer srcThumb, int startX,
-            int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
-            boolean scaleUp) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
-                    : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-            mNextAppTransitionScaleUp = scaleUp;
-            putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
-                    srcThumb);
-            postAnimationCallback();
-            mNextAppTransitionCallback = startedCallback;
-        }
-    }
-
-    void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
-            IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
-            boolean scaleUp) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
-                    : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-            mNextAppTransitionScaleUp = scaleUp;
-            if (specs != null) {
-                for (int i = 0; i < specs.length; i++) {
-                    AppTransitionAnimationSpec spec = specs[i];
-                    if (spec != null) {
-                        final PooledPredicate p = PooledLambda.obtainPredicate(
-                                Task::isTaskId, PooledLambda.__(Task.class), spec.taskId);
-                        final WindowContainer container = mDisplayContent.getTask(p);
-                        p.recycle();
-                        if (container == null) {
-                            continue;
-                        }
-                        mNextAppTransitionAnimationsSpecs.put(container.hashCode(), spec);
-                        if (i == 0) {
-                            // In full screen mode, the transition code depends on the default spec
-                            // to be set.
-                            Rect rect = spec.rect;
-                            putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
-                                    rect.width(), rect.height(), spec.buffer);
-                        }
-                    }
-                }
-            }
-            postAnimationCallback();
-            mNextAppTransitionCallback = onAnimationStartedCallback;
-            mAnimationFinishedCallback = onAnimationFinishedCallback;
-        }
-    }
-
-    void overridePendingAppTransitionMultiThumbFuture(
-            IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
-            boolean scaleUp) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
-                    : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-            mNextAppTransitionAnimationsSpecsFuture = specsFuture;
-            mNextAppTransitionScaleUp = scaleUp;
-            mNextAppTransitionFutureCallback = callback;
-            if (isReady()) {
-                fetchAppTransitionSpecsFromFuture();
-            }
-        }
-    }
-
-    void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) {
-        overridePendingAppTransitionRemote(remoteAnimationAdapter, false /* sync */,
-                false /* isActivityEmbedding*/);
-    }
-
-    void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter,
-            boolean sync, boolean isActivityEmbedding) {
-    }
-
-    void overrideInPlaceAppTransition(String packageName, int anim) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
-            mNextAppTransitionPackage = packageName;
-            mNextAppTransitionInPlace = anim;
-        }
-    }
-
-    /**
-     * @see {@link #NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS}
-     */
-    void overridePendingAppTransitionStartCrossProfileApps() {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
-            postAnimationCallback();
-        }
-    }
-
-    private boolean canOverridePendingAppTransition() {
-        // Remote animations always take precedence
-        return isTransitionSet() &&  mNextAppTransitionType != NEXT_TRANSIT_TYPE_REMOTE;
-    }
-
-    /**
-     * If a future is set for the app transition specs, fetch it in another thread.
-     */
-    private void fetchAppTransitionSpecsFromFuture() {
-        if (mNextAppTransitionAnimationsSpecsFuture != null) {
-            mNextAppTransitionAnimationsSpecsPending = true;
-            final IAppTransitionAnimationSpecsFuture future
-                    = mNextAppTransitionAnimationsSpecsFuture;
-            mNextAppTransitionAnimationsSpecsFuture = null;
-            mDefaultExecutor.execute(() -> {
-                AppTransitionAnimationSpec[] specs = null;
-                try {
-                    Binder.allowBlocking(future.asBinder());
-                    specs = future.get();
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed to fetch app transition specs: " + e);
-                }
-                synchronized (mService.mGlobalLock) {
-                    mNextAppTransitionAnimationsSpecsPending = false;
-                    overridePendingAppTransitionMultiThumb(specs,
-                            mNextAppTransitionFutureCallback, null /* finishedCallback */,
-                            mNextAppTransitionScaleUp);
-                    mNextAppTransitionFutureCallback = null;
-                    mService.requestTraversal();
-                }
-            });
-        }
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("mNextAppTransitionRequests=[");
-
-        boolean separator = false;
-        for (Integer transit : mNextAppTransitionRequests) {
-            if (separator) {
-                sb.append(", ");
-            }
-            sb.append(appTransitionToString(transit));
-            separator = true;
-        }
-        sb.append("]");
-        sb.append(", mNextAppTransitionFlags="
-                + appTransitionFlagsToString(mNextAppTransitionFlags));
-        return sb.toString();
-    }
-
-    /**
-     * Returns the human readable name of a old window transition.
-     *
-     * @param transition The old window transition.
-     * @return The transition symbolic name.
-     */
-    public static String appTransitionOldToString(@TransitionOldType int transition) {
-        switch (transition) {
-            case TRANSIT_OLD_UNSET: {
-                return "TRANSIT_OLD_UNSET";
-            }
-            case TRANSIT_OLD_NONE: {
-                return "TRANSIT_OLD_NONE";
-            }
-            case TRANSIT_OLD_ACTIVITY_OPEN: {
-                return "TRANSIT_OLD_ACTIVITY_OPEN";
-            }
-            case TRANSIT_OLD_ACTIVITY_CLOSE: {
-                return "TRANSIT_OLD_ACTIVITY_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_OPEN: {
-                return "TRANSIT_OLD_TASK_OPEN";
-            }
-            case TRANSIT_OLD_TASK_CLOSE: {
-                return "TRANSIT_OLD_TASK_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_TO_FRONT: {
-                return "TRANSIT_OLD_TASK_TO_FRONT";
-            }
-            case TRANSIT_OLD_TASK_TO_BACK: {
-                return "TRANSIT_OLD_TASK_TO_BACK";
-            }
-            case TRANSIT_OLD_WALLPAPER_CLOSE: {
-                return "TRANSIT_OLD_WALLPAPER_CLOSE";
-            }
-            case TRANSIT_OLD_WALLPAPER_OPEN: {
-                return "TRANSIT_OLD_WALLPAPER_OPEN";
-            }
-            case TRANSIT_OLD_WALLPAPER_INTRA_OPEN: {
-                return "TRANSIT_OLD_WALLPAPER_INTRA_OPEN";
-            }
-            case TRANSIT_OLD_WALLPAPER_INTRA_CLOSE: {
-                return "TRANSIT_OLD_WALLPAPER_INTRA_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_OPEN_BEHIND: {
-                return "TRANSIT_OLD_TASK_OPEN_BEHIND";
-            }
-            case TRANSIT_OLD_ACTIVITY_RELAUNCH: {
-                return "TRANSIT_OLD_ACTIVITY_RELAUNCH";
-            }
-            case TRANSIT_OLD_KEYGUARD_GOING_AWAY: {
-                return "TRANSIT_OLD_KEYGUARD_GOING_AWAY";
-            }
-            case TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
-                return "TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
-            }
-            case TRANSIT_OLD_KEYGUARD_OCCLUDE: {
-                return "TRANSIT_OLD_KEYGUARD_OCCLUDE";
-            }
-            case TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM: {
-                return "TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM";
-            }
-            case TRANSIT_OLD_KEYGUARD_UNOCCLUDE: {
-                return "TRANSIT_OLD_KEYGUARD_UNOCCLUDE";
-            }
-            case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN: {
-                return "TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN";
-            }
-            case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE: {
-                return "TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE";
-            }
-            case TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE: {
-                return "TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_FRAGMENT_OPEN: {
-                return "TRANSIT_OLD_TASK_FRAGMENT_OPEN";
-            }
-            case TRANSIT_OLD_TASK_FRAGMENT_CLOSE: {
-                return "TRANSIT_OLD_TASK_FRAGMENT_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_FRAGMENT_CHANGE: {
-                return "TRANSIT_OLD_TASK_FRAGMENT_CHANGE";
-            }
-            case TRANSIT_OLD_DREAM_ACTIVITY_OPEN: {
-                return "TRANSIT_OLD_DREAM_ACTIVITY_OPEN";
-            }
-            case TRANSIT_OLD_DREAM_ACTIVITY_CLOSE: {
-                return "TRANSIT_OLD_DREAM_ACTIVITY_CLOSE";
-            }
-            default: {
-                return "<UNKNOWN: " + transition + ">";
-            }
-        }
-    }
-
-    /**
-     * Returns the human readable name of a window transition.
-     *
-     * @param transition The window transition.
-     * @return The transition symbolic name.
-     */
-    public static String appTransitionToString(@TransitionType int transition) {
-        switch (transition) {
-            case TRANSIT_NONE: {
-                return "TRANSIT_NONE";
-            }
-            case TRANSIT_OPEN: {
-                return "TRANSIT_OPEN";
-            }
-            case TRANSIT_CLOSE: {
-                return "TRANSIT_CLOSE";
-            }
-            case TRANSIT_TO_FRONT: {
-                return "TRANSIT_TO_FRONT";
-            }
-            case TRANSIT_TO_BACK: {
-                return "TRANSIT_TO_BACK";
-            }
-            case TRANSIT_RELAUNCH: {
-                return "TRANSIT_RELAUNCH";
-            }
-            case TRANSIT_CHANGE: {
-                return "TRANSIT_CHANGE";
-            }
-            case TRANSIT_KEYGUARD_GOING_AWAY: {
-                return "TRANSIT_KEYGUARD_GOING_AWAY";
-            }
-            case TRANSIT_KEYGUARD_OCCLUDE: {
-                return "TRANSIT_KEYGUARD_OCCLUDE";
-            }
-            case TRANSIT_KEYGUARD_UNOCCLUDE: {
-                return "TRANSIT_KEYGUARD_UNOCCLUDE";
-            }
-            default: {
-                return "<UNKNOWN: " + transition + ">";
-            }
-        }
-    }
-
-    private String appStateToString() {
-        switch (mAppTransitionState) {
-            case APP_STATE_IDLE:
-                return "APP_STATE_IDLE";
-            case APP_STATE_READY:
-                return "APP_STATE_READY";
-            case APP_STATE_RUNNING:
-                return "APP_STATE_RUNNING";
-            case APP_STATE_TIMEOUT:
-                return "APP_STATE_TIMEOUT";
-            default:
-                return "unknown state=" + mAppTransitionState;
-        }
-    }
-
-    private String transitTypeToString() {
-        switch (mNextAppTransitionType) {
-            case NEXT_TRANSIT_TYPE_NONE:
-                return "NEXT_TRANSIT_TYPE_NONE";
-            case NEXT_TRANSIT_TYPE_CUSTOM:
-                return "NEXT_TRANSIT_TYPE_CUSTOM";
-            case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
-                return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
-            case NEXT_TRANSIT_TYPE_SCALE_UP:
-                return "NEXT_TRANSIT_TYPE_SCALE_UP";
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
-                return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
-                return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
-                return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
-                return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
-            case NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:
-                return "NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS";
-            default:
-                return "unknown type=" + mNextAppTransitionType;
-        }
-    }
-
-    private static final ArrayList<Pair<Integer, String>> sFlagToString;
-
-    static {
-        sFlagToString = new ArrayList<>();
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION"));
-        sFlagToString.add(new Pair<>(
-                TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_WITH_IN_WINDOW_ANIMATIONS"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_APP_CRASHED,
-                "TRANSIT_FLAG_APP_CRASHED"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_OPEN_BEHIND,
-                "TRANSIT_FLAG_OPEN_BEHIND"));
-    }
-
-    /**
-     * Returns the human readable names of transit flags.
-     *
-     * @param flags a bitmask combination of transit flags.
-     * @return The combination of symbolic names.
-     */
-    public static String appTransitionFlagsToString(int flags) {
-        String sep = "";
-        StringBuilder sb = new StringBuilder();
-        for (Pair<Integer, String> pair : sFlagToString) {
-            if ((flags & pair.first) != 0) {
-                sb.append(sep);
-                sb.append(pair.second);
-                sep = " | ";
-            }
-        }
-        return sb.toString();
-    }
-
-    void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-        proto.write(APP_TRANSITION_STATE, mAppTransitionState);
-        proto.write(LAST_USED_APP_TRANSITION, mLastUsedAppTransition);
-        proto.end(token);
-    }
-
-    @Override
-    public void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.println(this);
-        pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
-        if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
-            pw.print(prefix); pw.print("mNextAppTransitionType=");
-                    pw.println(transitTypeToString());
-        }
-        if (mNextAppTransitionOverrideRequested
-                || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
-            pw.print(prefix); pw.print("mNextAppTransitionPackage=");
-            pw.println(mNextAppTransitionPackage);
-            pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
-            pw.print(Integer.toHexString(mNextAppTransitionEnter));
-            pw.print(" mNextAppTransitionExit=0x");
-            pw.println(Integer.toHexString(mNextAppTransitionExit));
-            pw.print(" mNextAppTransitionBackgroundColor=0x");
-            pw.println(Integer.toHexString(mNextAppTransitionBackgroundColor));
-        }
-        switch (mNextAppTransitionType) {
-            case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
-                pw.print(prefix); pw.print("mNextAppTransitionPackage=");
-                        pw.println(mNextAppTransitionPackage);
-                pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
-                        pw.print(Integer.toHexString(mNextAppTransitionInPlace));
-                break;
-            case NEXT_TRANSIT_TYPE_SCALE_UP: {
-                getDefaultNextAppTransitionStartRect(mTmpRect);
-                pw.print(prefix); pw.print("mNextAppTransitionStartX=");
-                        pw.print(mTmpRect.left);
-                        pw.print(" mNextAppTransitionStartY=");
-                        pw.println(mTmpRect.top);
-                pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
-                        pw.print(mTmpRect.width());
-                        pw.print(" mNextAppTransitionStartHeight=");
-                        pw.println(mTmpRect.height());
-                break;
-            }
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
-                pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
-                        pw.println(mDefaultNextAppTransitionAnimationSpec);
-                pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
-                        pw.println(mNextAppTransitionAnimationsSpecs);
-                pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
-                        pw.println(mNextAppTransitionScaleUp);
-                break;
-            }
-        }
-        if (mNextAppTransitionCallback != null) {
-            pw.print(prefix); pw.print("mNextAppTransitionCallback=");
-                    pw.println(mNextAppTransitionCallback);
-        }
-        if (mLastUsedAppTransition != TRANSIT_OLD_NONE) {
-            pw.print(prefix); pw.print("mLastUsedAppTransition=");
-                    pw.println(appTransitionOldToString(mLastUsedAppTransition));
-            pw.print(prefix); pw.print("mLastOpeningApp=");
-                    pw.println(mLastOpeningApp);
-            pw.print(prefix); pw.print("mLastClosingApp=");
-                    pw.println(mLastClosingApp);
-            pw.print(prefix); pw.print("mLastChangingApp=");
-            pw.println(mLastChangingApp);
-        }
-    }
-
-    boolean prepareAppTransition(@TransitionType int transit, @TransitionFlags int flags) {
-        if (WindowManagerService.sEnableShellTransitions) {
-            return false;
-        }
-        mNextAppTransitionRequests.add(transit);
-        mNextAppTransitionFlags |= flags;
-        updateBooster();
-        removeAppTransitionTimeoutCallbacks();
-        mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable,
-                APP_TRANSITION_TIMEOUT_MS);
-        return prepare();
-    }
-
-    /**
-     * @return true if {@param transit} is representing a transition in which Keyguard is going
-     *         away, false otherwise
-     */
-    public static boolean isKeyguardGoingAwayTransitOld(int transit) {
-        return transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
-                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-    }
-
-    static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
-                || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM
-                || transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
-    }
-
-    static boolean isKeyguardTransitOld(@TransitionOldType int transit) {
-        return isKeyguardGoingAwayTransitOld(transit) || isKeyguardOccludeTransitOld(transit);
-    }
-
-    static boolean isTaskTransitOld(@TransitionOldType int transit) {
-        return isTaskOpenTransitOld(transit)
-                || isTaskCloseTransitOld(transit);
-    }
-
-    static boolean isTaskCloseTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_CLOSE
-                || transit == TRANSIT_OLD_TASK_TO_BACK;
-    }
-
-    private static  boolean isTaskOpenTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_OPEN
-                || transit == TRANSIT_OLD_TASK_OPEN_BEHIND
-                || transit == TRANSIT_OLD_TASK_TO_FRONT;
-    }
-
-    static boolean isActivityTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_ACTIVITY_OPEN
-                || transit == TRANSIT_OLD_ACTIVITY_CLOSE
-                || transit == TRANSIT_OLD_ACTIVITY_RELAUNCH;
-    }
-
-    static boolean isTaskFragmentTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_FRAGMENT_OPEN
-                || transit == TRANSIT_OLD_TASK_FRAGMENT_CLOSE
-                || transit == TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-    }
-
-    static boolean isChangeTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE
-                || transit == TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-    }
-
-    static boolean isClosingTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_ACTIVITY_CLOSE
-                || transit == TRANSIT_OLD_TASK_CLOSE
-                || transit == TRANSIT_OLD_WALLPAPER_CLOSE
-                || transit == TRANSIT_OLD_WALLPAPER_INTRA_CLOSE
-                || transit == TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE
-                || transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
-    }
-
-    static boolean isNormalTransit(@TransitionType int transit) {
-        return transit == TRANSIT_OPEN
-                || transit == TRANSIT_CLOSE
-                || transit == TRANSIT_TO_FRONT
-                || transit == TRANSIT_TO_BACK;
-    }
-
-    static boolean isKeyguardTransit(@TransitionType int transit) {
-        return transit == TRANSIT_KEYGUARD_GOING_AWAY
-                || transit == TRANSIT_KEYGUARD_OCCLUDE
-                || transit == TRANSIT_KEYGUARD_UNOCCLUDE;
-    }
-
-    @TransitionType int getKeyguardTransition() {
-        if (mNextAppTransitionRequests.indexOf(TRANSIT_KEYGUARD_GOING_AWAY) != -1) {
-            return TRANSIT_KEYGUARD_GOING_AWAY;
-        }
-        final int unoccludeIndex = mNextAppTransitionRequests.indexOf(TRANSIT_KEYGUARD_UNOCCLUDE);
-        final int occludeIndex = mNextAppTransitionRequests.indexOf(TRANSIT_KEYGUARD_OCCLUDE);
-        // No keyguard related transition requests.
-        if (unoccludeIndex == -1 && occludeIndex == -1) {
-            return TRANSIT_NONE;
-        }
-        // In case we unocclude Keyguard and occlude it again, meaning that we never actually
-        // unoccclude/occlude Keyguard, but just run a normal transition.
-        if (unoccludeIndex != -1 && unoccludeIndex < occludeIndex) {
-            return TRANSIT_NONE;
-        }
-        return unoccludeIndex != -1 ? TRANSIT_KEYGUARD_UNOCCLUDE : TRANSIT_KEYGUARD_OCCLUDE;
-    }
-
-    @TransitionType int getFirstAppTransition() {
-        for (int i = 0; i < mNextAppTransitionRequests.size(); ++i) {
-            final @TransitionType int transit = mNextAppTransitionRequests.get(i);
-            if (transit != TRANSIT_NONE && !isKeyguardTransit(transit)) {
-                return transit;
-            }
-        }
-        return TRANSIT_NONE;
-    }
-
-    boolean containsTransitRequest(@TransitionType int transit) {
-        return mNextAppTransitionRequests.contains(transit);
-    }
-
-    private void handleAppTransitionTimeout() {
-    }
-
-    private static void doAnimationCallback(@NonNull IRemoteCallback callback) {
-        try {
-            ((IRemoteCallback) callback).sendResult(null);
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void setAppTransitionFinishedCallbackIfNeeded(Animation anim) {
-        final IRemoteCallback callback = mAnimationFinishedCallback;
-        if (callback != null && anim != null) {
-            anim.setAnimationListener(new Animation.AnimationListener() {
-                @Override
-                public void onAnimationStart(Animation animation) { }
-
-                @Override
-                public void onAnimationEnd(Animation animation) {
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            AppTransition::doAnimationCallback, callback));
-                }
-
-                @Override
-                public void onAnimationRepeat(Animation animation) { }
-            });
-        }
-    }
-
-    void removeAppTransitionTimeoutCallbacks() {
-        mHandler.removeCallbacks(mHandleAppTransitionTimeoutRunnable);
-    }
-}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index e9d9ace..e9b7649 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -691,8 +691,8 @@
             return false;
         }
         if (window.mAttrs.windowAnimations != 0) {
-            final TransitionAnimation transitionAnimation = window.getDisplayContent()
-                    .mAppTransition.mTransitionAnimation;
+            final TransitionAnimation transitionAnimation = window.mDisplayContent
+                    .mTransitionAnimation;
             final int attr = com.android.internal.R.styleable
                     .WindowAnimation_activityCloseExitAnimation;
             final int appResId = transitionAnimation.getAnimationResId(
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 36686fc..2287a68 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -288,9 +288,10 @@
     }
 
     private boolean isHomeApp(int uid, @Nullable String packageName) {
-        if (getService().mHomeProcess != null) {
-            // Fast check
-            return uid == getService().mHomeProcess.mUid;
+        WindowProcessController homeProcess = getService().mHomeProcess;
+        if (homeProcess != null && (homeProcess.mUid != SYSTEM_UID || packageName == null)) {
+            // Fast check (skip if sharing system UID and we have a package name)
+            return uid == homeProcess.mUid;
         }
         if (packageName == null) {
             return false;
diff --git a/services/core/java/com/android/server/wm/BaseAppSnapshotPersister.java b/services/core/java/com/android/server/wm/BaseAppSnapshotPersister.java
index 5db02df..aaa5a00 100644
--- a/services/core/java/com/android/server/wm/BaseAppSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/BaseAppSnapshotPersister.java
@@ -16,10 +16,20 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.AbsAppSnapshotController.TAG;
+
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.window.TaskSnapshot;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
+
 import java.io.File;
+import java.util.UUID;
 
 class BaseAppSnapshotPersister {
     static final String LOW_RES_FILE_POSTFIX = "_reduced";
@@ -29,6 +39,7 @@
     // Shared with SnapshotPersistQueue
     protected final Object mLock;
     protected final SnapshotPersistQueue mSnapshotPersistQueue;
+    @VisibleForTesting
     protected final PersistInfoProvider mPersistInfoProvider;
 
     BaseAppSnapshotPersister(SnapshotPersistQueue persistQueue,
@@ -79,6 +90,8 @@
         private final boolean mEnableLowResSnapshots;
         private final float mLowResScaleFactor;
         private final boolean mUse16BitFormat;
+        private final SparseBooleanArray mInitializedUsers = new SparseBooleanArray();
+        private final SparseArray<File> mScrambleDirectories = new SparseArray<>();
 
         PersistInfoProvider(DirectoryResolver directoryResolver, String dirName,
                 boolean enableLowResSnapshots, float lowResScaleFactor, boolean use16BitFormat) {
@@ -91,9 +104,80 @@
 
         @NonNull
         File getDirectory(int userId) {
+            if (Flags.scrambleSnapshotFileName()) {
+                final File directory = getOrInitScrambleDirectory(userId);
+                if (directory != null) {
+                    return directory;
+                }
+            }
+            return getBaseDirectory(userId);
+        }
+
+        @NonNull
+        private File getBaseDirectory(int userId) {
             return new File(mDirectoryResolver.getSystemDirectoryForUser(userId), mDirName);
         }
 
+        @Nullable
+        private File getOrInitScrambleDirectory(int userId) {
+            synchronized (mScrambleDirectories) {
+                if (mInitializedUsers.get(userId)) {
+                    return mScrambleDirectories.get(userId);
+                }
+                mInitializedUsers.put(userId, true);
+                final File scrambledDirectory = getScrambleDirectory(userId);
+                final File baseDir = getBaseDirectory(userId);
+                String newName = null;
+                // If directory exists, rename
+                if (scrambledDirectory.exists()) {
+                    newName = UUID.randomUUID().toString();
+                    final File scrambleTo = new File(baseDir, newName);
+                    if (!scrambledDirectory.renameTo(scrambleTo)) {
+                        Slog.w(TAG, "SnapshotPersister rename scramble folder fail.");
+                        return null;
+                    }
+                } else {
+                    // If directory not exists, mkDir.
+                    if (!baseDir.exists() && !baseDir.mkdir()) {
+                        Slog.w(TAG, "SnapshotPersister make base folder fail.");
+                        return null;
+                    }
+                    if (!scrambledDirectory.mkdir()) {
+                        Slog.e(TAG, "SnapshotPersister make scramble folder fail");
+                        return null;
+                    }
+                    // Move any existing files to this folder.
+                    final String[] files = baseDir.list();
+                    if (files != null) {
+                        for (String file : files) {
+                            final File original = new File(baseDir, file);
+                            if (original.isDirectory()) {
+                                newName = file;
+                            } else {
+                                File to = new File(scrambledDirectory, file);
+                                original.renameTo(to);
+                            }
+                        }
+                    }
+                }
+                final File newFolder = new File(baseDir, newName);
+                mScrambleDirectories.put(userId, newFolder);
+                return newFolder;
+            }
+        }
+
+        @NonNull
+        private File getScrambleDirectory(int userId) {
+            final File dir = getBaseDirectory(userId);
+            final String[] directories = dir.list(
+                    (current, name) -> new File(current, name).isDirectory());
+            if (directories != null && directories.length > 0) {
+                return new File(dir, directories[0]);
+            } else {
+                return new File(dir, UUID.randomUUID().toString());
+            }
+        }
+
         /**
          * Return if task snapshots are stored in 16 bit pixel format.
          *
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index dc42b32..d91fca9 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.Flags.enableConnectedDisplaysWallpaper;
+import static android.window.DesktopExperienceFlags.ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -66,7 +67,7 @@
      * Return {@code true} if the current device can hosts desktop sessions on its internal display.
      */
     @VisibleForTesting
-    static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
+    private static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
         return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
     }
 
@@ -83,8 +84,11 @@
         if (!shouldEnforceDeviceRestrictions()) {
             return true;
         }
-        final boolean desktopModeSupported = isDesktopModeSupported(context)
-                && canInternalDisplayHostDesktops(context);
+        // If projected display is enabled, #canInternalDisplayHostDesktops is no longer a
+        // requirement.
+        final boolean desktopModeSupported = ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE.isTrue()
+                ? isDesktopModeSupported(context) : (isDesktopModeSupported(context)
+                && canInternalDisplayHostDesktops(context));
         final boolean desktopModeSupportedByDevOptions =
                 Flags.enableDesktopModeThroughDevOption()
                         && isDesktopModeDevOptionsSupported(context);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eb6b145..353ccd5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -99,7 +99,6 @@
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WALLPAPER;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_SHOW_TRANSACTIONS;
 import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN;
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -247,6 +246,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.policy.TransitionAnimation;
 import com.android.internal.protolog.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -364,7 +364,8 @@
     private boolean mTmpInitial;
     private int mMaxUiWidth = 0;
 
-    final AppTransition mAppTransition;
+    // TODO(b/400335290): extract the needed methods and remove this field.
+    final TransitionAnimation mTransitionAnimation;
 
     final UnknownAppVisibilityController mUnknownAppVisibilityController;
 
@@ -1179,7 +1180,7 @@
         mHoldScreenWakeLock.setReferenceCounted(false);
 
         mFixedRotationTransitionListener = new FixedRotationTransitionListener(mDisplayId);
-        mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
+        mTransitionAnimation = new TransitionAnimation(mWmService.mContext, false /* debug */, TAG);
         mTransitionController.registerLegacyListener(mFixedRotationTransitionListener);
         mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
         mRemoteDisplayChangeController = new RemoteDisplayChangeController(this);
@@ -3257,16 +3258,15 @@
     }
 
     void onDisplayInfoChangeApplied() {
-        if (!enableDisplayContentModeManagement()) {
+        if (!DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
             Slog.e(TAG, "ShouldShowSystemDecors shouldn't be updated when the flag is off.");
         }
 
-        final boolean shouldShowContent;
         if (!allowContentModeSwitch()) {
             return;
         }
-        shouldShowContent = mDisplay.canHostTasks();
 
+        final boolean shouldShowContent = mDisplay.canHostTasks();
         if (shouldShowContent == mWmService.mDisplayWindowSettings
                 .shouldShowSystemDecorsLocked(this)) {
             return;
@@ -3276,9 +3276,21 @@
         if (!shouldShowContent) {
             clearAllTasksOnDisplay(null /* clearTasksCallback */, false /* isRemovingDisplay */);
         }
+
+        // If the display is allowed to show content, then it belongs to the display topology;
+        // vice versa.
+        mWmService.mDisplayManagerInternal.onDisplayBelongToTopologyChanged(mDisplayId,
+                /* inTopology= */ shouldShowContent);
     }
 
      /**
+      * Whether the display is allowed to switch the content mode between extended and mirroring.
+      * If the content mode is extended, the display will start home activity and show system
+      * decorations, such as wallpapaer, status bar and navigation bar.
+      * If the content mode is mirroring, the display will not show home activity or system
+      * decorations.
+      * The content mode is switched when {@link Display#canHostTasks()} changes.
+      *
       * Note that we only allow displays that are able to show system decorations to use the content
       * mode switch; however, not all displays that are able to show system decorations are allowed
       * to use the content mode switch.
@@ -3294,6 +3306,10 @@
             return false;
         }
 
+        if (shouldNeverShowSystemDecorations()) {
+            return false;
+        }
+
         // TODO(b/391965805): Remove this after introducing FLAG_ALLOW_CONTENT_MODE_SWITCH.
         if ((mDisplay.getFlags() & Display.FLAG_REAR) != 0) {
             return false;
@@ -5658,16 +5674,23 @@
         return type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT;
     }
 
+    private boolean shouldNeverShowSystemDecorations() {
+        if (mDisplayId == mWmService.mVr2dDisplayId) {
+            // VR virtual display will be used to run and render 2D app within a VR experience.
+            return true;
+        }
+        if (!isTrusted()) {
+            // Do not show system decorations on untrusted virtual display.
+            return true;
+        }
+        return false;
+    }
+
     /**
      * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
      */
     boolean isSystemDecorationsSupported() {
-        if (mDisplayId == mWmService.mVr2dDisplayId) {
-            // VR virtual display will be used to run and render 2D app within a VR experience.
-            return false;
-        }
-        if (!isTrusted()) {
-            // Do not show system decorations on untrusted virtual display.
+        if (shouldNeverShowSystemDecorations()) {
             return false;
         }
         if (mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(this)
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index ec5b503f..313b77e 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -67,7 +67,6 @@
 
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_SCREEN_ON;
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -107,6 +106,7 @@
 import android.view.InsetsFrameProvider;
 import android.view.InsetsSource;
 import android.view.InsetsState;
+import android.view.PrivacyIndicatorBounds;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewDebug;
@@ -119,6 +119,7 @@
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import android.window.ClientWindowFrames;
+import android.window.DesktopExperienceFlags;
 import android.window.DesktopModeFlags;
 
 import com.android.internal.R;
@@ -747,7 +748,7 @@
     }
 
     void updateHasNavigationBarIfNeeded() {
-        if (!enableDisplayContentModeManagement()) {
+        if (!DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
             Slog.e(TAG, "mHasNavigationBar shouldn't be updated when the flag is off.");
         }
 
@@ -1875,7 +1876,7 @@
     }
 
     void notifyDisplayAddSystemDecorations() {
-        if (enableDisplayContentModeManagement()) {
+        if (DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
             final int displayId = getDisplayId();
             final boolean isSystemDecorationsSupported =
                     mDisplayContent.isSystemDecorationsSupported();
@@ -2121,6 +2122,8 @@
         }
 
         private static class Cache {
+            static final int TYPE_REGULAR_BARS = WindowInsets.Type.statusBars()
+                    | WindowInsets.Type.navigationBars();
             /**
              * If {@link #mPreserveId} is this value, it is in the middle of updating display
              * configuration before a transition is started. Then the active cache should be used.
@@ -2130,6 +2133,14 @@
             int mPreserveId;
             boolean mActive;
 
+            /**
+             * When display switches, mRegularBarsInsets will assign to mPreservedInsets, and the
+             * insets sources of previous device state will copy to mRegularBarsInsets.
+             */
+            ArrayList<InsetsSource> mPreservedInsets;
+            ArrayList<InsetsSource> mRegularBarsInsets;
+            PrivacyIndicatorBounds mPrivacyIndicatorBounds;
+
             Cache(DisplayContent dc) {
                 mDecorInsets = new DecorInsets(dc);
             }
@@ -2138,6 +2149,17 @@
                 return mPreserveId == ID_UPDATING_CONFIG || mDecorInsets.mDisplayContent
                         .mTransitionController.inTransition(mPreserveId);
             }
+
+            static ArrayList<InsetsSource> copyRegularBarInsets(InsetsState srcState) {
+                final ArrayList<InsetsSource> state = new ArrayList<>();
+                for (int i = srcState.sourceSize() - 1; i >= 0; i--) {
+                    final InsetsSource source = srcState.sourceAt(i);
+                    if ((source.getType() & TYPE_REGULAR_BARS) != 0) {
+                        state.add(new InsetsSource(source));
+                    }
+                }
+                return state;
+            }
         }
     }
 
@@ -2213,24 +2235,60 @@
     @VisibleForTesting
     void updateCachedDecorInsets() {
         DecorInsets prevCache = null;
+        PrivacyIndicatorBounds privacyIndicatorBounds = null;
         if (mCachedDecorInsets == null) {
             mCachedDecorInsets = new DecorInsets.Cache(mDisplayContent);
         } else {
             prevCache = new DecorInsets(mDisplayContent);
             prevCache.setTo(mCachedDecorInsets.mDecorInsets);
+            privacyIndicatorBounds = mCachedDecorInsets.mPrivacyIndicatorBounds;
+            mCachedDecorInsets.mPreservedInsets = mCachedDecorInsets.mRegularBarsInsets;
         }
         // Set a special id to preserve it before a real id is available from transition.
         mCachedDecorInsets.mPreserveId = DecorInsets.Cache.ID_UPDATING_CONFIG;
         // Cache the current insets.
         mCachedDecorInsets.mDecorInsets.setTo(mDecorInsets);
+        if (com.android.window.flags.Flags.useCachedInsetsForDisplaySwitch()) {
+            mCachedDecorInsets.mRegularBarsInsets = DecorInsets.Cache.copyRegularBarInsets(
+                    mDisplayContent.mDisplayFrames.mInsetsState);
+            mCachedDecorInsets.mPrivacyIndicatorBounds =
+                    mDisplayContent.mCurrentPrivacyIndicatorBounds;
+        } else {
+            mCachedDecorInsets.mRegularBarsInsets = null;
+            mCachedDecorInsets.mPrivacyIndicatorBounds = null;
+        }
         // Switch current to previous cache.
         if (prevCache != null) {
             mDecorInsets.setTo(prevCache);
+            if (privacyIndicatorBounds != null) {
+                mDisplayContent.mCurrentPrivacyIndicatorBounds = privacyIndicatorBounds;
+            }
             mCachedDecorInsets.mActive = true;
         }
     }
 
     /**
+     * This returns a new InsetsState with replacing the insets in target device state when the
+     * display is switching (e.g. fold/unfold). Otherwise, it returns the original state. This is
+     * to avoid dispatching old insets source before the insets providers update new insets.
+     */
+    InsetsState replaceInsetsSourcesIfNeeded(InsetsState originalState, boolean copyState) {
+        if (mCachedDecorInsets == null || mCachedDecorInsets.mPreservedInsets == null
+                || !shouldKeepCurrentDecorInsets()) {
+            return originalState;
+        }
+        final ArrayList<InsetsSource> preservedSources = mCachedDecorInsets.mPreservedInsets;
+        final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
+        for (int i = preservedSources.size() - 1; i >= 0; i--) {
+            final InsetsSource cacheSource = preservedSources.get(i);
+            if (state.peekSource(cacheSource.getId()) != null) {
+                state.addSource(new InsetsSource(cacheSource));
+            }
+        }
+        return state;
+    }
+
+    /**
      * Called after the display configuration is updated according to the physical change. Suppose
      * there should be a display change transition, so associate the cached decor insets with the
      * transition to limit the lifetime of using the cache.
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
index fa7a99d..d90fff2 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -40,14 +40,14 @@
     }
 
     int[] registerListener(IDisplayWindowListener listener) {
+        mDisplayListeners.register(listener);
+        final IntArray displayIds = new IntArray();
         synchronized (mService.mGlobalLock) {
-            mDisplayListeners.register(listener);
-            final IntArray displayIds = new IntArray();
             mService.mAtmService.mRootWindowContainer.forAllDisplays((displayContent) -> {
                 displayIds.add(displayContent.mDisplayId);
             });
-            return displayIds.toArray();
         }
+        return displayIds.toArray();
     }
 
     void unregisterListener(IDisplayWindowListener listener) {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index c6892e9..5657920 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -23,7 +23,6 @@
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
 
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
 
@@ -37,6 +36,7 @@
 import android.view.Surface;
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
+import android.window.DesktopExperienceFlags;
 
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.DisplayContent.ForceScalingMode;
@@ -240,6 +240,11 @@
         mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
+    /**
+     * Returns {@code true} if either the display is the default display, or the display is allowed
+     * to dynamically add/remove system decorations and the system decorations should be shown on it
+     * currently.
+     */
     boolean shouldShowSystemDecorsLocked(@NonNull DisplayContent dc) {
         if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
             // Default display should show system decors.
@@ -255,7 +260,7 @@
         final boolean changed = (shouldShow != shouldShowSystemDecorsLocked(dc));
         setShouldShowSystemDecorsInternalLocked(dc, shouldShow);
 
-        if (enableDisplayContentModeManagement()) {
+        if (DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
             if (dc.isDefaultDisplay || dc.isPrivate() || !changed) {
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 2872214..06754c4 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -229,6 +229,7 @@
             state = originalState;
         }
         state = adjustVisibilityForIme(target, state, state == originalState);
+        state = mPolicy.replaceInsetsSourcesIfNeeded(state, state == originalState);
         return adjustInsetsForRoundedCorners(target.mToken, state, state == originalState);
     }
 
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 29c0c7b..3a4d2ca 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -54,7 +54,6 @@
 
     private final Supplier<SurfaceControl.Builder> mSurfaceControlFactory;
     private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
-    private final Supplier<SurfaceControl> mParentSurfaceSupplier;
 
     private final Rect mOuter = new Rect();
     private final Rect mInner = new Rect();
@@ -83,13 +82,11 @@
     public Letterbox(Supplier<SurfaceControl.Builder> surfaceControlFactory,
             Supplier<SurfaceControl.Transaction> transactionFactory,
             @NonNull AppCompatReachabilityPolicy appCompatReachabilityPolicy,
-            @NonNull AppCompatLetterboxOverrides appCompatLetterboxOverrides,
-            Supplier<SurfaceControl> parentSurface) {
+            @NonNull AppCompatLetterboxOverrides appCompatLetterboxOverrides) {
         mSurfaceControlFactory = surfaceControlFactory;
         mTransactionFactory = transactionFactory;
         mAppCompatReachabilityPolicy = appCompatReachabilityPolicy;
         mAppCompatLetterboxOverrides = appCompatLetterboxOverrides;
-        mParentSurfaceSupplier = parentSurface;
     }
 
     /**
@@ -343,7 +340,6 @@
         private SurfaceControl mInputSurface;
         private Color mColor;
         private boolean mHasWallpaperBackground;
-        private SurfaceControl mParentSurface;
 
         private final Rect mSurfaceFrameRelative = new Rect();
         private final Rect mLayoutFrameGlobal = new Rect();
@@ -437,9 +433,8 @@
                 }
 
                 mColor = mAppCompatLetterboxOverrides.getLetterboxBackgroundColor();
-                mParentSurface = mParentSurfaceSupplier.get();
                 t.setColor(mSurface, getRgbColorArray());
-                setPositionAndReparent(t, mSurface);
+                setPositionAndCrop(t, mSurface);
 
                 mHasWallpaperBackground = mAppCompatLetterboxOverrides
                         .hasWallpaperBackgroundForLetterbox();
@@ -448,7 +443,7 @@
                 t.show(mSurface);
 
                 if (mInputSurface != null) {
-                    setPositionAndReparent(inputT, mInputSurface);
+                    setPositionAndCrop(inputT, mInputSurface);
                     inputT.setTrustedOverlay(mInputSurface, true);
                     inputT.show(mInputSurface);
                 }
@@ -470,12 +465,11 @@
             }
         }
 
-        private void setPositionAndReparent(@NonNull SurfaceControl.Transaction t,
+        private void setPositionAndCrop(@NonNull SurfaceControl.Transaction t,
                 @NonNull SurfaceControl surface) {
             t.setPosition(surface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
             t.setWindowCrop(surface, mSurfaceFrameRelative.width(),
                     mSurfaceFrameRelative.height());
-            t.reparent(surface, mParentSurface);
         }
 
         private void updateAlphaAndBlur(SurfaceControl.Transaction t) {
@@ -511,14 +505,13 @@
 
         public boolean needsApplySurfaceChanges() {
             return !mSurfaceFrameRelative.equals(mLayoutFrameRelative)
-                    // If mSurfaceFrameRelative is empty then mHasWallpaperBackground, mColor,
-                    // and mParentSurface may never be updated in applySurfaceChanges but this
-                    // doesn't mean that update is needed.
+                    // If mSurfaceFrameRelative is empty, then mHasWallpaperBackground and mColor
+                    // may never be updated in applySurfaceChanges but this doesn't mean that
+                    // update is needed.
                     || !mSurfaceFrameRelative.isEmpty()
                     && (mAppCompatLetterboxOverrides.hasWallpaperBackgroundForLetterbox()
                         != mHasWallpaperBackground
-                    || !mAppCompatLetterboxOverrides.getLetterboxBackgroundColor().equals(mColor)
-                    || mParentSurfaceSupplier.get() != mParentSurface);
+                    || !mAppCompatLetterboxOverrides.getLetterboxBackgroundColor().equals(mColor));
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index e864ecf..cf201c9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -36,6 +36,7 @@
 import static android.view.WindowManager.TRANSIT_PIP;
 import static android.view.WindowManager.TRANSIT_SLEEP;
 import static android.view.WindowManager.TRANSIT_WAKE;
+import static android.window.DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT;
 
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_KEEP_SCREEN_ON;
@@ -45,7 +46,6 @@
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TASKS;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WALLPAPER;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_SHOW_SURFACE_ALLOC;
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -1371,7 +1371,8 @@
         // When display content mode management flag is enabled, the task display area is marked as
         // removed when switching from extended display to mirroring display. We need to restart the
         // task display area before starting the home.
-        if (enableDisplayContentModeManagement() && taskDisplayArea.shouldKeepNoTask()) {
+        if (ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()
+                && taskDisplayArea.shouldKeepNoTask()) {
             taskDisplayArea.setShouldKeepNoTask(false);
         }
 
@@ -2771,10 +2772,17 @@
                 return;
             }
 
-            if (enableDisplayContentModeManagement() && display.allowContentModeSwitch()) {
-                mWindowManager.mDisplayWindowSettings
-                        .setShouldShowSystemDecorsInternalLocked(display,
-                                display.mDisplay.canHostTasks());
+            if (ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
+                if (display.allowContentModeSwitch()) {
+                    mWindowManager.mDisplayWindowSettings
+                            .setShouldShowSystemDecorsInternalLocked(display,
+                                    display.mDisplay.canHostTasks());
+                }
+
+                final boolean inTopology = mWindowManager.mDisplayWindowSettings
+                        .shouldShowSystemDecorsLocked(display);
+                mWmService.mDisplayManagerInternal.onDisplayBelongToTopologyChanged(displayId,
+                        inTopology);
             }
 
             startSystemDecorations(display, "displayAdded");
@@ -2823,7 +2831,7 @@
                 displayContent.requestDisplayUpdate(
                         () -> {
                             clearDisplayInfoCaches(displayId);
-                            if (enableDisplayContentModeManagement()) {
+                            if (ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
                                 displayContent.onDisplayInfoChangeApplied();
                             }
                         });
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 22f0278..d16c301 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4497,7 +4497,7 @@
     }
 
     void onPictureInPictureParamsChanged() {
-        if (inPinnedWindowingMode() || Flags.enableDesktopWindowingPip()) {
+        if (inPinnedWindowingMode() || DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue()) {
             dispatchTaskInfoChangedIfNeeded(true /* force */);
         }
     }
diff --git a/services/core/java/com/android/server/wm/ViewServer.java b/services/core/java/com/android/server/wm/ViewServer.java
index ecf5652..971e6f9 100644
--- a/services/core/java/com/android/server/wm/ViewServer.java
+++ b/services/core/java/com/android/server/wm/ViewServer.java
@@ -19,7 +19,10 @@
 
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerInternal.WindowFocusChangeListener;
+import static com.android.server.wm.WindowManagerService.WindowChangeListener;
 
+import android.os.IBinder;
 import android.util.Slog;
 
 import java.net.ServerSocket;
@@ -206,7 +209,7 @@
         return result;
     }
 
-    class ViewServerWorker implements Runnable, WindowManagerService.WindowChangeListener {
+    class ViewServerWorker implements Runnable, WindowChangeListener, WindowFocusChangeListener {
         private Socket mClient;
         private boolean mNeedWindowListUpdate;
         private boolean mNeedFocusedWindowUpdate;
@@ -284,7 +287,7 @@
             }
         }
 
-        public void focusChanged() {
+        public void focusChanged(IBinder focusedWindowToken) {
             synchronized(this) {
                 mNeedFocusedWindowUpdate = true;
                 notifyAll();
@@ -293,6 +296,7 @@
 
         private boolean windowManagerAutolistLoop() {
             mWindowManager.addWindowChangeListener(this);
+            mWindowManager.addWindowFocusChangeListener(this);
             BufferedWriter out = null;
             try {
                 out = new BufferedWriter(new OutputStreamWriter(mClient.getOutputStream()));
@@ -332,6 +336,7 @@
                     }
                 }
                 mWindowManager.removeWindowChangeListener(this);
+                mWindowManager.removeWindowFocusChangeListener(this);
             }
             return true;
         }
diff --git a/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java b/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
deleted file mode 100644
index d3530c5..0000000
--- a/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static com.android.server.wm.AnimationAdapter.STATUS_BAR_TRANSITION_DURATION;
-import static com.android.server.wm.AnimationSpecProto.WINDOW;
-import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
-
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.os.SystemClock;
-import android.util.proto.ProtoOutputStream;
-import android.view.DisplayInfo;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.ClipRectAnimation;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.Transformation;
-import android.view.animation.TranslateAnimation;
-
-import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
-
-import java.io.PrintWriter;
-
-/**
- * Animation spec for changing window animations.
- */
-public class WindowChangeAnimationSpec implements AnimationSpec {
-
-    private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
-    private final boolean mIsAppAnimation;
-    private final Rect mStartBounds;
-    private final Rect mEndBounds;
-    private final Rect mTmpRect = new Rect();
-
-    private Animation mAnimation;
-    private final boolean mIsThumbnail;
-
-    static final int ANIMATION_DURATION = AppTransition.DEFAULT_APP_TRANSITION_DURATION;
-
-    public WindowChangeAnimationSpec(Rect startBounds, Rect endBounds, DisplayInfo displayInfo,
-            float durationScale, boolean isAppAnimation, boolean isThumbnail) {
-        mStartBounds = new Rect(startBounds);
-        mEndBounds = new Rect(endBounds);
-        mIsAppAnimation = isAppAnimation;
-        mIsThumbnail = isThumbnail;
-        createBoundsInterpolator((int) (ANIMATION_DURATION * durationScale), displayInfo);
-    }
-
-    @Override
-    public boolean getShowWallpaper() {
-        return false;
-    }
-
-    @Override
-    public long getDuration() {
-        return mAnimation.getDuration();
-    }
-
-    /**
-     * This animator behaves slightly differently depending on whether the window is growing
-     * or shrinking:
-     * If growing, it will do a clip-reveal after quicker fade-out/scale of the smaller (old)
-     * snapshot.
-     * If shrinking, it will do an opposite clip-reveal on the old snapshot followed by a quicker
-     * fade-out of the bigger (old) snapshot while simultaneously shrinking the new window into
-     * place.
-     * @param duration
-     * @param displayInfo
-     */
-    private void createBoundsInterpolator(long duration, DisplayInfo displayInfo) {
-        boolean growing = mEndBounds.width() - mStartBounds.width()
-                + mEndBounds.height() - mStartBounds.height() >= 0;
-        float scalePart = 0.7f;
-        long scalePeriod = (long) (duration * scalePart);
-        float startScaleX = scalePart * ((float) mStartBounds.width()) / mEndBounds.width()
-                + (1.f - scalePart);
-        float startScaleY = scalePart * ((float) mStartBounds.height()) / mEndBounds.height()
-                + (1.f - scalePart);
-        if (mIsThumbnail) {
-            AnimationSet animSet = new AnimationSet(true);
-            Animation anim = new AlphaAnimation(1.f, 0.f);
-            anim.setDuration(scalePeriod);
-            if (!growing) {
-                anim.setStartOffset(duration - scalePeriod);
-            }
-            animSet.addAnimation(anim);
-            float endScaleX = 1.f / startScaleX;
-            float endScaleY = 1.f / startScaleY;
-            anim = new ScaleAnimation(endScaleX, endScaleX, endScaleY, endScaleY);
-            anim.setDuration(duration);
-            animSet.addAnimation(anim);
-            mAnimation = animSet;
-            mAnimation.initialize(mStartBounds.width(), mStartBounds.height(),
-                    mEndBounds.width(), mEndBounds.height());
-        } else {
-            AnimationSet animSet = new AnimationSet(true);
-            final Animation scaleAnim = new ScaleAnimation(startScaleX, 1, startScaleY, 1);
-            scaleAnim.setDuration(scalePeriod);
-            if (!growing) {
-                scaleAnim.setStartOffset(duration - scalePeriod);
-            }
-            animSet.addAnimation(scaleAnim);
-            final Animation translateAnim = new TranslateAnimation(mStartBounds.left,
-                    mEndBounds.left, mStartBounds.top, mEndBounds.top);
-            translateAnim.setDuration(duration);
-            animSet.addAnimation(translateAnim);
-            Rect startClip = new Rect(mStartBounds);
-            Rect endClip = new Rect(mEndBounds);
-            startClip.offsetTo(0, 0);
-            endClip.offsetTo(0, 0);
-            final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
-            clipAnim.setDuration(duration);
-            animSet.addAnimation(clipAnim);
-            mAnimation = animSet;
-            mAnimation.initialize(mStartBounds.width(), mStartBounds.height(),
-                    displayInfo.appWidth, displayInfo.appHeight);
-        }
-    }
-
-    @Override
-    public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
-        final TmpValues tmp = mThreadLocalTmps.get();
-        if (mIsThumbnail) {
-            mAnimation.getTransformation(currentPlayTime, tmp.mTransformation);
-            t.setMatrix(leash, tmp.mTransformation.getMatrix(), tmp.mFloats);
-            t.setAlpha(leash, tmp.mTransformation.getAlpha());
-        } else {
-            mAnimation.getTransformation(currentPlayTime, tmp.mTransformation);
-            final Matrix matrix = tmp.mTransformation.getMatrix();
-            t.setMatrix(leash, matrix, tmp.mFloats);
-
-            // The following applies an inverse scale to the clip-rect so that it crops "after" the
-            // scale instead of before.
-            tmp.mVecs[1] = tmp.mVecs[2] = 0;
-            tmp.mVecs[0] = tmp.mVecs[3] = 1;
-            matrix.mapVectors(tmp.mVecs);
-            tmp.mVecs[0] = 1.f / tmp.mVecs[0];
-            tmp.mVecs[3] = 1.f / tmp.mVecs[3];
-            final Rect clipRect = tmp.mTransformation.getClipRect();
-            mTmpRect.left = (int) (clipRect.left * tmp.mVecs[0] + 0.5f);
-            mTmpRect.right = (int) (clipRect.right * tmp.mVecs[0] + 0.5f);
-            mTmpRect.top = (int) (clipRect.top * tmp.mVecs[3] + 0.5f);
-            mTmpRect.bottom = (int) (clipRect.bottom * tmp.mVecs[3] + 0.5f);
-            t.setWindowCrop(leash, mTmpRect);
-        }
-    }
-
-    @Override
-    public long calculateStatusBarTransitionStartTime() {
-        long uptime = SystemClock.uptimeMillis();
-        return Math.max(uptime, uptime + ((long) (((float) mAnimation.getDuration()) * 0.99f))
-                - STATUS_BAR_TRANSITION_DURATION);
-    }
-
-    @Override
-    public boolean canSkipFirstFrame() {
-        return false;
-    }
-
-    @Override
-    public boolean needsEarlyWakeup() {
-        return mIsAppAnimation;
-    }
-
-    @Override
-    public void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.println(mAnimation.getDuration());
-    }
-
-    @Override
-    public void dumpDebugInner(ProtoOutputStream proto) {
-        final long token = proto.start(WINDOW);
-        proto.write(ANIMATION, mAnimation.toString());
-        proto.end(token);
-    }
-
-    private static class TmpValues {
-        final Transformation mTransformation = new Transformation();
-        final float[] mFloats = new float[9];
-        final float[] mVecs = new float[4];
-    }
-}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e3746f1..466ed78 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -97,7 +97,6 @@
 import com.android.server.wm.SurfaceAnimator.AnimationType;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 import com.android.server.wm.utils.AlwaysTruePredicate;
-import com.android.window.flags.Flags;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -2630,7 +2629,7 @@
         if (!mTransitionController.canAssignLayers(this)) return;
         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
         if (mSurfaceControl != null && changed) {
-            if (Flags.useSelfSyncTransactionForLayer() && mSyncState != SYNC_STATE_NONE) {
+            if (mSyncState != SYNC_STATE_NONE) {
                 // When this container needs to be synced, assign layer with its own sync
                 // transaction to avoid out of ordering when merge.
                 // Still use the passed-in transaction for non-sync case, such as building finish
@@ -2647,7 +2646,7 @@
             boolean forceUpdate) {
         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
         if (mSurfaceControl != null && (changed || forceUpdate)) {
-            if (Flags.useSelfSyncTransactionForLayer() && mSyncState != SYNC_STATE_NONE) {
+            if (mSyncState != SYNC_STATE_NONE) {
                 // When this container needs to be synced, assign layer with its own sync
                 // transaction to avoid out of ordering when merge.
                 // Still use the passed-in transaction for non-sync case, such as building finish
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 6e224f0..4b5a3a0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -152,6 +152,30 @@
         }
     }
 
+    /** Interface for clients to receive callbacks related to window change. */
+    public interface WindowFocusChangeListener {
+        /**
+         * Notify on focus changed.
+         *
+         * @param focusedWindowToken the token of the newly focused window.
+         */
+        void focusChanged(@NonNull IBinder focusedWindowToken);
+    }
+
+    /**
+     * Registers a listener to be notified about window focus changes.
+     *
+     * @param listener the {@link WindowFocusChangeListener} to register.
+     */
+    public abstract void registerWindowFocusChangeListener(WindowFocusChangeListener listener);
+
+    /**
+     * Unregisters a listener that was registered via {@link #registerWindowFocusChangeListener}.
+     *
+     * @param listener the {@link WindowFocusChangeListener} to unregister.
+     */
+    public abstract void unregisterWindowFocusChangeListener(WindowFocusChangeListener listener);
+
     /**
      * Interface to receive a callback when the windows reported for
      * accessibility changed.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 54f9609..9fc0339 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -145,6 +145,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerInternal.OnWindowRemovedListener;
+import static com.android.server.wm.WindowManagerInternal.WindowFocusChangeListener;
 import static com.android.server.wm.WindowManagerServiceDumpProto.BACK_NAVIGATION;
 import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_APP;
 import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_DISPLAY_ID;
@@ -1078,14 +1079,12 @@
 
     private ViewServer mViewServer;
     final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
+    final ArrayList<WindowFocusChangeListener> mWindowFocusChangeListeners = new ArrayList<>();
     boolean mWindowsChanged = false;
 
-    public interface WindowChangeListener {
+    interface WindowChangeListener {
         /** Notify on windows changed */
         void windowsChanged();
-
-        /** Notify on focus changed */
-        void focusChanged();
     }
 
     final HighRefreshRateDenylist mHighRefreshRateDenylist;
@@ -5306,18 +5305,30 @@
         return success;
     }
 
-    public void addWindowChangeListener(WindowChangeListener listener) {
+    void addWindowChangeListener(WindowChangeListener listener) {
         synchronized (mGlobalLock) {
             mWindowChangeListeners.add(listener);
         }
     }
 
-    public void removeWindowChangeListener(WindowChangeListener listener) {
+    void removeWindowChangeListener(WindowChangeListener listener) {
         synchronized (mGlobalLock) {
             mWindowChangeListeners.remove(listener);
         }
     }
 
+    void addWindowFocusChangeListener(WindowFocusChangeListener listener) {
+        synchronized (mGlobalLock) {
+            mWindowFocusChangeListeners.add(listener);
+        }
+    }
+
+    void removeWindowFocusChangeListener(WindowFocusChangeListener listener) {
+        synchronized (mGlobalLock) {
+            mWindowFocusChangeListeners.remove(listener);
+        }
+    }
+
     private void notifyWindowRemovedListeners(IBinder client) {
         OnWindowRemovedListener[] windowRemovedListeners;
         synchronized (mGlobalLock) {
@@ -5350,18 +5361,19 @@
         }
     }
 
-    private void notifyFocusChanged() {
-        WindowChangeListener[] windowChangeListeners;
+    private void notifyFocusChanged(IBinder focusedWindowToken) {
+        WindowFocusChangeListener[] windowFocusChangeListeners;
         synchronized (mGlobalLock) {
-            if(mWindowChangeListeners.isEmpty()) {
+            if(mWindowFocusChangeListeners.isEmpty()) {
                 return;
             }
-            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
-            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
+            windowFocusChangeListeners =
+                    new WindowFocusChangeListener[mWindowFocusChangeListeners.size()];
+            mWindowFocusChangeListeners.toArray(windowFocusChangeListeners);
         }
-        int N = windowChangeListeners.length;
+        int N = windowFocusChangeListeners.length;
         for(int i = 0; i < N; i++) {
-            windowChangeListeners[i].focusChanged();
+            windowFocusChangeListeners[i].focusChanged(focusedWindowToken);
         }
     }
 
@@ -5636,7 +5648,7 @@
         if (newFocusedWindow != null && newFocusedWindow.mInputChannelToken == newToken) {
             mAnrController.onFocusChanged(newFocusedWindow);
             newFocusedWindow.reportFocusChangedSerialized(true);
-            notifyFocusChanged();
+            notifyFocusChanged(newTarget.getWindowToken());
         }
 
         WindowState lastFocusedWindow = lastTarget != null ? lastTarget.getWindowState() : null;
@@ -8650,6 +8662,16 @@
         }
 
         @Override
+        public void registerWindowFocusChangeListener(WindowFocusChangeListener listener) {
+            WindowManagerService.this.addWindowFocusChangeListener(listener);
+        }
+
+        @Override
+        public void unregisterWindowFocusChangeListener(WindowFocusChangeListener listener) {
+            WindowManagerService.this.removeWindowFocusChangeListener(listener);
+        }
+
+        @Override
         public void registerOnWindowRemovedListener(OnWindowRemovedListener listener) {
             synchronized (mGlobalLock) {
                 mOnWindowRemovedListeners.add(listener);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3b7d312..1022d18 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5447,7 +5447,7 @@
     @Override
     void assignLayer(Transaction t, int layer) {
         if (mStartingData != null) {
-            if (Flags.useSelfSyncTransactionForLayer() && mSyncState != SYNC_STATE_NONE) {
+            if (mSyncState != SYNC_STATE_NONE) {
                 // When this container needs to be synced, assign layer with its own sync
                 // transaction to avoid out of ordering when merge.
                 // Still use the passed-in transaction for non-sync case, such as building finish
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 1d8d867..0d434f5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -561,7 +561,7 @@
                         break;
                 }
                 if (attr >= 0) {
-                    a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
+                    a = mWin.mDisplayContent.mTransitionAnimation.loadAnimationAttr(
                             mWin.mAttrs, attr, TRANSIT_OLD_NONE);
                 }
             }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 9577608..66d04df 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -193,10 +193,6 @@
         "android.hardware.tv.input@1.0",
         "android.hardware.tv.input-V2-ndk",
         "android.hardware.vibrator-V3-ndk",
-        "android.hardware.vibrator@1.0",
-        "android.hardware.vibrator@1.1",
-        "android.hardware.vibrator@1.2",
-        "android.hardware.vibrator@1.3",
         "android.hardware.vr@1.0",
         "android.hidl.token@1.0-utils",
         "android.frameworks.schedulerservice@1.0",
diff --git a/services/core/jni/com_android_server_display_DisplayControl.cpp b/services/core/jni/com_android_server_display_DisplayControl.cpp
index aeae13d..c674f90 100644
--- a/services/core/jni/com_android_server_display_DisplayControl.cpp
+++ b/services/core/jni/com_android_server_display_DisplayControl.cpp
@@ -24,12 +24,13 @@
 namespace android {
 
 static jobject nativeCreateVirtualDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
-                                          jboolean secure, jstring uniqueIdStr,
-                                          jfloat requestedRefreshRate) {
+                                          jboolean secure, jboolean optimizeForPower,
+                                          jstring uniqueIdStr, jfloat requestedRefreshRate) {
     const ScopedUtfChars name(env, nameObj);
     const ScopedUtfChars uniqueId(env, uniqueIdStr);
     sp<IBinder> token(SurfaceComposerClient::createVirtualDisplay(std::string(name.c_str()),
                                                                   bool(secure),
+                                                                  bool(optimizeForPower),
                                                                   std::string(uniqueId.c_str()),
                                                                   requestedRefreshRate));
     return javaObjectForIBinder(env, token);
@@ -182,7 +183,7 @@
 
 static const JNINativeMethod sDisplayMethods[] = {
         // clang-format off
-    {"nativeCreateVirtualDisplay", "(Ljava/lang/String;ZLjava/lang/String;F)Landroid/os/IBinder;",
+    {"nativeCreateVirtualDisplay", "(Ljava/lang/String;ZZLjava/lang/String;F)Landroid/os/IBinder;",
             (void*)nativeCreateVirtualDisplay },
     {"nativeDestroyVirtualDisplay", "(Landroid/os/IBinder;)V",
             (void*)nativeDestroyVirtualDisplay },
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index 534dbb1..11dbbdf 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -19,7 +19,6 @@
 #include <aidl/android/hardware/vibrator/IVibrator.h>
 #include <android/binder_parcel.h>
 #include <android/binder_parcel_jni.h>
-#include <android/hardware/vibrator/1.3/IVibrator.h>
 #include <android/persistable_bundle_aidl.h>
 #include <android_os_vibrator.h>
 #include <nativehelper/JNIHelp.h>
@@ -32,8 +31,6 @@
 #include "core_jni_helpers.h"
 #include "jni.h"
 
-namespace V1_0 = android::hardware::vibrator::V1_0;
-namespace V1_3 = android::hardware::vibrator::V1_3;
 namespace Aidl = aidl::android::hardware::vibrator;
 
 using aidl::android::os::PersistableBundle;
@@ -80,31 +77,6 @@
     jfieldID timeMillis;
 } sPwlePointClassInfo;
 
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
-              static_cast<uint8_t>(Aidl::EffectStrength::LIGHT));
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
-              static_cast<uint8_t>(Aidl::EffectStrength::MEDIUM));
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
-              static_cast<uint8_t>(Aidl::EffectStrength::STRONG));
-
-static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
-              static_cast<uint8_t>(Aidl::Effect::CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
-              static_cast<uint8_t>(Aidl::Effect::DOUBLE_CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(Aidl::Effect::TICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(Aidl::Effect::THUD));
-static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(Aidl::Effect::POP));
-static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
-              static_cast<uint8_t>(Aidl::Effect::HEAVY_CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
-              static_cast<uint8_t>(Aidl::Effect::RINGTONE_1));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
-              static_cast<uint8_t>(Aidl::Effect::RINGTONE_2));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
-              static_cast<uint8_t>(Aidl::Effect::RINGTONE_15));
-static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
-              static_cast<uint8_t>(Aidl::Effect::TEXTURE_TICK));
-
 static std::shared_ptr<vibrator::HalController> findVibrator(int32_t vibratorId) {
     vibrator::ManagerHalController* manager =
             android_server_vibrator_VibratorManagerService_getManager();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index a81a0b3..4b98a72 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -50,6 +50,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
+import android.util.PrintWriterPrinter;
 
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
@@ -1484,5 +1485,12 @@
             pw.print("mProvisioningContext=");
             pw.println(mProvisioningContext);
         }
+
+        if (info != null) {
+            pw.println("DeviceAdminInfo:");
+            pw.increaseIndent();
+            info.dump(new PrintWriterPrinter(pw), "");
+            pw.decreaseIndent();
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 215d6ca..0ad976c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -245,6 +245,7 @@
 import static android.app.admin.ProvisioningException.ERROR_SETTING_PROFILE_OWNER_FAILED;
 import static android.app.admin.ProvisioningException.ERROR_SET_DEVICE_OWNER_FAILED;
 import static android.app.admin.ProvisioningException.ERROR_STARTING_PROFILE_FAILED;
+import static android.content.Context.RECEIVER_NOT_EXPORTED;
 import static android.content.Intent.ACTION_MANAGED_PROFILE_AVAILABLE;
 import static android.content.Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -486,6 +487,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
+import android.telephony.euicc.EuiccManager;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -643,6 +645,14 @@
     static final String ACTION_PROFILE_OFF_DEADLINE =
             "com.android.server.ACTION_PROFILE_OFF_DEADLINE";
 
+    /** Broadcast action invoked when a managed eSIM is removed while deleting work profile. */
+    private static final String ACTION_ESIM_REMOVED_WITH_MANAGED_PROFILE =
+            "com.android.server.ACTION_ESIM_REMOVED_WITH_MANAGED_PROFILE";
+
+    /** Extra for the subscription ID of the managed eSIM removed while deleting work profile. */
+    private static final String EXTRA_REMOVED_ESIM_SUBSCRIPTION_ID =
+            "com.android.server.EXTRA_ESIM_REMOVED_WITH_MANAGED_PROFILE_SUBSCRIPTION_ID";
+
     private static final String CALLED_FROM_PARENT = "calledFromParent";
     private static final String NOT_CALLED_FROM_PARENT = "notCalledFromParent";
 
@@ -1266,6 +1276,8 @@
                 removeCredentialManagementApp(intent.getData().getSchemeSpecificPart());
             } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)) {
                 clearWipeProfileNotification();
+            } else if (Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
+                removeManagedEmbeddedSubscriptionsForUser(userHandle);
             } else if (Intent.ACTION_DATE_CHANGED.equals(action)
                     || Intent.ACTION_TIME_CHANGED.equals(action)) {
                 // Update freeze period record when clock naturally progresses to the next day
@@ -1298,6 +1310,13 @@
                 triggerPolicyComplianceCheckIfNeeded(userHandle, suspended);
             } else if (LOGIN_ACCOUNTS_CHANGED_ACTION.equals(action)) {
                 calculateHasIncompatibleAccounts();
+            } else if (ACTION_ESIM_REMOVED_WITH_MANAGED_PROFILE.equals(action)) {
+                int removedSubscriptionId = intent.getIntExtra(EXTRA_REMOVED_ESIM_SUBSCRIPTION_ID,
+                        -1);
+                Slogf.i(LOG_TAG,
+                        "Deleted subscription with ID %d because owning managed profile was "
+                                + "removed",
+                        removedSubscriptionId);
             }
         }
 
@@ -2219,9 +2238,14 @@
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
         filter.addAction(Intent.ACTION_TIME_CHANGED);
         filter.addAction(Intent.ACTION_DATE_CHANGED);
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+        filter = new IntentFilter();
+        filter.addAction(ACTION_ESIM_REMOVED_WITH_MANAGED_PROFILE);
+        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null,
+                mHandler, RECEIVER_NOT_EXPORTED);
 
         LocalServices.addService(DevicePolicyManagerInternal.class, mLocalService);
 
@@ -3970,6 +3994,7 @@
             deletedUsers.remove(userInfo.id);
         }
         for (Integer userId : deletedUsers) {
+            removeManagedEmbeddedSubscriptionsForUser(userId);
             removeUserData(userId);
             mDevicePolicyEngine.handleUserRemoved(userId);
         }
@@ -8099,6 +8124,45 @@
         mInjector.getNotificationManager().cancel(SystemMessage.NOTE_PROFILE_WIPED);
     }
 
+    /**
+     * Remove eSIM subscriptions that are managed by any of the admin packages of the given
+     * userHandle.
+     */
+    private void removeManagedEmbeddedSubscriptionsForUser(int userHandle) {
+        if (!Flags.removeManagedEsimOnWorkProfileDeletion()) {
+            return;
+        }
+
+        Slogf.i(LOG_TAG,
+                "Managed profile with ID=%d deleted: going to remove managed embedded "
+                        + "subscriptions", userHandle);
+        String profileOwnerPackage = mOwners.getProfileOwnerPackage(userHandle);
+        if (profileOwnerPackage == null) {
+            Slogf.wtf(LOG_TAG, "Profile owner package for managed profile is null");
+            return;
+        }
+        IntArray managedSubscriptionIds = getSubscriptionIdsInternal(profileOwnerPackage);
+        deleteEmbeddedSubscriptions(managedSubscriptionIds);
+    }
+
+    private void deleteEmbeddedSubscriptions(IntArray subscriptionIds) {
+        EuiccManager euiccManager = mContext.getSystemService(EuiccManager.class);
+        for (int subscriptionId : subscriptionIds.toArray()) {
+            Slogf.i(LOG_TAG, "Deleting embedded subscription with ID %d", subscriptionId);
+            euiccManager.deleteSubscription(subscriptionId,
+                    createCallbackPendingIntentForRemovingManagedSubscription(
+                            subscriptionId));
+        }
+    }
+
+    private PendingIntent createCallbackPendingIntentForRemovingManagedSubscription(
+            Integer subscriptionId) {
+        Intent intent = new Intent(ACTION_ESIM_REMOVED_WITH_MANAGED_PROFILE);
+        intent.putExtra(EXTRA_REMOVED_ESIM_SUBSCRIPTION_ID, subscriptionId);
+        return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
+    }
+
+
     @Override
     public void setFactoryResetProtectionPolicy(ComponentName who, String callerPackageName,
             @Nullable FactoryResetProtectionPolicy policy) {
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 8e74952..de78271 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
@@ -20,6 +20,7 @@
 import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_UNSUPPORTED_WHEN_POWER_SAVE_MODE;
 import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL;
 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
+import static android.os.Trace.TRACE_TAG_SYSTEM_SERVER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.TYPE_EXTERNAL;
 
@@ -324,6 +325,11 @@
             }
 
             if (newState != INVALID_DEVICE_STATE_IDENTIFIER && newState != mLastReportedState) {
+                if (Trace.isTagEnabled(TRACE_TAG_SYSTEM_SERVER)) {
+                    Trace.instant(TRACE_TAG_SYSTEM_SERVER,
+                            "[Device state changed] Last hinge sensor event timestamp: "
+                                    + mLastHingeAngleSensorEvent.timestamp);
+                }
                 mLastReportedState = newState;
                 stateToReport = newState;
             }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 860b6fb..788b3b8 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -366,6 +366,8 @@
             "com.android.clockwork.time.WearTimeService";
     private static final String WEAR_SETTINGS_SERVICE_CLASS =
             "com.android.clockwork.settings.WearSettingsService";
+    private static final String WEAR_GESTURE_SERVICE_CLASS =
+            "com.android.clockwork.gesture.WearGestureService";
     private static final String WRIST_ORIENTATION_SERVICE_CLASS =
             "com.android.clockwork.wristorientation.WristOrientationService";
     private static final String IOT_SERVICE_CLASS =
@@ -2844,6 +2846,13 @@
                 mSystemServiceManager.startService(WRIST_ORIENTATION_SERVICE_CLASS);
                 t.traceEnd();
             }
+
+            if (android.server.Flags.wearGestureApi()
+                    && SystemProperties.getBoolean("config.enable_gesture_api", false)) {
+                t.traceBegin("StartWearGestureService");
+                mSystemServiceManager.startService(WEAR_GESTURE_SERVICE_CLASS);
+                t.traceEnd();
+            }
         }
 
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_SLICES_DISABLED)) {
diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
index 86ccd87..7a6bd75 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -65,4 +65,12 @@
      namespace: "package_manager_service"
      description: "Remove AppIntegrityManagerService"
      bug: "364200023"
+}
+
+flag {
+     name: "wear_gesture_api"
+     namespace: "wear_frameworks"
+     description: "Whether the Wear Gesture API is available."
+     bug: "396154116"
+     is_exported: true
 }
\ No newline at end of file
diff --git a/services/proguard.flags b/services/proguard.flags
index 8d8b418..dd3757c 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -59,6 +59,7 @@
 
 # Referenced in wear-service
 -keep public class com.android.server.wm.WindowManagerInternal { *; }
+-keep public class com.android.server.wm.WindowManagerInternal$WindowFocusChangeListener { *; }
 
 # JNI keep rules
 # The global keep rule for native methods allows stripping of such methods if they're unreferenced
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 2dd16f6..80a3a87 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -109,6 +109,7 @@
 import com.android.server.LocalServices;
 import com.android.server.backup.BackupAgentConnectionManager;
 import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.BackupRestoreTask.CancellationReason;
 import com.android.server.backup.BackupWakeLock;
 import com.android.server.backup.DataChangedJournal;
 import com.android.server.backup.KeyValueBackupJob;
@@ -2412,7 +2413,7 @@
         KeyValueBackupTask task = spy(createKeyValueBackupTask(transportMock, PACKAGE_1));
         doNothing().when(task).waitCancel();
 
-        task.handleCancel(true);
+        task.handleCancel(CancellationReason.EXTERNAL);
 
         InOrder inOrder = inOrder(task);
         inOrder.verify(task).markCancel();
@@ -2420,12 +2421,14 @@
     }
 
     @Test
-    public void testHandleCancel_whenCancelAllFalse_throws() throws Exception {
+    public void testHandleCancel_timeout_throws() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgentWithData(PACKAGE_1);
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
 
-        expectThrows(IllegalArgumentException.class, () -> task.handleCancel(false));
+        expectThrows(
+                IllegalArgumentException.class,
+                () -> task.handleCancel(CancellationReason.TIMEOUT));
     }
 
     /** Do not update backup token if no data was moved. */
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt
index afb18f5..5c9ba40 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt
@@ -32,7 +32,7 @@
 
     private var ignore = false
 
-    override fun apply(base: Statement?, description: Description?): Statement {
+    override fun apply(base: Statement, description: Description): Statement {
         return object : Statement() {
             override fun evaluate() {
                 ignore = false
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 65585d0..2770caa8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -324,7 +324,8 @@
             return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
                     new VirtualDisplayAdapter.SurfaceControlDisplayFactory() {
                         @Override
-                        public IBinder createDisplay(String name, boolean secure, String uniqueId,
+                        public IBinder createDisplay(String name, boolean secure,
+                                boolean optimizeForPower, String uniqueId,
                                 float requestedRefreshRate) {
                             return mMockDisplayToken;
                         }
@@ -3914,6 +3915,7 @@
         DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerService.BinderService displayManagerBinderService =
                 displayManager.new BinderService();
+        DisplayManagerInternal localService = displayManager.new LocalService();
         Handler handler = displayManager.getDisplayHandler();
         waitForIdleHandler(handler);
 
@@ -3922,8 +3924,8 @@
                 INTERNAL_EVENT_FLAG_TOPOLOGY_UPDATED);
         waitForIdleHandler(handler);
 
-        var topology = initDisplayTopology(displayManager, displayManagerBinderService, callback,
-                handler, /*shouldEmitTopologyChangeEvent=*/ true);
+        var topology = initDisplayTopology(displayManager, displayManagerBinderService,
+                localService, callback, handler, /*shouldEmitTopologyChangeEvent=*/ true);
         callback.clear();
         callback.expectsEvent(TOPOLOGY_CHANGED_EVENT);
         displayManagerBinderService.setDisplayTopology(topology);
@@ -3938,6 +3940,7 @@
         DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerService.BinderService displayManagerBinderService =
                 displayManager.new BinderService();
+        DisplayManagerInternal localService = displayManager.new LocalService();
         Handler handler = displayManager.getDisplayHandler();
         waitForIdleHandler(handler);
 
@@ -3947,8 +3950,8 @@
                 STANDARD_DISPLAY_EVENTS);
         waitForIdleHandler(handler);
 
-        var topology = initDisplayTopology(displayManager, displayManagerBinderService, callback,
-                handler, /*shouldEmitTopologyChangeEvent=*/ false);
+        var topology = initDisplayTopology(displayManager, displayManagerBinderService,
+                localService, callback, handler, /*shouldEmitTopologyChangeEvent=*/ false);
         callback.clear();
         callback.expectsEvent(TOPOLOGY_CHANGED_EVENT); // should not happen
         displayManagerBinderService.setDisplayTopology(topology);
@@ -4706,15 +4709,16 @@
 
     private DisplayTopology initDisplayTopology(DisplayManagerService displayManager,
             DisplayManagerService.BinderService displayManagerBinderService,
-            FakeDisplayManagerCallback callback,
+            DisplayManagerInternal localService, FakeDisplayManagerCallback callback,
             Handler handler, boolean shouldEmitTopologyChangeEvent) {
         Settings.Global.putInt(mContext.getContentResolver(),
                 DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 1);
         callback.expectsEvent(TOPOLOGY_CHANGED_EVENT);
         FakeDisplayDevice displayDevice0 =
-                createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+                createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
         int displayId0 = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
                 displayDevice0);
+        waitForIdleHandler(handler);
         if (shouldEmitTopologyChangeEvent) {
             callback.waitForExpectedEvent();
         } else {
@@ -4728,6 +4732,11 @@
         int displayId1 = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
                 displayDevice1);
         waitForIdleHandler(handler);
+        // Non-default display should not be added until onDisplayBelongToTopologyChanged is called
+        // with true
+        callback.waitForNonExpectedEvent();
+        localService.onDisplayBelongToTopologyChanged(displayId1, true);
+        waitForIdleHandler(handler);
         if (shouldEmitTopologyChangeEvent) {
             callback.waitForExpectedEvent();
         } else {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
index 3c134b5d..6dc7361 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
@@ -47,7 +47,7 @@
     private val mockTopology = mock<DisplayTopology>()
     private val mockTopologyCopy = mock<DisplayTopology>()
     private val mockTopologyGraph = mock<DisplayTopologyGraph>()
-    private val mockIsExtendedDisplayEnabled = mock<() -> Boolean>()
+    private val mockIsExtendedDisplayAllowed = mock<() -> Boolean>()
     private val mockTopologySavedCallback = mock<() -> Unit>()
     private val mockTopologyChangedCallback =
         mock<(android.util.Pair<DisplayTopology, DisplayTopologyGraph>) -> Unit>()
@@ -73,10 +73,10 @@
             ) =
                 mockTopologyStore
         }
-        whenever(mockIsExtendedDisplayEnabled()).thenReturn(true)
+        whenever(mockIsExtendedDisplayAllowed()).thenReturn(true)
         whenever(mockTopology.copy()).thenReturn(mockTopologyCopy)
         whenever(mockTopologyCopy.getGraph(any())).thenReturn(mockTopologyGraph)
-        coordinator = DisplayTopologyCoordinator(injector, mockIsExtendedDisplayEnabled,
+        coordinator = DisplayTopologyCoordinator(injector, mockIsExtendedDisplayAllowed,
             mockTopologyChangedCallback, topologyChangeExecutor, DisplayManagerService.SyncRoot(),
             mockTopologySavedCallback)
     }
@@ -195,7 +195,7 @@
 
     @Test
     fun addDisplay_external_extendedDisplaysDisabled() {
-        whenever(mockIsExtendedDisplayEnabled()).thenReturn(false)
+        whenever(mockIsExtendedDisplayAllowed()).thenReturn(false)
 
         for (displayInfo in displayInfos) {
             coordinator.onDisplayAdded(displayInfo)
@@ -208,7 +208,7 @@
     @Test
     fun addDisplay_overlay_extendedDisplaysDisabled() {
         displayInfos[0].type = Display.TYPE_OVERLAY
-        whenever(mockIsExtendedDisplayEnabled()).thenReturn(false)
+        whenever(mockIsExtendedDisplayAllowed()).thenReturn(false)
 
         for (displayInfo in displayInfos) {
             coordinator.onDisplayAdded(displayInfo)
@@ -220,17 +220,6 @@
     }
 
     @Test
-    fun addDisplay_notInDefaultDisplayGroup() {
-        displayInfos[0].displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1
-
-        coordinator.onDisplayAdded(displayInfos[0])
-
-        verify(mockTopology, never()).addDisplay(anyInt(), anyFloat(), anyFloat())
-        verify(mockTopologyChangedCallback, never()).invoke(any())
-        verify(mockTopologyStore, never()).restoreTopology(any())
-    }
-
-    @Test
     fun updateDisplay() {
         whenever(mockTopology.updateDisplay(eq(displayInfos[0].displayId), anyFloat(), anyFloat()))
             .thenReturn(true)
@@ -325,7 +314,7 @@
 
     @Test
     fun updateDisplay_external_extendedDisplaysDisabled() {
-        whenever(mockIsExtendedDisplayEnabled()).thenReturn(false)
+        whenever(mockIsExtendedDisplayAllowed()).thenReturn(false)
 
         for (displayInfo in displayInfos) {
             coordinator.onDisplayChanged(displayInfo)
@@ -339,7 +328,7 @@
     @Test
     fun updateDisplay_overlay_extendedDisplaysDisabled() {
         displayInfos[0].type = Display.TYPE_OVERLAY
-        whenever(mockIsExtendedDisplayEnabled()).thenReturn(false)
+        whenever(mockIsExtendedDisplayAllowed()).thenReturn(false)
 
         coordinator.onDisplayChanged(displayInfos[0])
 
@@ -349,17 +338,6 @@
     }
 
     @Test
-    fun updateDisplay_notInDefaultDisplayGroup() {
-        displayInfos[0].displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1
-
-        coordinator.onDisplayChanged(displayInfos[0])
-
-        verify(mockTopology, never()).updateDisplay(anyInt(), anyFloat(), anyFloat())
-        verify(mockTopologyCopy, never()).getGraph(any())
-        verify(mockTopologyChangedCallback, never()).invoke(any())
-    }
-
-    @Test
     fun removeDisplay() {
         addDisplay()
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
index 0bef3b89..10bea7d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -416,7 +416,7 @@
         final String uniqueId = "uniqueId";
         final IBinder displayToken = new Binder();
         when(mMockSufaceControlDisplayFactory.createDisplay(
-                any(), anyBoolean(), eq(uniqueId), anyFloat()))
+                any(), anyBoolean(), anyBoolean(), eq(uniqueId), anyFloat()))
                 .thenReturn(displayToken);
 
         // The display needs to be public, otherwise it will be considered never blank.
@@ -456,6 +456,49 @@
         verify(mMockCallback).onPaused();
     }
 
+    @EnableFlags(
+            android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE)
+    @Test
+    public void createVirtualDisplayLocked_neverBlank_optimizesForPower() {
+        final String uniqueId = "uniqueId";
+        final IBinder displayToken = new Binder();
+        final String name = "name";
+        when(mVirtualDisplayConfigMock.getName()).thenReturn(name);
+        when(mMockSufaceControlDisplayFactory.createDisplay(
+                any(), anyBoolean(), anyBoolean(), eq(uniqueId), anyFloat()))
+                .thenReturn(displayToken);
+
+        // Use a private display to cause the display to be never blank.
+        mAdapter.createVirtualDisplayLocked(mMockCallback,
+                /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+                uniqueId, /* surface= */ mSurfaceMock, 0, mVirtualDisplayConfigMock);
+
+        verify(mMockSufaceControlDisplayFactory).createDisplay(eq(name), eq(false), eq(true),
+                eq(uniqueId), anyFloat());
+    }
+
+    @EnableFlags(
+            android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE)
+    @Test
+    public void createVirtualDisplayLocked_blankable_optimizesForPerformance() {
+        final String uniqueId = "uniqueId";
+        final IBinder displayToken = new Binder();
+        final String name = "name";
+        when(mVirtualDisplayConfigMock.getName()).thenReturn(name);
+        when(mMockSufaceControlDisplayFactory.createDisplay(
+                any(), anyBoolean(), anyBoolean(), eq(uniqueId), anyFloat()))
+                .thenReturn(displayToken);
+
+        // Use a public display to cause the display to be blankable
+        mAdapter.createVirtualDisplayLocked(mMockCallback,
+                /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+                uniqueId, /* surface= */ mSurfaceMock, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
+                mVirtualDisplayConfigMock);
+
+        verify(mMockSufaceControlDisplayFactory).createDisplay(eq(name), eq(false), eq(false),
+                eq(uniqueId), anyFloat());
+    }
+
     private IVirtualDisplayCallback createCallback() {
         return new IVirtualDisplayCallback.Stub() {
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index 22c10f9..067230a 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -29,7 +29,6 @@
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -113,10 +112,10 @@
         doReturn(mContext).when(mContext).getApplicationContext();
 
         final Resources res = Mockito.spy(mContext.getResources());
+        doReturn(res).when(mContext).getResources();
         doReturn(MINIMAL_COLOR_MODES).when(res).getIntArray(R.array.config_availableColorModes);
         doReturn(true).when(res).getBoolean(R.bool.config_nightDisplayAvailable);
         doReturn(true).when(res).getBoolean(R.bool.config_displayWhiteBalanceAvailable);
-        when(mContext.getResources()).thenReturn(res);
         mResourcesSpy = res;
 
         mUserId = ActivityManager.getCurrentUser();
@@ -1105,10 +1104,11 @@
 
     @Test
     public void compositionColorSpaces_noResources() {
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
-            .thenReturn(new int[] {});
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
-            .thenReturn(new int[] {});
+        doReturn(new int[] {}).when(mResourcesSpy)
+                .getIntArray(R.array.config_displayCompositionColorModes);
+        doReturn(new int[] {}).when(mResourcesSpy)
+                .getIntArray(R.array.config_displayCompositionColorSpaces);
+
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
         verify(mDisplayTransformManager).setColorMode(
@@ -1118,16 +1118,15 @@
 
     @Test
     public void compositionColorSpaces_invalidResources() {
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
-                .thenReturn(new int[] {
-                        ColorDisplayManager.COLOR_MODE_NATURAL,
-                        // Missing second color mode
-                });
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
-                .thenReturn(new int[] {
-                        Display.COLOR_MODE_SRGB,
-                        Display.COLOR_MODE_DISPLAY_P3
-                });
+        doReturn(new int[] {
+                ColorDisplayManager.COLOR_MODE_NATURAL,
+                // Missing second color mode
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorModes);
+        doReturn(new int[] {
+                Display.COLOR_MODE_SRGB,
+                Display.COLOR_MODE_DISPLAY_P3
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorSpaces);
+
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
         verify(mDisplayTransformManager).setColorMode(
@@ -1137,14 +1136,13 @@
 
     @Test
     public void compositionColorSpaces_validResources_validColorMode() {
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
-                .thenReturn(new int[] {
-                        ColorDisplayManager.COLOR_MODE_NATURAL
-                });
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
-                .thenReturn(new int[] {
-                        Display.COLOR_MODE_SRGB,
-                });
+        doReturn(new int[] {
+                ColorDisplayManager.COLOR_MODE_NATURAL
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorModes);
+        doReturn(new int[] {
+                Display.COLOR_MODE_SRGB,
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorSpaces);
+
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
         verify(mDisplayTransformManager).setColorMode(
@@ -1154,14 +1152,13 @@
 
     @Test
     public void compositionColorSpaces_validResources_invalidColorMode() {
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
-                .thenReturn(new int[] {
-                        ColorDisplayManager.COLOR_MODE_NATURAL
-                });
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
-                .thenReturn(new int[] {
-                        Display.COLOR_MODE_SRGB,
-                });
+        doReturn(new int[] {
+                ColorDisplayManager.COLOR_MODE_NATURAL
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorModes);
+        doReturn(new int[] {
+                Display.COLOR_MODE_SRGB,
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorSpaces);
+
         setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
         startService();
         verify(mDisplayTransformManager).setColorMode(
@@ -1171,8 +1168,7 @@
 
     @Test
     public void getColorMode_noAvailableModes_returnsNotSet() {
-        when(mResourcesSpy.getIntArray(R.array.config_availableColorModes))
-                    .thenReturn(new int[] {});
+        doReturn(new int[] {}).when(mResourcesSpy).getIntArray(R.array.config_availableColorModes);
         startService();
         verify(mDisplayTransformManager, never()).setColorMode(anyInt(), any(), any(), anyInt());
         assertThat(mBinderService.getColorMode()).isEqualTo(-1);
@@ -1197,16 +1193,17 @@
 
     @Test
     public void sliderScalesWithinRange() {
+        doReturn(true).when(mRbcSpy).isAvailable(mContext);
+
+        doReturn(85).when(mResourcesSpy).getInteger(
+                R.integer.config_reduceBrightColorsStrengthMax);
+        doReturn(10).when(mResourcesSpy).getInteger(
+                R.integer.config_reduceBrightColorsStrengthMin);
+        doReturn(44).when(mResourcesSpy).getInteger(
+                R.integer.config_reduceBrightColorsStrengthDefault);
+
         // setup
         startService();
-        reset(mRbcSpy);
-        doReturn(true).when(mRbcSpy).isAvailable(mContext);
-        when(mContext.getResources().getInteger(
-                R.integer.config_reduceBrightColorsStrengthMax)).thenReturn(85);
-        when(mContext.getResources().getInteger(
-                R.integer.config_reduceBrightColorsStrengthMin)).thenReturn(10);
-        when(mContext.getResources().getInteger(
-                R.integer.config_reduceBrightColorsStrengthDefault)).thenReturn(44);
 
         // Valid value test //
         // set on, and to 90% of range
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
index 7c239ef..586ff52 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
@@ -328,6 +328,7 @@
                 case DREAM_STATE_STARTED -> startDream();
                 case DREAM_STATE_WOKEN -> wakeDream();
             }
+            mTestableLooper.processAllMessages();
         } while (mCurrentDreamState < state);
 
         return true;
diff --git a/services/tests/media/mediarouterservicetest/Android.bp b/services/tests/media/mediarouterservicetest/Android.bp
index aed3af6..f149f2e 100644
--- a/services/tests/media/mediarouterservicetest/Android.bp
+++ b/services/tests/media/mediarouterservicetest/Android.bp
@@ -9,6 +9,10 @@
 
 android_test {
     name: "MediaRouterServiceTests",
+    defaults: [
+        // For ExtendedMockito dependencies.
+        "modules-utils-testable-device-config-defaults",
+    ],
     srcs: [
         "src/**/*.java",
     ],
@@ -23,12 +27,17 @@
         "services.core",
         "truth",
     ],
+    libs: [
+        "android.test.base.stubs",
+        "android.test.runner.stubs",
+    ],
 
     platform_apis: true,
 
     test_suites: [
         // "device-tests",
         "general-tests",
+        "mts-statsd",
     ],
 
     certificate: "platform",
@@ -36,4 +45,5 @@
     optimize: {
         enabled: false,
     },
+    min_sdk_version: "30",
 }
diff --git a/services/tests/media/mediarouterservicetest/AndroidTest.xml b/services/tests/media/mediarouterservicetest/AndroidTest.xml
index b065681..646812b 100644
--- a/services/tests/media/mediarouterservicetest/AndroidTest.xml
+++ b/services/tests/media/mediarouterservicetest/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-tag" value="MediaRouterServiceTests" />
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-instrumentation" />
+    <option name="test-suite-tag" value="mts" />
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
 
@@ -26,7 +27,7 @@
         <option name="install-arg" value="-t" />
     </target_preparer>
 
-    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.server.media.tests" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
diff --git a/services/tests/media/mediarouterservicetest/src/com/android/server/media/MediaRouterMetricLoggerTest.java b/services/tests/media/mediarouterservicetest/src/com/android/server/media/MediaRouterMetricLoggerTest.java
new file mode 100644
index 0000000..5e401ae
--- /dev/null
+++ b/services/tests/media/mediarouterservicetest/src/com/android/server/media/MediaRouterMetricLoggerTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import static android.media.MediaRoute2ProviderService.REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA;
+import static android.media.MediaRoute2ProviderService.REASON_INVALID_COMMAND;
+import static android.media.MediaRoute2ProviderService.REASON_NETWORK_ERROR;
+import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
+import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
+import static android.media.MediaRoute2ProviderService.REASON_UNIMPLEMENTED;
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.testing.ExtendedMockitoRule;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaRouterMetricLoggerTest {
+    @Rule
+    public final ExtendedMockitoRule mExtendedMockitoRule =
+            new ExtendedMockitoRule.Builder(this).mockStatic(MediaRouterStatsLog.class).build();
+
+    private MediaRouterMetricLogger mLogger;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLogger = new MediaRouterMetricLogger();
+    }
+
+    @Test
+    public void addRequestInfo_addsRequestInfoToCache() {
+        long requestId = 123;
+        int eventType = MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+
+        mLogger.addRequestInfo(requestId, eventType);
+
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(1);
+    }
+
+    @Test
+    public void removeRequestInfo_removesRequestInfoFromCache() {
+        long requestId = 123;
+        int eventType = MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+        mLogger.addRequestInfo(requestId, eventType);
+
+        mLogger.removeRequestInfo(requestId);
+
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(0);
+    }
+
+    @Test
+    public void logOperationFailure_logsOperationFailure() {
+        int eventType = MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+        int result = MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
+        mLogger.logOperationFailure(eventType, result);
+        verify(
+                () ->
+                        MediaRouterStatsLog.write( // Use ExtendedMockito.verify and lambda
+                                MEDIA_ROUTER_EVENT_REPORTED, eventType, result));
+    }
+
+    @Test
+    public void logRequestResult_logsRequestResult() {
+        long requestId = 123;
+        int eventType = MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+        int result = MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS;
+        mLogger.addRequestInfo(requestId, eventType);
+
+        mLogger.logRequestResult(requestId, result);
+
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(0);
+        verify(
+                () ->
+                        MediaRouterStatsLog.write( // Use ExtendedMockito.verify and lambda
+                                MEDIA_ROUTER_EVENT_REPORTED, eventType, result));
+    }
+
+    @Test
+    public void convertResultFromReason_returnsCorrectResult() {
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_UNKNOWN_ERROR))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_REJECTED))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_NETWORK_ERROR))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_ROUTE_NOT_AVAILABLE))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_INVALID_COMMAND))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_UNIMPLEMENTED))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED);
+        assertThat(
+                        MediaRouterMetricLogger.convertResultFromReason(
+                                REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA))
+                .isEqualTo(
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(-1))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
+    }
+
+    @Test
+    public void getRequestCacheSize_returnsCorrectSize() {
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(0);
+        mLogger.addRequestInfo(
+                123, MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION);
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(1);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
index d6349fc..ab3784b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
@@ -32,7 +32,6 @@
 import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_USER_STOPPED;
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
 import static com.android.server.am.PendingIntentRecord.cancelReasonToString;
-import static com.android.window.flags.Flags.balClearAllowlistDuration;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -216,9 +215,7 @@
                 pir.getAllowlistDurationLocked(token);
         assertNotNull(allowlistDurationLockedAfterClear);
         assertEquals(1000, allowlistDurationLockedAfterClear.duration);
-        assertEquals(balClearAllowlistDuration()
-                        ? TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED
-                        : TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+        assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
                 allowlistDurationLocked.type);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
index 8aaa723..33bd95e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
@@ -51,6 +51,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.LocalServices;
+import com.android.server.backup.BackupRestoreTask.CancellationReason;
 import com.android.server.backup.internal.LifecycleOperationStorage;
 
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
@@ -368,9 +369,12 @@
         mConnectionManager.agentDisconnected(TEST_PACKAGE);
 
         mTestThread.join();
-        verify(mUserBackupManagerService).handleCancel(eq(123), eq(true));
-        verify(mUserBackupManagerService).handleCancel(eq(456), eq(true));
-        verify(mUserBackupManagerService).handleCancel(eq(789), eq(true));
+        verify(mUserBackupManagerService)
+                .handleCancel(eq(123), eq(CancellationReason.AGENT_DISCONNECTED));
+        verify(mUserBackupManagerService)
+                .handleCancel(eq(456), eq(CancellationReason.AGENT_DISCONNECTED));
+        verify(mUserBackupManagerService)
+                .handleCancel(eq(789), eq(CancellationReason.AGENT_DISCONNECTED));
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
index 8ce05e2..c9f86b0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
@@ -23,7 +23,6 @@
 import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
 import static android.view.Display.DEFAULT_DISPLAY_GROUP;
 
-import static com.android.server.power.ScreenUndimDetector.DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS;
 import static com.android.server.power.ScreenUndimDetector.KEY_KEEP_SCREEN_ON_ENABLED;
 import static com.android.server.power.ScreenUndimDetector.KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS;
 import static com.android.server.power.ScreenUndimDetector.KEY_UNDIMS_REQUIRED;
@@ -49,6 +48,7 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Tests for {@link com.android.server.power.ScreenUndimDetector}
@@ -61,7 +61,8 @@
                     POLICY_DIM,
                     POLICY_BRIGHT);
     private static final int OTHER_DISPLAY_GROUP = DEFAULT_DISPLAY_GROUP + 1;
-
+    private static final long DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS =
+            TimeUnit.MINUTES.toMillis(5);
     @ClassRule
     public static final TestableContext sContext = new TestableContext(
             InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
@@ -88,7 +89,8 @@
     @Before
     public void setup() {
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_KEEP_SCREEN_ON_ENABLED, Boolean.TRUE.toString(), false /*makeDefault*/);
         DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
                 KEY_UNDIMS_REQUIRED,
                 Integer.toString(1), false /*makeDefault*/);
@@ -108,10 +110,10 @@
 
     @Test
     public void recordScreenPolicy_disabledByFlag_noop() {
+        setup();
         DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
                 KEY_KEEP_SCREEN_ON_ENABLED, Boolean.FALSE.toString(), false /*makeDefault*/);
         mScreenUndimDetector.readValuesFromDeviceConfig();
-
         mScreenUndimDetector.recordScreenPolicy(DEFAULT_DISPLAY_GROUP, POLICY_DIM);
         mScreenUndimDetector.recordScreenPolicy(DEFAULT_DISPLAY_GROUP, POLICY_BRIGHT);
 
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 5165e34..fc864dd 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
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.spy;
@@ -330,31 +331,24 @@
             return invocation.callRealMethod();
         }).when(mHistory).readFragmentToParcel(any(), any());
 
-        // Prepare history for iteration
-        mHistory.iterate(0, MonotonicClock.UNDEFINED);
+        int eventsRead = 0;
+        BatteryStatsHistoryIterator iterator = mHistory.iterate(0, MonotonicClock.UNDEFINED);
+        while (iterator.hasNext()) {
+            HistoryItem item = iterator.next();
+            if (item.eventCode == HistoryItem.EVENT_JOB_START) {
+                eventsRead++;
+                assertThat(mReadFiles).containsExactly("123.bh");
+            } else if (item.eventCode == HistoryItem.EVENT_JOB_FINISH) {
+                eventsRead++;
+                assertThat(mReadFiles).containsExactly("123.bh", "1000.bh");
+            } else if (item.eventCode == HistoryItem.EVENT_ALARM) {
+                eventsRead++;
+                assertThat(mReadFiles).containsExactly("123.bh", "1000.bh", "2000.bh");
+            }
+        }
 
-        Parcel parcel = mHistory.getNextParcel(0, Long.MAX_VALUE);
-        assertThat(parcel).isNotNull();
-        assertThat(mReadFiles).containsExactly("123.bh");
-
-        // Skip to the end to force reading the next parcel
-        parcel.setDataPosition(parcel.dataSize());
-        mReadFiles.clear();
-        parcel = mHistory.getNextParcel(0, Long.MAX_VALUE);
-        assertThat(parcel).isNotNull();
-        assertThat(mReadFiles).containsExactly("1000.bh");
-
-        parcel.setDataPosition(parcel.dataSize());
-        mReadFiles.clear();
-        parcel = mHistory.getNextParcel(0, Long.MAX_VALUE);
-        assertThat(parcel).isNotNull();
-        assertThat(mReadFiles).containsExactly("2000.bh");
-
-        parcel.setDataPosition(parcel.dataSize());
-        mReadFiles.clear();
-        parcel = mHistory.getNextParcel(0, Long.MAX_VALUE);
-        assertThat(parcel).isNull();
-        assertThat(mReadFiles).isEmpty();
+        assertThat(eventsRead).isEqualTo(3);
+        assertThat(mReadFiles).containsExactly("123.bh", "1000.bh", "2000.bh", "3000.bh");
     }
 
     @Test
@@ -372,25 +366,19 @@
             return invocation.callRealMethod();
         }).when(mHistory).readFragmentToParcel(any(), any());
 
-        // Prepare history for iteration
-        mHistory.iterate(1000, 3000);
+        BatteryStatsHistoryIterator iterator = mHistory.iterate(1000, 3000);
+        while (iterator.hasNext()) {
+            HistoryItem item = iterator.next();
+            if (item.eventCode == HistoryItem.EVENT_JOB_START) {
+                fail("Event outside the range");
+            } else if (item.eventCode == HistoryItem.EVENT_JOB_FINISH) {
+                assertThat(mReadFiles).containsExactly("1000.bh");
+            } else if (item.eventCode == HistoryItem.EVENT_ALARM) {
+                fail("Event outside the range");
+            }
+        }
 
-        Parcel parcel = mHistory.getNextParcel(1000, 3000);
-        assertThat(parcel).isNotNull();
-        assertThat(mReadFiles).containsExactly("1000.bh");
-
-        // Skip to the end to force reading the next parcel
-        parcel.setDataPosition(parcel.dataSize());
-        mReadFiles.clear();
-        parcel = mHistory.getNextParcel(1000, 3000);
-        assertThat(parcel).isNotNull();
-        assertThat(mReadFiles).containsExactly("2000.bh");
-
-        parcel.setDataPosition(parcel.dataSize());
-        mReadFiles.clear();
-        parcel = mHistory.getNextParcel(1000, 3000);
-        assertThat(parcel).isNull();
-        assertThat(mReadFiles).isEmpty();
+        assertThat(mReadFiles).containsExactly("1000.bh", "2000.bh");
     }
 
     private void prepareMultiFileHistory() {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
index ea83825..69877c3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
@@ -660,6 +660,59 @@
         assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1);
     }
 
+    @Test
+    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+    public void onMotionEvent_flagOn_lazyInitAutoclickScrollPanel() {
+        assertThat(mController.mAutoclickScrollPanel).isNull();
+
+        injectFakeMouseActionHoverMoveEvent();
+
+        assertThat(mController.mAutoclickScrollPanel).isNotNull();
+    }
+
+    @Test
+    @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+    public void onMotionEvent_flagOff_notInitAutoclickScrollPanel() {
+        assertThat(mController.mAutoclickScrollPanel).isNull();
+
+        injectFakeMouseActionHoverMoveEvent();
+
+        assertThat(mController.mAutoclickScrollPanel).isNull();
+    }
+
+    @Test
+    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+    public void onDestroy_flagOn_hideAutoclickScrollPanel() {
+        injectFakeMouseActionHoverMoveEvent();
+        AutoclickScrollPanel mockAutoclickScrollPanel = mock(AutoclickScrollPanel.class);
+        mController.mAutoclickScrollPanel = mockAutoclickScrollPanel;
+
+        mController.onDestroy();
+
+        verify(mockAutoclickScrollPanel).hide();
+    }
+
+    @Test
+    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+    public void changeFromScrollToOtherClickType_hidesScrollPanel() {
+        injectFakeMouseActionHoverMoveEvent();
+
+        // Set active click type to SCROLL.
+        mController.clickPanelController.handleAutoclickTypeChange(
+                AutoclickTypePanel.AUTOCLICK_TYPE_SCROLL);
+
+        // Show the scroll panel.
+        mController.mAutoclickScrollPanel.show();
+        assertThat(mController.mAutoclickScrollPanel.isVisible()).isTrue();
+
+        // Change click type to LEFT_CLICK.
+        mController.clickPanelController.handleAutoclickTypeChange(
+                AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK);
+
+        // Verify scroll panel is hidden.
+        assertThat(mController.mAutoclickScrollPanel.isVisible()).isFalse();
+    }
+
     private void injectFakeMouseActionHoverMoveEvent() {
         MotionEvent event = getFakeMotionHoverMoveEvent();
         event.setSource(InputDevice.SOURCE_MOUSE);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickScrollPanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickScrollPanelTest.java
new file mode 100644
index 0000000..f445b50
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickScrollPanelTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.autoclick;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper;
+import android.view.WindowManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/** Test cases for {@link AutoclickScrollPanel}. */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class AutoclickScrollPanelTest {
+    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Rule
+    public TestableContext mTestableContext =
+            new TestableContext(getInstrumentation().getContext());
+
+    @Mock private WindowManager mMockWindowManager;
+    private AutoclickScrollPanel mScrollPanel;
+
+    @Before
+    public void setUp() {
+        mTestableContext.addMockSystemService(Context.WINDOW_SERVICE, mMockWindowManager);
+        mScrollPanel = new AutoclickScrollPanel(mTestableContext, mMockWindowManager);
+    }
+
+    @Test
+    public void show_addsViewToWindowManager() {
+        mScrollPanel.show();
+
+        // Verify view is added to window manager.
+        verify(mMockWindowManager).addView(any(), any(WindowManager.LayoutParams.class));
+
+        // Verify isVisible reflects correct state.
+        assertThat(mScrollPanel.isVisible()).isTrue();
+    }
+
+    @Test
+    public void show_alreadyVisible_doesNotAddAgain() {
+        // Show twice.
+        mScrollPanel.show();
+        mScrollPanel.show();
+
+        // Verify addView was only called once.
+        verify(mMockWindowManager, times(1)).addView(any(), any());
+    }
+
+    @Test
+    public void hide_removesViewFromWindowManager() {
+        // First show the panel.
+        mScrollPanel.show();
+        // Then hide it.
+        mScrollPanel.hide();
+        // Verify view is removed from window manager.
+        verify(mMockWindowManager).removeView(any());
+        // Verify scroll panel is hidden.
+        assertThat(mScrollPanel.isVisible()).isFalse();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index ac27a97..9ec99c6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -30,7 +30,10 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -248,6 +251,40 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testRegister_RegistersPointerMotionFilter() {
+        register(DISPLAY_0);
+
+        verify(mMockInputManager).registerAccessibilityPointerMotionFilter(
+                any(InputManagerInternal.AccessibilityPointerMotionFilter.class));
+
+        // If a filter is already registered, adding a display won't invoke another filter
+        // registration.
+        clearInvocations(mMockInputManager);
+        register(DISPLAY_1);
+        register(INVALID_DISPLAY);
+
+        verify(mMockInputManager, times(0)).registerAccessibilityPointerMotionFilter(
+                any(InputManagerInternal.AccessibilityPointerMotionFilter.class));
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testUnregister_UnregistersPointerMotionFilter() {
+        register(DISPLAY_0);
+        register(DISPLAY_1);
+        clearInvocations(mMockInputManager);
+
+        mFullScreenMagnificationController.unregister(DISPLAY_1);
+        // There's still an active display. Don't unregister yet.
+        verify(mMockInputManager, times(0)).registerAccessibilityPointerMotionFilter(
+                nullable(InputManagerInternal.AccessibilityPointerMotionFilter.class));
+
+        mFullScreenMagnificationController.unregister(DISPLAY_0);
+        verify(mMockInputManager, times(1)).registerAccessibilityPointerMotionFilter(isNull());
+    }
+
+    @Test
     public void testInitialState_noMagnificationAndMagnificationRegionReadFromWindowManager() {
         for (int i = 0; i < DISPLAY_COUNT; i++) {
             initialState_noMagnificationAndMagnificationRegionReadFromWindowManager(i);
@@ -699,6 +736,63 @@
     }
 
     @Test
+    public void testSetOffset_whileMagnifying_offsetsMove() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setOffset_whileMagnifying_offsetsMove(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setOffset_whileMagnifying_offsetsMove(int displayId) {
+        register(displayId);
+        PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+        for (final float scale : new float[]{2.0f, 2.5f, 3.0f}) {
+            assertTrue(mFullScreenMagnificationController
+                    .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, true, false,
+                            SERVICE_ID_1));
+            mMessageCapturingHandler.sendAllMessages();
+
+            for (final PointF center : new PointF[]{
+                    INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER,
+                    INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER}) {
+                Mockito.clearInvocations(mMockWindowManager);
+                PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, center, scale);
+                mFullScreenMagnificationController.setOffset(displayId, newOffsets.x, newOffsets.y,
+                        SERVICE_ID_1);
+                mMessageCapturingHandler.sendAllMessages();
+
+                MagnificationSpec expectedSpec = getMagnificationSpec(scale, newOffsets);
+                verify(mMockWindowManager)
+                        .setMagnificationSpec(eq(displayId), argThat(closeTo(expectedSpec)));
+                assertEquals(center.x, mFullScreenMagnificationController.getCenterX(displayId),
+                        0.0);
+                assertEquals(center.y, mFullScreenMagnificationController.getCenterY(displayId),
+                        0.0);
+                verify(mMockValueAnimator, times(0)).start();
+            }
+        }
+    }
+
+    @Test
+    public void testSetOffset_whileNotMagnifying_hasNoEffect() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setOffset_whileNotMagnifying_hasNoEffect(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setOffset_whileNotMagnifying_hasNoEffect(int displayId) {
+        register(displayId);
+        Mockito.reset(mMockWindowManager);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
+        mFullScreenMagnificationController.setOffset(displayId, 100, 100, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
+        mFullScreenMagnificationController.setOffset(displayId, 200, 200, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+    }
+
+    @Test
     @RequiresFlagsEnabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
     public void testStartFling_whileMagnifying_flings() throws InterruptedException {
         for (int i = 0; i < DISPLAY_COUNT; i++) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 5c126d1..4ea5fcf 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -1419,6 +1419,12 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testMouseMoveEventsDoNotMoveMagnifierViewport() {
+        runMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_MOUSE);
+    }
+
+    @Test
     public void testStylusMoveEventsDoNotMoveMagnifierViewport() {
         runMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_STYLUS);
     }
@@ -1467,11 +1473,28 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testMouseHoverMoveEventsDoNotMoveMagnifierViewport() {
+        // Note that this means mouse hover shouldn't be handled here.
+        // FullScreenMagnificationPointerMotionEventFilter handles mouse input events.
+        runHoverMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_MOUSE);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testStylusHoverMoveEventsDoNotMoveMagnifierViewport() {
+        // TODO(b/398984690): We will revisit the behavior.
+        runHoverMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_STYLUS);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
     public void testMouseHoverMoveEventsMoveMagnifierViewport() {
         runHoverMovesViewportTest(InputDevice.SOURCE_MOUSE);
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
     public void testStylusHoverMoveEventsMoveMagnifierViewport() {
         runHoverMovesViewportTest(InputDevice.SOURCE_STYLUS);
     }
@@ -1497,6 +1520,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
     public void testMouseMoveEventsMoveMagnifierViewport() {
         final EventCaptor eventCaptor = new EventCaptor();
         mMgh.setNext(eventCaptor);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilterTest.java
new file mode 100644
index 0000000..a8315d4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilterTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.magnification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class FullScreenMagnificationPointerMotionEventFilterTest {
+    @Mock
+    private FullScreenMagnificationController mMockFullScreenMagnificationController;
+
+    private FullScreenMagnificationPointerMotionEventFilter mFilter;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mFilter = new FullScreenMagnificationPointerMotionEventFilter(
+                mMockFullScreenMagnificationController);
+    }
+
+    @Test
+    public void inactiveDisplay_doNothing() {
+        when(mMockFullScreenMagnificationController.isActivated(anyInt())).thenReturn(false);
+
+        float[] delta = new float[]{1.f, 2.f};
+        float[] result = mFilter.filterPointerMotionEvent(delta[0], delta[1], 3.0f, 4.0f, 0);
+        assertThat(result).isEqualTo(delta);
+    }
+
+    @Test
+    public void testContinuousMove() {
+        when(mMockFullScreenMagnificationController.isActivated(anyInt())).thenReturn(true);
+        when(mMockFullScreenMagnificationController.getScale(anyInt())).thenReturn(3.f);
+
+        float[] delta = new float[]{5.f, 10.f};
+        float[] result = mFilter.filterPointerMotionEvent(delta[0], delta[1], 20.f, 30.f, 0);
+        assertThat(result).isEqualTo(delta);
+        // At the first cursor move, it goes to (20, 30) + (5, 10) = (25, 40). The scale is 3.0.
+        // The expected offset is (-25 * (3-1), -40 * (3-1)) = (-50, -80).
+        verify(mMockFullScreenMagnificationController)
+                .setOffset(eq(0), eq(-50.f), eq(-80.f), anyInt());
+
+        float[] delta2 = new float[]{10.f, 5.f};
+        float[] result2 = mFilter.filterPointerMotionEvent(delta2[0], delta2[1], 25.f, 40.f, 0);
+        assertThat(result2).isEqualTo(delta2);
+        // At the second cursor move, it goes to (25, 40) + (10, 5) = (35, 40). The scale is 3.0.
+        // The expected offset is (-35 * (3-1), -45 * (3-1)) = (-70, -90).
+        verify(mMockFullScreenMagnificationController)
+                .setOffset(eq(0), eq(-70.f), eq(-90.f), anyInt());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpXmlPersistenceTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpXmlPersistenceTest.java
index ae973be..56f802b 100644
--- a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpXmlPersistenceTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpXmlPersistenceTest.java
@@ -89,8 +89,7 @@
         int attributionChainId = AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
 
         mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, null, opFlags,
-                uidState, accessTime, duration, attributionFlags, attributionChainId,
-                DiscreteOpsXmlRegistry.ACCESS_TYPE_FINISH_OP);
+                uidState, accessTime, duration, attributionFlags, attributionChainId);
 
         // Verify in-memory object is correct
         fetchDiscreteOpsAndValidate(uid, packageName, op, deviceId, null, accessTime,
@@ -121,8 +120,7 @@
         int attributionChainId = 10;
 
         mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, null, opFlags,
-                uidState, accessTime, duration, attributionFlags, attributionChainId,
-                DiscreteOpsXmlRegistry.ACCESS_TYPE_START_OP);
+                uidState, accessTime, duration, attributionFlags, attributionChainId);
 
         fetchDiscreteOpsAndValidate(uid, packageName, op, deviceId, null, accessTime,
                 duration, uidState, opFlags, attributionFlags, attributionChainId);
diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java
index 8eea1c7..6c66f149 100644
--- a/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java
@@ -70,7 +70,7 @@
                     opEvent.getDeviceId(), opEvent.getOpCode(), opEvent.getAttributionTag(),
                     opEvent.getOpFlags(), opEvent.getUidState(), opEvent.getAccessTime(),
                     opEvent.getDuration(), opEvent.getAttributionFlags(),
-                    (int) opEvent.getChainId(), DiscreteOpsRegistry.ACCESS_TYPE_NOTE_OP);
+                    (int) opEvent.getChainId());
         }
         xmlRegistry.writeAndClearOldAccessHistory();
         assertThat(xmlRegistry.readLargestChainIdFromDiskLocked()).isEqualTo(RECORD_COUNT);
@@ -104,7 +104,7 @@
                     opEvent.getDeviceId(), opEvent.getOpCode(), opEvent.getAttributionTag(),
                     opEvent.getOpFlags(), opEvent.getUidState(), opEvent.getAccessTime(),
                     opEvent.getDuration(), opEvent.getAttributionFlags(),
-                    (int) opEvent.getChainId(), DiscreteOpsRegistry.ACCESS_TYPE_NOTE_OP);
+                    (int) opEvent.getChainId());
         }
         // flush records from cache to the database.
         sqlRegistry.shutdown();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 30aa8ce..01bcc25 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -143,6 +143,7 @@
 import android.provider.Settings;
 import android.security.KeyChain;
 import android.security.keystore.AttestationUtils;
+import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.test.MoreAsserts;
@@ -8715,6 +8716,47 @@
         }
     }
 
+    @RequiresFlagsEnabled(Flags.FLAG_REMOVE_MANAGED_ESIM_ON_WORK_PROFILE_DELETION)
+    @Test
+    public void testManagedProfileDeleted_managedEmbeddedSubscriptionDeleted() throws Exception {
+        // Setup PO mode.
+        setupProfileOwner();
+        // Mock SubscriptionManager to return a subscription managed by the profile owner package.
+        int managedSubscriptionId = 42;
+        SubscriptionInfo managedSubscription = new SubscriptionInfo.Builder().setCardId(1).setId(
+                managedSubscriptionId).setGroupOwner(admin1.getPackageName()).build();
+        when(getServices().subscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
+                List.of(managedSubscription));
+
+        // Send a ACTION_MANAGED_PROFILE_REMOVED broadcast to emulate a managed profile being
+        // removed.
+        sendBroadcastWithUser(dpms, Intent.ACTION_MANAGED_PROFILE_REMOVED, CALLER_USER_HANDLE);
+
+        // Verify that EuiccManager was called to delete the subscription.
+        verify(getServices().euiccManager).deleteSubscription(eq(managedSubscriptionId), any());
+    }
+
+    @RequiresFlagsDisabled(Flags.FLAG_REMOVE_MANAGED_ESIM_ON_WORK_PROFILE_DELETION)
+    @Test
+    public void testManagedProfileDeleted_flagDisabled_managedEmbeddedSubscriptionDeleted()
+            throws Exception {
+        // Set up PO mode.
+        setupProfileOwner();
+        // Mock SubscriptionManager to return a subscription managed by the profile owner package.
+        int managedSubscriptionId = 42;
+        SubscriptionInfo managedSubscription = new SubscriptionInfo.Builder().setCardId(1).setId(
+                managedSubscriptionId).setGroupOwner(admin1.getPackageName()).build();
+        when(getServices().subscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
+                List.of(managedSubscription));
+
+        // Send a ACTION_MANAGED_PROFILE_REMOVED broadcast to emulate a managed profile being
+        // removed.
+        sendBroadcastWithUser(dpms, Intent.ACTION_MANAGED_PROFILE_REMOVED, CALLER_USER_HANDLE);
+
+        // Verify that EuiccManager was not called to delete the subscription.
+        verifyZeroInteractions(getServices().euiccManager);
+    }
+
     private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) {
         final AppOpsManager.PackageOps vpnOp = new AppOpsManager.PackageOps(userVpnPackage,
                 userVpnUid, List.of(new AppOpsManager.OpEntry(
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 00b0c55..479af73 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -253,6 +253,8 @@
                 return mMockSystemServices.subscriptionManager;
             case Context.USB_SERVICE:
                 return mMockSystemServices.usbManager;
+            case Context.EUICC_SERVICE:
+                return mMockSystemServices.euiccManager;
         }
         throw new UnsupportedOperationException();
     }
@@ -487,6 +489,14 @@
     }
 
     @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+        mMockSystemServices.registerReceiver(receiver, filter, scheduler);
+        return spiedContext.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+                scheduler, flags);
+    }
+
+    @Override
     public void unregisterReceiver(BroadcastReceiver receiver) {
         mMockSystemServices.unregisterReceiver(receiver);
         spiedContext.unregisterReceiver(receiver);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 3e4448c1..d01fa91 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -68,6 +68,7 @@
 import android.security.KeyChain;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.euicc.EuiccManager;
 import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
 import android.util.ArrayMap;
@@ -151,6 +152,7 @@
     public final File dataDir;
     public final PolicyPathProvider pathProvider;
     public final SupervisionManagerInternal supervisionManagerInternal;
+    public final EuiccManager euiccManager;
 
     private final Map<String, PackageState> mTestPackageStates = new ArrayMap<>();
 
@@ -206,6 +208,7 @@
         roleManagerForMock = mock(RoleManagerForMock.class);
         subscriptionManager = mock(SubscriptionManager.class);
         supervisionManagerInternal = mock(SupervisionManagerInternal.class);
+        euiccManager = mock(EuiccManager.class);
 
         // Package manager is huge, so we use a partial mock instead.
         packageManager = spy(realContext.getPackageManager());
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 2da2f50..e836780 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.locksettings;
 
+import static android.content.pm.UserInfo.FLAG_FOR_TESTING;
 import static android.content.pm.UserInfo.FLAG_FULL;
 import static android.content.pm.UserInfo.FLAG_MAIN;
 import static android.content.pm.UserInfo.FLAG_PRIMARY;
@@ -44,6 +45,8 @@
 
 import android.app.PropertyInvalidatedCache;
 import android.app.admin.PasswordMetrics;
+import android.content.ComponentName;
+import android.content.pm.UserInfo;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
@@ -357,6 +360,45 @@
     }
 
     @Test
+    public void testEscrowDataRetainedWhenManagedUserVerifiesCredential() throws RemoteException {
+        when(mDeviceStateCache.isUserOrganizationManaged(anyInt())).thenReturn(true);
+
+        LockscreenCredential password = newPassword("password");
+        initSpAndSetCredential(PRIMARY_USER_ID, password);
+
+        mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */);
+
+        assertTrue("Escrow data was destroyed", mSpManager.hasEscrowData(PRIMARY_USER_ID));
+    }
+
+    @Test
+    public void testEscrowDataRetainedWhenUnmanagedTestUserVerifiesCredential()
+            throws RemoteException {
+        when(mDeviceStateCache.isUserOrganizationManaged(anyInt())).thenReturn(false);
+        UserInfo userInfo = mUserManagerInternal.getUserInfo(PRIMARY_USER_ID);
+        userInfo.flags |= FLAG_FOR_TESTING;
+
+        LockscreenCredential password = newPassword("password");
+        initSpAndSetCredential(PRIMARY_USER_ID, password);
+
+        mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */);
+
+        assertTrue("Escrow data was destroyed", mSpManager.hasEscrowData(PRIMARY_USER_ID));
+    }
+
+    @Test
+    public void testEscrowDataDeletedWhenUnmanagedUserVerifiesCredential() throws RemoteException {
+        when(mDeviceStateCache.isUserOrganizationManaged(anyInt())).thenReturn(false);
+
+        LockscreenCredential password = newPassword("password");
+        initSpAndSetCredential(PRIMARY_USER_ID, password);
+
+        mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */);
+
+        assertFalse("Escrow data wasn't destroyed", mSpManager.hasAnyEscrowData(PRIMARY_USER_ID));
+    }
+
+    @Test
     public void testTokenBasedClearPassword() throws RemoteException {
         LockscreenCredential password = newPassword("password");
         LockscreenCredential pattern = newPattern("123654");
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 f994660..b842d3a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -389,6 +389,44 @@
     }
 
     @Test
+    public void testSupervisingProfile() throws Exception {
+        assumeTrue("Device doesn't support supervising profiles ",
+                mUserManager.isUserTypeEnabled(UserManager.USER_TYPE_PROFILE_SUPERVISING));
+
+        final UserTypeDetails userTypeDetails =
+                UserTypeFactory.getUserTypes().get(UserManager.USER_TYPE_PROFILE_SUPERVISING);
+        assertWithMessage("No supervising user type on device").that(userTypeDetails).isNotNull();
+
+
+        // Create supervising profile if it doesn't exist
+        UserInfo supervisingUser = getSupervisingProfile();
+        if (supervisingUser == null) {
+            supervisingUser = createUser("Supervising",
+                    UserManager.USER_TYPE_PROFILE_SUPERVISING, /*flags*/ 0);
+        }
+        assertWithMessage("Couldn't create supervising profile").that(supervisingUser).isNotNull();
+        UserHandle supervisingHandle = supervisingUser.getUserHandle();
+
+        // Test that only one supervising profile can be created
+        final UserInfo secondSupervisingProfile =
+                createUser("Supervising", UserManager.USER_TYPE_PROFILE_SUPERVISING,
+                        /*flags*/ 0);
+        assertThat(secondSupervisingProfile).isNull();
+
+        // Verify that the supervising profile doesn't have a parent
+        assertThat(mUserManager.getProfileParent(supervisingHandle.getIdentifier())).isNull();
+
+        // Make sure that the supervising profile can be started in the background, and that it
+        // is visible
+        final boolean isStarted = mActivityManager.startProfile(supervisingHandle);
+        assertWithMessage("Unable to start supervising profile").that(isStarted).isTrue();
+        final UserManager umSupervising = (UserManager) mContext.createPackageContextAsUser(
+                "android", 0, supervisingHandle).getSystemService(Context.USER_SERVICE);
+        assertWithMessage("Supervising profile not visible").that(
+                umSupervising.isUserVisible()).isTrue();
+    }
+
+    @Test
     public void testGetProfileAccessibilityString_throwsExceptionForNonProfileUser() {
         UserInfo user1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
         assertThat(user1).isNotNull();
@@ -2198,4 +2236,13 @@
         assertEquals(actual.getLevel(), expected.getLevel());
     }
 
+    @Nullable
+    private UserInfo getSupervisingProfile() {
+        for (UserInfo user : mUserManager.getUsers()) {
+            if (user.userType.equals(UserManager.USER_TYPE_PROFILE_SUPERVISING)) {
+                return user;
+            }
+        }
+        return null;
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index 4eac1d1..a9759c8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -102,7 +102,9 @@
 import platform.test.runner.parameterized.Parameters;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 @SmallTest
 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the class.
@@ -4443,4 +4445,97 @@
         verify(mCallback).sendAppProvidedSummaryDeleteIntent(eq(pkg),
                 eq(deleteIntentofFirstSummary));
     }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
+    public void testGroupSummaryAdded_hadUngroupedNotif_doesNotAutogroup() {
+        // Scenario:
+        //  * child notification posted before summary; added to ungrouped notifications
+        //  * summary posted, so now the child has a group summary and is no longer "ungrouped
+        //  * another ungrouped notification is posted
+        // Confirm that the first notification (that now has a summary) is not autogrouped.
+
+        // Bookkeeping items
+        List<NotificationRecord> notifList = new ArrayList<>();
+        Map<String, NotificationRecord> summaryByGroupKey = new HashMap<>();
+
+        // Setup: post AUTOGROUP_AT_COUNT - 2 notifications so that the next notification would not
+        // trigger autogrouping, but the one after that would
+        for (int i = 0; i < AUTOGROUP_AT_COUNT - 2; i++) {
+            NotificationRecord child = getNotificationRecord(mPkg, i, "", mUser, "group" + i, false,
+                    IMPORTANCE_DEFAULT);
+            notifList.add(child);
+            mGroupHelper.onNotificationPostedWithDelay(child, notifList, summaryByGroupKey);
+        }
+
+        // Group child: posted enough before its associated summary to be put in the "ungrouped"
+        // set of notifications
+        NotificationRecord groupChild = getNotificationRecord(mPkg, AUTOGROUP_AT_COUNT - 2, "",
+                mUser, "specialGroup", false, IMPORTANCE_DEFAULT);
+        notifList.add(groupChild);
+        mGroupHelper.onNotificationPostedWithDelay(groupChild, notifList, summaryByGroupKey);
+
+        // Group summary: posted after child 1
+        NotificationRecord groupSummary = getNotificationRecord(mPkg, AUTOGROUP_AT_COUNT - 1, "",
+                mUser, "specialGroup", true, IMPORTANCE_DEFAULT);
+        notifList.add(groupSummary);
+        summaryByGroupKey.put(groupSummary.getSbn().getGroupKey(), groupSummary);
+        mGroupHelper.onGroupSummaryAdded(groupSummary, notifList);
+        mGroupHelper.onNotificationPostedWithDelay(groupSummary, notifList, summaryByGroupKey);
+
+        // One more notification posted to the group; because its summary already exists, it should
+        // never be counted as an "ungrouped" notification
+        NotificationRecord groupChild2 = getNotificationRecord(mPkg, AUTOGROUP_AT_COUNT, "",
+                mUser, "specialGroup", false, IMPORTANCE_DEFAULT);
+        notifList.add(groupChild2);
+        mGroupHelper.onNotificationPostedWithDelay(groupChild2, notifList, summaryByGroupKey);
+
+        // Now one more ungrouped notification; this would have put the number of "ungrouped"
+        // notifications above the limit if the first groupChild notification were left ungrouped
+        NotificationRecord extra = getNotificationRecord(mPkg, AUTOGROUP_AT_COUNT + 1, "", mUser,
+                "yetAnotherGroup", false, IMPORTANCE_DEFAULT);
+        notifList.add(extra);
+        mGroupHelper.onNotificationPostedWithDelay(extra, notifList, summaryByGroupKey);
+
+        // no autogrouping should have occurred
+        verifyZeroInteractions(mCallback);
+    }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
+    public void testGroupSummaryAdded_onlyUnrelatedGroupedNotifs() {
+        // If all of the existing ungrouped notifications have nothing to do with the summary
+        // they should still get grouped as needed.
+        List<NotificationRecord> notifList = new ArrayList<>();
+        Map<String, NotificationRecord> summaryByGroupKey = new HashMap<>();
+
+        // Post 1 fewer than the autogroupable notifications, each associated with a different
+        // group without a summary.
+        for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
+            NotificationRecord child = getNotificationRecord(mPkg, i, "", mUser, "group" + i, false,
+                    IMPORTANCE_DEFAULT);
+            notifList.add(child);
+            mGroupHelper.onNotificationPostedWithDelay(child, notifList, summaryByGroupKey);
+        }
+
+        // At this point we do not yet expect autogrouping.
+        // Add a group summary that is a summary associated with none of the above notifications.
+        // Because this gets considered a "summary without children", all of these notifications
+        // should now be autogrouped.
+        NotificationRecord summary = getNotificationRecord(mPkg, AUTOGROUP_AT_COUNT, "", mUser,
+                "summaryGroup", true, IMPORTANCE_DEFAULT);
+        notifList.add(summary);
+        summaryByGroupKey.put(summary.getSbn().getKey(), summary);
+        mGroupHelper.onGroupSummaryAdded(summary, notifList);
+        mGroupHelper.onNotificationPostedWithDelay(summary, notifList, summaryByGroupKey);
+
+        // all of the above posted notifications should be autogrouped
+        String expectedGroupKey = getExpectedAutogroupKey(
+                getNotificationRecord(mPkg, 0, String.valueOf(0), mUser));
+        verify(mCallback, times(1)).addAutoGroupSummary(
+                anyInt(), eq(mPkg), anyString(), eq(expectedGroupKey),
+                anyInt(), eq(getNotificationAttributes(BASE_FLAGS)));
+        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+                eq(expectedGroupKey), anyBoolean());
+    }
 }
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 04335df..2baf0c1 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -247,6 +247,7 @@
         assertThat(mVibratorProviders.get(VIBRATOR_ID).getAmplitudes()).isEmpty();
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_singleVibratorWaveform_runsVibrationAndChangesAmplitudes() {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
@@ -269,7 +270,10 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED)
+    @EnableFlags({
+            Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED,
+            Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING,
+    })
     public void vibrate_singleWaveformWithAdaptiveHapticsScaling_scalesAmplitudesProperly() {
         // No user settings scale.
         setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
@@ -296,7 +300,10 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED)
+    @EnableFlags({
+            Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED,
+            Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING,
+    })
     public void vibrate_withVibrationParamsRequestStalling_timeoutRequestAndApplyNoScaling() {
         // No user settings scale.
         setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
@@ -357,6 +364,7 @@
         }
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_singleVibratorRepeatingShortAlwaysOnWaveform_turnsVibratorOnForLonger()
             throws Exception {
@@ -380,6 +388,7 @@
                 .containsExactly(expectedOneShot(5000)).inOrder();
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_singleVibratorPatternWithZeroDurationSteps_skipsZeroDurationSteps() {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
@@ -399,6 +408,7 @@
                 .containsExactlyElementsIn(expectedOneShots(100L, 150L)).inOrder();
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_singleVibratorPatternWithZeroDurationAndAmplitude_skipsZeroDurationSteps() {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
@@ -537,6 +547,7 @@
         assertThat(fakeVibrator.getEffectSegments(vibration.id)).hasSize(10);
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_singleVibratorRepeatingLongAlwaysOnWaveform_turnsVibratorOnForACycle()
             throws Exception {
@@ -700,6 +711,7 @@
                 .containsExactly(expectedPrebaked(VibrationEffect.EFFECT_THUD)).inOrder();
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_singleVibratorPrebakedAndUnsupportedEffectWithFallback_runsFallback() {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
@@ -1247,6 +1259,7 @@
                 .containsExactly(expected).inOrder();
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_multipleStereo_runsVibrationOnRightVibrators() {
         mockVibrators(1, 2, 3, 4);
@@ -1479,6 +1492,7 @@
         assertThat(mVibratorProviders.get(1).getAmplitudes()).isEmpty();
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_multipleWaveforms_playsWaveformsInParallel() throws Exception {
         mockVibrators(1, 2, 3);
@@ -1544,8 +1558,8 @@
                         VibrationEffect.createOneShot(
                                 expectedDuration, VibrationEffect.DEFAULT_AMPLITUDE)));
 
-        startThreadAndDispatcher(vibration);
         long startTime = SystemClock.elapsedRealtime();
+        startThreadAndDispatcher(vibration);
 
         vibration.waitForEnd();
         long vibrationEndTime = SystemClock.elapsedRealtime();
@@ -1554,15 +1568,13 @@
         long completionTime = SystemClock.elapsedRealtime();
 
         verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibration.id), anyLong());
-        // Vibration ends after duration, thread completed after ramp down
-        assertThat(vibrationEndTime - startTime).isAtLeast(expectedDuration);
+        // Vibration ends before ramp down, thread completed after ramp down
         assertThat(vibrationEndTime - startTime).isLessThan(expectedDuration + rampDownDuration);
         assertThat(completionTime - startTime).isAtLeast(expectedDuration + rampDownDuration);
     }
 
     @Test
-    public void vibrate_withVibratorCallbackDelayShorterThanTimeout_vibrationFinishedAfterDelay()
-            throws Exception {
+    public void vibrate_withVibratorCallbackDelayShorterThanTimeout_vibrationFinishedAfterDelay() {
         long expectedDuration = 10;
         long callbackDelay = VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT / 2;
 
@@ -1577,10 +1589,8 @@
         long startTime = SystemClock.elapsedRealtime();
         startThreadAndDispatcher(vibration);
 
-        vibration.waitForEnd();
-        long vibrationEndTime = SystemClock.elapsedRealtime();
-
         waitForCompletion(TEST_TIMEOUT_MILLIS);
+        long vibrationEndTime = SystemClock.elapsedRealtime();
 
         verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibration.id), anyLong());
         assertThat(vibrationEndTime - startTime).isAtLeast(expectedDuration + callbackDelay);
@@ -1588,8 +1598,7 @@
 
     @LargeTest
     @Test
-    public void vibrate_withVibratorCallbackDelayLongerThanTimeout_vibrationFinishedAfterTimeout()
-            throws Exception {
+    public void vibrate_withVibratorCallbackDelayLongerThanTimeout_vibrationFinishedAfterTimeout() {
         long expectedDuration = 10;
         long callbackTimeout = VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT;
         long callbackDelay = callbackTimeout * 2;
@@ -1602,21 +1611,17 @@
                         VibrationEffect.createOneShot(
                                 expectedDuration, VibrationEffect.DEFAULT_AMPLITUDE)));
 
-        startThreadAndDispatcher(vibration);
         long startTime = SystemClock.elapsedRealtime();
-
-        vibration.waitForEnd();
-        long vibrationEndTime = SystemClock.elapsedRealtime();
+        startThreadAndDispatcher(vibration);
 
         waitForCompletion(callbackDelay + TEST_TIMEOUT_MILLIS);
-        long completionTime = SystemClock.elapsedRealtime();
+        long vibrationEndTime = SystemClock.elapsedRealtime();
 
         verify(mControllerCallbacks, never())
                 .onComplete(eq(VIBRATOR_ID), eq(vibration.id), anyLong());
         // Vibration ends and thread completes after timeout, before the HAL callback
         assertThat(vibrationEndTime - startTime).isAtLeast(expectedDuration + callbackTimeout);
         assertThat(vibrationEndTime - startTime).isLessThan(expectedDuration + callbackDelay);
-        assertThat(completionTime - startTime).isLessThan(expectedDuration + callbackDelay);
     }
 
     @LargeTest
@@ -1637,8 +1642,8 @@
         Arrays.fill(amplitudes, VibrationEffect.DEFAULT_AMPLITUDE);
         VibrationEffect effect = VibrationEffect.createWaveform(timings, amplitudes, -1);
 
-        startThreadAndDispatcher(effect);
         long startTime = SystemClock.elapsedRealtime();
+        startThreadAndDispatcher(effect);
 
         waitForCompletion(totalDuration + TEST_TIMEOUT_MILLIS);
         long delay = Math.abs(SystemClock.elapsedRealtime() - startTime - totalDuration);
@@ -1806,6 +1811,7 @@
         assertThat(mControllers.get(VIBRATOR_ID).isVibrating()).isFalse();
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_waveformWithRampDown_addsRampDownAfterVibrationCompleted() {
         when(mVibrationConfigMock.getRampDownDurationMs()).thenReturn(15);
@@ -1833,6 +1839,7 @@
         }
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_waveformWithRampDown_triggersCallbackWhenOriginalVibrationEnds()
             throws Exception {
@@ -1863,6 +1870,7 @@
         verify(mManagerHooks).onVibrationThreadReleased(vibration.id);
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_waveformCancelledWithRampDown_addsRampDownAfterVibrationCancelled()
             throws Exception {
@@ -2057,6 +2065,7 @@
                 .containsExactly(expectedPrebaked(EFFECT_CLICK)).inOrder();
     }
 
+    @EnableFlags(Flags.FLAG_FIX_VIBRATION_THREAD_CALLBACK_HANDLING)
     @Test
     public void vibrate_multipleVibratorsSequentialInSession_runsInOrderWithoutDelaysAndNoOffs() {
         mockVibrators(1, 2, 3);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java
index 948371f..ad706e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java
@@ -63,11 +63,23 @@
         super(0.8f /* highResScale */, 0.5f /* lowResScale */);
     }
 
+    private class TestActivitySnapshotController extends ActivitySnapshotController {
+        TestActivitySnapshotController(WindowManagerService service,
+                SnapshotPersistQueue persistQueue) {
+            super(service, persistQueue);
+        }
+        @Override
+        BaseAppSnapshotPersister.PersistInfoProvider createPersistInfoProvider(
+                WindowManagerService service) {
+            return mPersister.mPersistInfoProvider;
+        }
+    }
     @Override
     @Before
     public void setUp() {
         super.setUp();
-        mActivitySnapshotController = new ActivitySnapshotController(mWm, mSnapshotPersistQueue);
+        mActivitySnapshotController = new TestActivitySnapshotController(
+                mWm, mSnapshotPersistQueue);
         spyOn(mActivitySnapshotController);
         doReturn(false).when(mActivitySnapshotController).shouldDisableSnapshots();
         mActivitySnapshotController.resetTmpFields();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
index d016e735..8fe0855 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -251,10 +251,6 @@
         doReturn(mTaskStack.top()).when(mActivityStack.top()).getOrganizedTask();
     }
 
-    void setIsInLetterboxAnimation(boolean inAnimation) {
-        doReturn(inAnimation).when(mActivityStack.top()).isInLetterboxAnimation();
-    }
-
     void setTopTaskInMultiWindowMode(boolean inMultiWindowMode) {
         doReturn(inMultiWindowMode).when(mTaskStack.top()).inMultiWindowMode();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
index d38f3b0..7bcf4ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
@@ -66,7 +66,6 @@
         runTestScenario((robot) -> {
             robot.configureWindowStateWithTaskBar(/* hasTaskBarInsetsRoundedCorners */ true);
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -87,7 +86,6 @@
         runTestScenario((robot) -> {
             robot.configureWindowStateWithTaskBar(/* hasTaskBarInsetsRoundedCorners */ false);
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -109,7 +107,6 @@
         runTestScenario((robot) -> {
             robot.configureWindowStateWithTaskBar(/* hasTaskBarInsetsRoundedCorners */ true);
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -131,7 +128,6 @@
         runTestScenario((robot) -> {
             robot.configureWindowStateWithTaskBar(/* hasTaskBarInsetsRoundedCorners */ true);
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -157,7 +153,6 @@
             robot.conf().setLetterboxActivityCornersRadius(-1);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -184,25 +179,17 @@
             robot.conf().setLetterboxActivityCornersRadius(15);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
             robot.resources().configureGetDimensionPixelSize(R.dimen.taskbar_frame_height, 20);
             robot.setInvCompatState(/* scale */ 0.5f);
 
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ true);
-            robot.checkWindowStateRoundedCornersRadius(/* expected */ 7);
-
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.checkWindowStateRoundedCornersRadius(/* expected */ 7);
 
             robot.activity().setTopActivityVisibleRequested(/* isVisibleRequested */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ false);
             robot.checkWindowStateRoundedCornersRadius(/* expected */ 0);
-
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ true);
-            robot.checkWindowStateRoundedCornersRadius(/* expected */ 7);
         });
     }
 
@@ -212,7 +199,6 @@
             robot.conf().setLetterboxActivityCornersRadius(15);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -236,7 +222,6 @@
             robot.conf().setLetterboxActivityCornersRadius(15);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -260,7 +245,6 @@
             robot.conf().setLetterboxActivityCornersRadius(15);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -362,10 +346,6 @@
             mWindowState.mInvGlobalScale = scale;
         }
 
-        void setTopActivityInLetterboxAnimation(boolean inLetterboxAnimation) {
-            doReturn(inLetterboxAnimation).when(activity().top()).isInLetterboxAnimation();
-        }
-
         void setTopActivityTransparentPolicyRunning(boolean running) {
             doReturn(running).when(getTransparentPolicy()).isRunning();
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxUtilsTest.java
index a4a63d2..ac707d2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxUtilsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxUtilsTest.java
@@ -63,25 +63,10 @@
     }
 
     @Test
-    public void positionIsFromTaskWhenLetterboxAnimationIsRunning() {
+    public void positionIsFromActivity() {
         runTestScenario((robot) -> {
             robot.activity().createActivityWithComponent();
             robot.setTopActivityLetterboxPolicyRunning(true);
-            robot.activity().setIsInLetterboxAnimation(true);
-            robot.activity().configureTaskBounds(
-                    new Rect(/* left */ 100, /* top */ 200, /* right */ 300, /* bottom */ 400));
-            robot.getLetterboxPosition();
-
-            robot.assertPosition(/* x */ 100, /* y */ 200);
-        });
-    }
-
-    @Test
-    public void positionIsFromActivityWhenLetterboxAnimationIsNotRunning() {
-        runTestScenario((robot) -> {
-            robot.activity().createActivityWithComponent();
-            robot.setTopActivityLetterboxPolicyRunning(true);
-            robot.activity().setIsInLetterboxAnimation(false);
             robot.activity().configureTopActivityBounds(
                     new Rect(/* left */ 200, /* top */ 400, /* right */ 300, /* bottom */ 400));
             robot.getLetterboxPosition();
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index e081971..bdee3c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -225,10 +225,10 @@
         CrossActivityTestCase testCase = createTopTaskWithTwoActivities();
         IOnBackInvokedCallback callback = withSystemCallback(testCase.task);
         testCase.windowFront.mAttrs.windowAnimations = 0x10;
-        spyOn(mDisplayContent.mAppTransition.mTransitionAnimation);
-        doReturn(0xffff00AB).when(mDisplayContent.mAppTransition.mTransitionAnimation)
+        spyOn(mDisplayContent.mTransitionAnimation);
+        doReturn(0xffff00AB).when(mDisplayContent.mTransitionAnimation)
                 .getAnimationResId(any(), anyInt(), anyInt());
-        doReturn(0xffff00CD).when(mDisplayContent.mAppTransition.mTransitionAnimation)
+        doReturn(0xffff00CD).when(mDisplayContent.mTransitionAnimation)
                 .getDefaultAnimationResId(anyInt(), anyInt());
 
         BackNavigationInfo backNavigationInfo = startBackNavigation();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
index 1e91bed..43755ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
@@ -181,6 +181,7 @@
         assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isTrue();
     }
 
+    @DisableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
     @Test
     public void isDeviceEligibleForDesktopMode_configDEModeOffAndIntDispHostsDesktop_returnsFalse() {
         doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported));
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 4854f0d..862158e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -362,7 +362,19 @@
 
     @Test
     public void testSwitchDecorInsets() {
-        createNavBarWithProvidedInsets(mDisplayContent);
+        final WindowState win = createApplicationWindow();
+        final WindowState bar = createNavBarWithProvidedInsets(mDisplayContent);
+        bar.getFrame().set(0, mDisplayContent.mDisplayFrames.mHeight - NAV_BAR_HEIGHT,
+                mDisplayContent.mDisplayFrames.mWidth, mDisplayContent.mDisplayFrames.mHeight);
+        final int insetsId = bar.mAttrs.providedInsets[0].getId();
+        final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController()
+                .getOrCreateSourceProvider(insetsId, bar.mAttrs.providedInsets[0].getType());
+        provider.setServerVisible(true);
+        provider.updateSourceFrame(bar.getFrame());
+
+        final InsetsState prevInsetsState = new InsetsState();
+        prevInsetsState.addSource(new InsetsSource(provider.getSource()));
+
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
         final DisplayInfo info = mDisplayContent.getDisplayInfo();
         final int w = info.logicalWidth;
@@ -385,6 +397,18 @@
         // The current insets are restored from cache directly.
         assertEquals(prevConfigFrame, displayPolicy.getDecorInsetsInfo(info.rotation,
                 info.logicalWidth, info.logicalHeight).mConfigFrame);
+        // Assume that the InsetsSource in current InsetsState is not updated yet. And it will be
+        // replaced by the one in cache.
+        InsetsState currentInsetsState = new InsetsState();
+        final InsetsSource prevSource = new InsetsSource(provider.getSource());
+        prevSource.getFrame().scale(0.5f);
+        currentInsetsState.addSource(prevSource);
+        currentInsetsState = mDisplayContent.getInsetsPolicy().adjustInsetsForWindow(
+                win, currentInsetsState);
+        if (com.android.window.flags.Flags.useCachedInsetsForDisplaySwitch()) {
+            assertEquals(prevInsetsState.peekSource(insetsId),
+                    currentInsetsState.peekSource(insetsId));
+        }
 
         // If screen is not fully turned on, then the cache should be preserved.
         displayPolicy.screenTurnedOff(false /* acquireSleepToken */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java
index 51e0240..8ee5999 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java
@@ -38,7 +38,6 @@
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.view.InputWindowHandle;
-import android.view.SurfaceControl;
 import android.view.WindowManager;
 
 import com.android.server.testutils.StubTransaction;
@@ -76,8 +75,7 @@
         doReturn(0.5f).when(letterboxOverrides).getLetterboxWallpaperDarkScrimAlpha();
         mWindowState = createWindowState();
         mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
-                mock(AppCompatReachabilityPolicy.class), letterboxOverrides,
-                () -> mock(SurfaceControl.class));
+                mock(AppCompatReachabilityPolicy.class), letterboxOverrides);
         mTransaction = spy(StubTransaction.class);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index a51a44f..e5533b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -68,7 +68,6 @@
     private SurfaceControlMocker mSurfaces;
     private SurfaceControl.Transaction mTransaction;
 
-    private SurfaceControl mParentSurface = mock(SurfaceControl.class);
     private AppCompatLetterboxOverrides mLetterboxOverrides;
     private WindowState mWindowState;
 
@@ -84,7 +83,7 @@
         doReturn(0.5f).when(mLetterboxOverrides).getLetterboxWallpaperDarkScrimAlpha();
         mWindowState = mock(WindowState.class);
         mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
-                mock(AppCompatReachabilityPolicy.class), mLetterboxOverrides, () -> mParentSurface);
+                mock(AppCompatReachabilityPolicy.class), mLetterboxOverrides);
         mTransaction = spy(StubTransaction.class);
     }
 
@@ -259,22 +258,6 @@
     }
 
     @Test
-    public void testNeedsApplySurfaceChanges_setParentSurface() {
-        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
-        applySurfaceChanges();
-
-        verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
-        assertFalse(mLetterbox.needsApplySurfaceChanges());
-
-        mParentSurface = mock(SurfaceControl.class);
-
-        assertTrue(mLetterbox.needsApplySurfaceChanges());
-
-        applySurfaceChanges();
-        verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
-    }
-
-    @Test
     public void testApplySurfaceChanges_cornersNotRounded_surfaceFullWindowSurfaceNotCreated() {
         mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
         applySurfaceChanges();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index e4a1bf6..34e9bed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -31,6 +31,7 @@
 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.spyOn;
+import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT;
 import static com.android.server.wm.ActivityRecord.State.FINISHING;
 import static com.android.server.wm.ActivityRecord.State.PAUSED;
 import static com.android.server.wm.ActivityRecord.State.PAUSING;
@@ -82,6 +83,7 @@
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
+import android.view.DisplayInfo;
 
 import androidx.test.filters.MediumTest;
 
@@ -1379,6 +1381,23 @@
         verify(controller, never()).notifyTaskProfileLocked(any(), anyInt());
     }
 
+    @EnableFlags(FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT)
+    @Test
+    public void testOnDisplayBelongToTopologyChanged() {
+        final DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.copyFrom(mDisplayInfo);
+        displayInfo.displayId = DEFAULT_DISPLAY + 1;
+        final DisplayContent dc = createNewDisplay(displayInfo);
+        final int displayId = dc.getDisplayId();
+
+        doReturn(dc).when(mRootWindowContainer).getDisplayContentOrCreate(displayId);
+        doReturn(true).when(mWm.mDisplayWindowSettings).shouldShowSystemDecorsLocked(dc);
+
+        mRootWindowContainer.onDisplayAdded(displayId);
+        verify(mWm.mDisplayManagerInternal, times(1)).onDisplayBelongToTopologyChanged(anyInt(),
+                anyBoolean());
+    }
+
     /**
      * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
      * info for test cases.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 3776b036..b558fad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -78,6 +78,7 @@
 
 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.protolog.PerfettoProtoLogImpl;
 import com.android.internal.protolog.ProtoLog;
 import com.android.internal.protolog.WmProtoLogGroups;
 import com.android.server.AnimationThread;
@@ -187,7 +188,10 @@
     }
 
     private void setUp() {
-        ProtoLog.init(WmProtoLogGroups.values());
+        if (ProtoLog.getSingleInstance() == null) {
+            ProtoLog.init(WmProtoLogGroups.values());
+            PerfettoProtoLogImpl.waitForInitialization();
+        }
 
         if (mOnBeforeServicesCreated != null) {
             mOnBeforeServicesCreated.run();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotLowResDisabledTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotLowResDisabledTest.java
index 51ea498..f22ecb5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotLowResDisabledTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotLowResDisabledTest.java
@@ -68,11 +68,8 @@
     public void testPersistAndLoadSnapshot() {
         mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
         mSnapshotPersistQueue.waitForQueueEmpty();
-        final File[] files = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1.jpg")};
-        final File[] nonExistsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
+        final File[] files = convertFilePath("1.proto", "1.jpg");
+        final File[] nonExistsFiles = convertFilePath("1_reduced.proto");
         assertTrueForFiles(files, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
         final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* isLowResolution */);
@@ -92,14 +89,9 @@
         taskIds.add(1);
         mPersister.removeObsoleteFiles(taskIds, new int[]{mTestUserId});
         mSnapshotPersistQueue.waitForQueueEmpty();
-        final File[] existsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1.jpg")};
-        final File[] nonExistsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/2.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/2.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")};
+        final File[] existsFiles = convertFilePath("1.proto", "1.jpg");
+        final File[] nonExistsFiles = convertFilePath("1_reduced.proto", "2.proto", "2.jpg",
+                "2_reduced.jpg");
         assertTrueForFiles(existsFiles, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
     }
@@ -112,14 +104,8 @@
         mPersister.removeObsoleteFiles(taskIds, new int[]{mTestUserId});
         mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
         mSnapshotPersistQueue.waitForQueueEmpty();
-        final File[] existsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/2.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/2.jpg")};
-        final File[] nonExistsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")};
+        final File[] existsFiles = convertFilePath("1.proto", "1.jpg", "2.proto", "2.jpg");
+        final File[] nonExistsFiles = convertFilePath("1_reduced.jpg", "2_reduced.jpg");
         assertTrueForFiles(existsFiles, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 4b54e44..af06c145 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -75,9 +75,7 @@
     public void testPersistAndLoadSnapshot() {
         mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
         mSnapshotPersistQueue.waitForQueueEmpty();
-        final File[] files = new File[]{new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
+        final File[] files = convertFilePath("1.proto", "1.jpg", "1_reduced.jpg");
         assertTrueForFiles(files, File::exists, " must exist");
         final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* isLowResolution */);
         assertNotNull(snapshot);
@@ -140,13 +138,8 @@
         mSnapshotPersistQueue.waitForQueueEmpty();
 
         // Make sure 1,2 were purged but removeObsoleteFiles wasn't.
-        final File[] existsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/3.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/4.proto")};
-        final File[] nonExistsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/100.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1.proto")};
+        final File[] existsFiles = convertFilePath("3.proto", "4.proto");
+        final File[] nonExistsFiles = convertFilePath("100.proto", "1.proto", "2.proto");
         assertTrueForFiles(existsFiles, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
     }
@@ -427,14 +420,8 @@
         taskIds.add(1);
         mPersister.removeObsoleteFiles(taskIds, new int[]{mTestUserId});
         mSnapshotPersistQueue.waitForQueueEmpty();
-        final File[] existsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
-        final File[] nonExistsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/2.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/2.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")};
+        final File[] existsFiles = convertFilePath("1.proto", "1.jpg", "1_reduced.jpg");
+        final File[] nonExistsFiles = convertFilePath("2.proto", "2.jpg", "2_reduced.jpg");
         assertTrueForFiles(existsFiles, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
     }
@@ -447,13 +434,8 @@
         mPersister.removeObsoleteFiles(taskIds, new int[]{mTestUserId});
         mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
         mSnapshotPersistQueue.waitForQueueEmpty();
-        final File[] existsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/2.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/2.jpg"),
-                new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")};
+        final File[] existsFiles = convertFilePath("1.proto", "1.jpg", "1_reduced.jpg", "2.proto",
+                "2.jpg", "2_reduced.jpg");
         assertTrueForFiles(existsFiles, File::exists, " must exist");
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 1e16c97..b2c195e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.ContextWrapper;
 import android.content.res.Resources;
@@ -46,6 +47,7 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider;
+import com.android.window.flags.Flags;
 
 import org.junit.After;
 import org.junit.AfterClass;
@@ -129,12 +131,33 @@
             return;
         }
         for (File file : files) {
-            if (!file.isDirectory()) {
-                file.delete();
+            if (file.isDirectory()) {
+                final File[] subFiles = file.listFiles();
+                if (subFiles == null) {
+                    continue;
+                }
+                for (File subFile : subFiles) {
+                    subFile.delete();
+                }
             }
+            file.delete();
         }
     }
 
+    File[] convertFilePath(@NonNull String... fileNames) {
+        final File[] files = new File[fileNames.length];
+        final String path;
+        if (Flags.scrambleSnapshotFileName()) {
+            path = mPersister.mPersistInfoProvider.getDirectory(mTestUserId).getPath();
+        } else {
+            path = FILES_DIR.getPath() + "/snapshots/";
+        }
+        for (int i = 0; i < fileNames.length; i++) {
+            files[i] = new File(path + fileNames[i]);
+        }
+        return files;
+    }
+
     TaskSnapshot createSnapshot() {
         return new TaskSnapshotBuilder().setTopActivityComponent(getUniqueComponentName()).build();
     }
diff --git a/services/usb/java/com/android/server/usb/UsbManagerInternal.java b/services/usb/java/com/android/server/usb/UsbManagerInternal.java
deleted file mode 100644
index 31c5986..0000000
--- a/services/usb/java/com/android/server/usb/UsbManagerInternal.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.usb;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.hardware.usb.IUsbOperationInternal;
-import android.hardware.usb.UsbPort;
-import android.util.ArraySet;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * UsbManagerInternal provides internal APIs for the UsbService to
- * reduce IPC overhead costs and support internal USB data signal stakers.
- *
- * @hide Only for use within the system server.
- */
-public abstract class UsbManagerInternal {
-
-  public static final int OS_USB_DISABLE_REASON_AAPM = 0;
-  public static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1;
-
-  @Retention(RetentionPolicy.SOURCE)
-  @IntDef(value = {OS_USB_DISABLE_REASON_AAPM,
-    OS_USB_DISABLE_REASON_LOCKDOWN_MODE})
-  public @interface OsUsbDisableReason {
-  }
-
-  public abstract boolean enableUsbData(String portId, boolean enable,
-      int operationId, IUsbOperationInternal callback, @OsUsbDisableReason int disableReason);
-
-  public abstract UsbPort[] getPorts();
-
-}
\ No newline at end of file
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 4395b76..7808b2e 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -27,7 +27,10 @@
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
 
+import android.hardware.usb.IUsbManagerInternal;
+
 import android.annotation.NonNull;
+import android.annotation.IntDef;
 import android.annotation.UserIdInt;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
@@ -80,12 +83,16 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  * UsbService manages all USB related state, including both host and device support.
  * Host related events and calls are delegated to UsbHostManager, and device related
@@ -93,6 +100,15 @@
  */
 public class UsbService extends IUsbManager.Stub {
 
+    public static final int OS_USB_DISABLE_REASON_AAPM = 0;
+    public static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {OS_USB_DISABLE_REASON_AAPM,
+        OS_USB_DISABLE_REASON_LOCKDOWN_MODE})
+    public @interface OsUsbDisableReason {
+    }
+
     public static class Lifecycle extends SystemService {
         private UsbService mUsbService;
         private final CompletableFuture<Void> mOnStartFinished = new CompletableFuture<>();
@@ -227,7 +243,7 @@
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, null);
         if(android.hardware.usb.flags.Flags.enableUsbDataSignalStakingInternal()) {
-            LocalServices.addService(UsbManagerInternal.class, new UsbManagerInternalImpl());
+            LocalServices.addService(IUsbManagerInternal.class, new UsbManagerInternalImpl());
         }
     }
 
@@ -246,7 +262,7 @@
         mPermissionManager = new UsbPermissionManager(context, this);
 
         if(android.hardware.usb.flags.Flags.enableUsbDataSignalStakingInternal()) {
-            LocalServices.addService(UsbManagerInternal.class, new UsbManagerInternalImpl());
+            LocalServices.addService(IUsbManagerInternal.class, new UsbManagerInternalImpl());
         }
     }
 
@@ -1536,24 +1552,30 @@
                 enableUsbDataInternal(port.getId(), !lockDownTriggeredByUser,
                     STRONG_AUTH_OPERATION_ID,
                     new IUsbOperationInternal.Default(),
-                    UsbManagerInternal.OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
+                    OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
                     true);
             }
         }
     }
 
-    private class UsbManagerInternalImpl extends UsbManagerInternal {
-        @Override
-        public boolean enableUsbData(String portId, boolean enable,
-                int operationId, IUsbOperationInternal callback,
-            @OsUsbDisableReason int disableReason) {
-            return enableUsbDataInternal(portId, enable, operationId, callback,
-                disableReason, true);
-        }
+    private class UsbManagerInternalImpl extends IUsbManagerInternal.Stub {
+        private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
 
         @Override
-        public UsbPort[] getPorts() {
-            return mPortManager.getPorts();
+        public boolean enableUsbDataSignal(boolean enable,
+                @OsUsbDisableReason int disableReason) {
+                boolean result = true;
+                int operationId = sUsbOperationCount.incrementAndGet() + disableReason;
+                for (UsbPort port : mPortManager.getPorts()) {
+                    boolean success = enableUsbDataInternal(port.getId(), enable, operationId,
+                        new IUsbOperationInternal.Default(), disableReason, true);
+                    if(!success) {
+                        Slog.e(TAG, "enableUsbDataInternal failed to change USB port "
+                            + port.getId() + "state to " + enable);
+                    }
+                    result &= success;
+                }
+                return result;
         }
     }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 89b9850..a727df7 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -43,6 +43,8 @@
 import android.media.permission.Identity;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.os.ParcelFileDescriptor;
@@ -837,6 +839,13 @@
         private final int mBindingFlags;
         private final int mInstanceNumber;
 
+        private static final HandlerThread mHandler;
+
+        static {
+            mHandler = new HandlerThread("Sandbox detection connector");
+            mHandler.start();
+        }
+
         private boolean mRespectServiceConnectionStatusChanged = true;
         private boolean mIsBound = false;
         private boolean mIsLoggedFirstConnect = false;
@@ -883,6 +892,11 @@
             }
         }
 
+        @Override // from ServiceConnector.Impl
+        protected Handler getJobHandler() {
+            return mHandler.getThreadHandler();
+        }
+
         @Override
         protected long getAutoDisconnectTimeoutMs() {
             return -1;
@@ -1151,14 +1165,12 @@
     }
 
     private void updateServiceIdentity(ServiceConnection connection) {
-        connection.run(service -> service.ping(new IRemoteCallback.Stub() {
+        connection.run(service -> service.ping(new ISandboxedDetectionService.IPingMe.Stub() {
             @Override
-            public void sendResult(Bundle bundle) throws RemoteException {
+            public void onPing() throws RemoteException {
                 // TODO: Exit if the service has been unbound already (though there's a very low
                 // chance this happens).
-                if (DEBUG) {
-                    Slog.d(TAG, "updating hotword UID " + Binder.getCallingUid());
-                }
+                Slog.d(TAG, "updating hotword UID " + Binder.getCallingUid());
                 // TODO: Have the provider point to the current state stored in
                 // VoiceInteractionManagerServiceImpl.
                 final int uid = Binder.getCallingUid();
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 29d3942..ebe0078 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1237,6 +1237,10 @@
             builder.append(isLong ? " PROPERTY_IS_DOWNGRADED_CONFERENCE" : " dngrd_conf");
         }
 
+        if ((properties & PROPERTY_CROSS_SIM) == PROPERTY_CROSS_SIM) {
+            builder.append(isLong ? " PROPERTY_CROSS_SIM" : " xsim");
+        }
+
         builder.append("]");
         return builder.toString();
     }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 58833e8..50c5a6b6 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -10962,7 +10962,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.putInt(KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT, -1);
         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/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d2741ac..e04d285 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1187,6 +1187,61 @@
     public static final String IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM =
             SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM;
 
+    /**
+     * TelephonyProvider column name for satellite entitlement barred plmns. The value of this
+     * column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_BARRED_PLMNS =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS;
+
+    /**
+     * TelephonyProvider column name for satellite entitlement data plan for plmns. The value
+     * of this column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS;
+
+    /**
+     * TelephonyProvider column name for satellite entitlement service type map. The value of
+     * this column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP;
+
+    /**
+     * TelephonyProvider column name for satellite entitlement data service policy. The value
+     * of this column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY;
+
+    /**
+     * TelephonyProvider column name for satellite entitlement voice service policy. The value
+     * of this column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"USAGE_SETTING_"},
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml
index 2f9c3aa..15e2a79 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_blue_bright">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml
index 7c7b2ca..4bc7099 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml
@@ -16,6 +16,7 @@
   -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fitsSystemWindows="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <Button
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
index f0dfdfc..e98ffd0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
@@ -19,5 +19,6 @@
     android:id="@+id/root_activity_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical">
 </LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
index 939ba81..16c906d 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
 
     <LinearLayout
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml
index 6d4de99..eedb910 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml
@@ -19,6 +19,7 @@
     android:id="@+id/secondary_activity_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical">
 
   <Button
@@ -49,4 +50,4 @@
       android:layout_height="48dp"
       android:text="Enter pip" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml
index fe7bced..2ab5fe7 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
     <Button
         android:id="@+id/launch_second_activity"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
index 6d5a9dd..aeb8423 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_orange_light">
 
@@ -29,4 +30,4 @@
       android:text="NonResizeableActivity"
       android:textAppearance="?android:attr/textAppearanceLarge"/>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
index 365a0ea..d66b3d7 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_blue_bright">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml
index 79e88e4..16c3bc0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_green_light">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml
index ed9feaf..7643cf5 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_blue_light">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
index c34d200..79e7bb5 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:gravity="center"
     android:orientation="vertical"
     android:background="@android:color/holo_orange_light">
@@ -39,4 +40,4 @@
         android:gravity="center_vertical|center_horizontal"
         android:text="Start Media Projection with extra intent"
         android:textAppearance="?android:attr/textAppearanceLarge"/>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml
index 0730ded..32df5f0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml
@@ -15,6 +15,7 @@
   ~ limitations under the License.
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fitsSystemWindows="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml
index ff4ead9..a0c87fd 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml
@@ -17,6 +17,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/black">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml
index 7807200..da58b3f 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml
@@ -18,10 +18,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
     <Button
         android:id="@+id/post_notification"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal|center_vertical"
         android:text="Post Notification" />
 </LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
index 8f75d17..ec3135c 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
     <Button
         android:id="@+id/launch_new_task"
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
index 4418b5a..30bf616 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
@@ -30,7 +30,6 @@
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.WindowManager;
 
 public class ImeActivity extends Activity {
 
@@ -64,10 +63,6 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_ime);
 
         final var filter = new IntentFilter();
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java
index 95f933f..887a15c 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java
@@ -30,8 +30,6 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
         p.softInputMode = SOFT_INPUT_STATE_ALWAYS_HIDDEN;
         getWindow().setAttributes(p);
         LinearLayout layout = new LinearLayout(this);
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
index e5710c8..97d7a64 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
@@ -19,17 +19,12 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
-import android.view.WindowManager;
 import android.widget.Button;
 
 public class LaunchNewActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_launch_new);
 
         Button button = findViewById(R.id.launch_second_activity);
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
index 1809781..402a393 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
@@ -21,17 +21,12 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
-import android.view.WindowManager;
 import android.widget.Button;
 
 public class LaunchNewTaskActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.task_button);
 
         Button button = findViewById(R.id.launch_new_task);
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java
index d6427ab..6125438 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java
@@ -45,14 +45,10 @@
             requestPermissions(new String[] { POST_NOTIFICATIONS }, 0);
         }
 
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.notification_button);
 
-        Button button = findViewById(R.id.post_notification);
-        button.setOnClickListener(v -> postNotification());
+        ((Button) findViewById(R.id.post_notification))
+                .setOnClickListener(v -> postNotification());
 
         createNotificationChannel();
     }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
index ee25ab2..e030dcf 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
@@ -47,8 +47,6 @@
 import android.util.Log;
 import android.util.Rational;
 import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
 import android.widget.CheckBox;
 import android.widget.RadioButton;
 
@@ -145,12 +143,6 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        final Window window = getWindow();
-        final WindowManager.LayoutParams layoutParams = window.getAttributes();
-        layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        window.setAttributes(layoutParams);
-
         setContentView(R.layout.activity_pip);
 
         findViewById(R.id.media_session_start)
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java
index b1876b5..552d843 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java
@@ -18,16 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.WindowManager;
 
 public class PortraitOnlyActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_simple);
     }
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
index ce7a005..e98c34d 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
@@ -61,8 +61,6 @@
     private void enableSeamlessRotation() {
         WindowManager.LayoutParams p = getWindow().getAttributes();
         p.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                 WindowManager.LayoutParams.FLAG_FULLSCREEN);
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java
index 6f94b74..a533c90 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java
@@ -18,16 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.WindowManager;
 
 public class ShowWhenLockedActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_simple);
     }
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java
index 699abf8..c56eefe 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java
@@ -18,16 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.WindowManager;
 
 public class SimpleActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_simple);
     }
 }
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java b/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
index 51d57f0..f5d4b0c 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
@@ -24,15 +24,20 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.hardware.usb.IUsbManagerInternal;
 import android.hardware.usb.IUsbOperationInternal;
 import android.hardware.usb.flags.Flags;
 import android.hardware.usb.UsbPort;
@@ -70,7 +75,9 @@
     @Mock
     private IUsbOperationInternal mCallback;
 
-    private static final String TEST_PORT_ID = "123";
+    private static final String TEST_PORT_ID = "1";
+
+    private static final String TEST_PORT_ID_2 = "2";
 
     private static final int TEST_TRANSACTION_ID = 1;
 
@@ -84,7 +91,7 @@
 
     private UsbService mUsbService;
 
-    private UsbManagerInternal mUsbManagerInternal;
+    private IUsbManagerInternal mIUsbManagerInternal;
 
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -101,9 +108,9 @@
 
         mUsbService = new UsbService(mContext, mUsbPortManager, mUsbAlsaManager,
                 mUserManager, mUsbSettingsManager);
-        mUsbManagerInternal = LocalServices.getService(UsbManagerInternal.class);
-        assertWithMessage("LocalServices.getService(UsbManagerInternal.class)")
-            .that(mUsbManagerInternal).isNotNull();
+        mIUsbManagerInternal = LocalServices.getService(IUsbManagerInternal.class);
+        assertWithMessage("LocalServices.getService(IUsbManagerInternal.class)")
+            .that(mIUsbManagerInternal).isNotNull();
     }
 
     private void assertToggleUsbSuccessfully(int requester, boolean enable,
@@ -255,30 +262,42 @@
         assertToggleUsbSuccessfully(TEST_INTERNAL_REQUESTER_REASON_1, true, false);
     }
 
-    /**
-     * Verify USB Manager internal calls mPortManager to get UsbPorts
-     */
     @Test
-    public void usbManagerInternal_getPorts_callsPortManager() {
-        when(mUsbPortManager.getPorts()).thenReturn(new UsbPort[] {});
-
-        UsbPort[] ports = mUsbManagerInternal.getPorts();
-
-        verify(mUsbPortManager).getPorts();
-        assertEquals(ports.length, 0);
+    public void usbManagerInternal_enableUsbDataSignal_successfullyEnabled() {
+        assertTrue(runInternalUsbDataSignalTest(true, true, true));
     }
 
     @Test
-    public void usbManagerInternal_enableUsbData_successfullyEnable() {
-        boolean desiredEnableState = true;
+    public void usbManagerInternal_enableUsbDataSignal_successfullyDisabled() {
+        assertTrue(runInternalUsbDataSignalTest(false, true, true));
+    }
 
-        assertTrue(mUsbManagerInternal.enableUsbData(TEST_PORT_ID, desiredEnableState,
-        TEST_TRANSACTION_ID, mCallback, TEST_INTERNAL_REQUESTER_REASON_1));
+    @Test
+    public void usbManagerInternal_enableUsbDataSignal_returnsFalseIfOnePortFails() {
+        assertFalse(runInternalUsbDataSignalTest(true, true, false));
+    }
 
-        verify(mUsbPortManager).enableUsbData(TEST_PORT_ID,
-                desiredEnableState, TEST_TRANSACTION_ID, mCallback, null);
-        verifyZeroInteractions(mCallback);
-        clearInvocations(mUsbPortManager);
-        clearInvocations(mCallback);
+    private boolean runInternalUsbDataSignalTest(boolean desiredEnableState, boolean portOneSuccess,
+        boolean portTwoSuccess) {
+        UsbPort port = mock(UsbPort.class);
+        UsbPort port2 = mock(UsbPort.class);
+        when(port.getId()).thenReturn(TEST_PORT_ID);
+        when(port2.getId()).thenReturn(TEST_PORT_ID_2);
+        when(mUsbPortManager.getPorts()).thenReturn(new UsbPort[] { port, port2 });
+        when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID),
+                eq(desiredEnableState), anyInt(), any(IUsbOperationInternal.class), isNull()))
+            .thenReturn(portOneSuccess);
+        when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID_2),
+                eq(desiredEnableState), anyInt(), any(IUsbOperationInternal.class), isNull()))
+            .thenReturn(portTwoSuccess);
+        try {
+            boolean result = mIUsbManagerInternal.enableUsbDataSignal(desiredEnableState,
+                        TEST_INTERNAL_REQUESTER_REASON_1);
+            clearInvocations(mUsbPortManager);
+            return result;
+        } catch(RemoteException e) {
+            fail("RemoteException thrown when calling enableUsbDataSignal");
+            return false;
+        }
     }
 }
diff --git a/tools/codegen/src/com/android/codegen/Debug.kt b/tools/codegen/src/com/android/codegen/Debug.kt
index de31844..6423c4f 100644
--- a/tools/codegen/src/com/android/codegen/Debug.kt
+++ b/tools/codegen/src/com/android/codegen/Debug.kt
@@ -21,7 +21,7 @@
 fun Node.dump(indent: String = ""): String {
     return buildString {
         append(indent)
-        appendln(dumpOneLineNoChildren())
+        appendLine(dumpOneLineNoChildren())
         childNodes.forEach { child ->
             append(child.dump(indent + "  "))
         }
diff --git a/tools/codegen/src/com/android/codegen/FeatureFlag.kt b/tools/codegen/src/com/android/codegen/FeatureFlag.kt
index 24150d6..f305429 100644
--- a/tools/codegen/src/com/android/codegen/FeatureFlag.kt
+++ b/tools/codegen/src/com/android/codegen/FeatureFlag.kt
@@ -22,6 +22,6 @@
     CONST_DEFS(true, "@Int/StringDef's based on declared static constants"),
     FOR_EACH_FIELD(false, "forEachField((name, value) -> ...)");
 
-    val kebabCase = name.toLowerCase().replace("_", "-")
-    val upperCamelCase = name.split("_").map { it.toLowerCase().capitalize() }.joinToString("")
+    val kebabCase = name.lowercase().replace("_", "-")
+    val upperCamelCase = name.split("_").map { it.lowercase().capitalize() }.joinToString("")
 }
diff --git a/tools/codegen/src/com/android/codegen/FileInfo.kt b/tools/codegen/src/com/android/codegen/FileInfo.kt
index cc3a156..ca04f1e 100644
--- a/tools/codegen/src/com/android/codegen/FileInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FileInfo.kt
@@ -126,7 +126,7 @@
                 +"\n}"
             }
             // Print general code as-is
-            is CodeChunk.Code -> chunk.lines.forEach { stringBuilder.appendln(it) }
+            is CodeChunk.Code -> chunk.lines.forEach { stringBuilder.appendLine(it) }
             // Recursively render data classes
             is CodeChunk.DataClass -> chunk.chunks.forEach { print(it) }
         }
@@ -175,11 +175,11 @@
         /** Debug info */
         override fun toString(): String {
             return buildString {
-                appendln("class $name $range")
+                appendLine("class $name $range")
                 nested.forEach {
-                    appendln(it)
+                    appendLine(it)
                 }
-                appendln("end $name")
+                appendLine("end $name")
             }
         }
     }
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index d3a8b03..7109602 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -43,7 +43,7 @@
     }
     var AnnotationName = prefix.split("_")
             .filterNot { it.isBlank() }
-            .map { it.toLowerCase().capitalize() }
+            .map { it.lowercase().capitalize() }
             .joinToString("")
     val annotatedConst = consts.find { it.second.annotations.isNonEmpty }
     if (annotatedConst != null) {
@@ -122,7 +122,7 @@
     if (aidl.exists()) return
     aidl.writeText(buildString {
         sourceLines.dropLastWhile { !it.startsWith("package ") }.forEach {
-            appendln(it)
+            appendLine(it)
         }
         append("\nparcelable ${mainClass.nameAsString};\n")
     })
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index a40bdd7..9631443 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -62,7 +62,7 @@
     if (length >= 2 && this[0] == 'm' && this[1].isUpperCase()) return substring(1).capitalize()
     if (all { it.isLetterOrDigit() }) return decapitalize()
     return split("[^a-zA-Z0-9]".toRegex())
-            .map { it.toLowerCase().capitalize() }
+            .map { it.lowercase().capitalize() }
             .joinToString("")
             .decapitalize()
 }
diff --git a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
index 4995eeb..fe72dae 100644
--- a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
+++ b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
@@ -155,35 +155,35 @@
         ) {
             val indent = "  "
 
-            writer.appendln("{")
+            writer.appendLine("{")
 
             val intDefTypesCount = annotationTypeToIntDefMapping.size
             var currentIntDefTypesCount = 0
             for ((field, intDefMapping) in annotationTypeToIntDefMapping) {
-                writer.appendln("""$indent"$field": {""")
+                writer.appendLine("""$indent"$field": {""")
 
                 // Start IntDef
 
-                writer.appendln("""$indent$indent"flag": ${intDefMapping.flag},""")
+                writer.appendLine("""$indent$indent"flag": ${intDefMapping.flag},""")
 
-                writer.appendln("""$indent$indent"values": {""")
+                writer.appendLine("""$indent$indent"values": {""")
                 intDefMapping.entries.joinTo(writer, separator = ",\n") { (value, identifier) ->
                     """$indent$indent$indent"$value": "$identifier""""
                 }
-                writer.appendln()
-                writer.appendln("$indent$indent}")
+                writer.appendLine()
+                writer.appendLine("$indent$indent}")
 
                 // End IntDef
 
                 writer.append("$indent}")
                 if (++currentIntDefTypesCount < intDefTypesCount) {
-                    writer.appendln(",")
+                    writer.appendLine(",")
                 } else {
-                    writer.appendln("")
+                    writer.appendLine("")
                 }
             }
 
-            writer.appendln("}")
+            writer.appendLine("}")
         }
     }
 }