Merge "Cleaning up deprecate_flags_and_settings_resets" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index e5c059e..8b95679 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -230,6 +230,17 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+java_aconfig_library {
+    name: "telephony_flags_core_java_exported_lib",
+    aconfig_declarations: "telephony_flags",
+    mode: "exported",
+    min_sdk_version: "30",
+    apex_available: [
+        "com.android.wifi",
+    ],
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 cc_aconfig_library {
     name: "telephony_flags_c_lib",
     aconfig_declarations: "telephony_flags",
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f63170a..588ca1d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -387,7 +387,7 @@
     @UnsupportedAppUsage
     private ContextImpl mSystemContext;
     @GuardedBy("this")
-    private ArrayList<WeakReference<ContextImpl>> mDisplaySystemUiContexts;
+    private ArrayList<WeakReference<Context>> mDisplaySystemUiContexts;
 
     @UnsupportedAppUsage
     static volatile IPackageManager sPackageManager;
@@ -3204,7 +3204,7 @@
     }
 
     @NonNull
-    public ContextImpl getSystemUiContext() {
+    public Context getSystemUiContext() {
         return getSystemUiContext(DEFAULT_DISPLAY);
     }
 
@@ -3214,7 +3214,7 @@
      * @see ContextImpl#createSystemUiContext(ContextImpl, int)
      */
     @NonNull
-    public ContextImpl getSystemUiContext(int displayId) {
+    public Context getSystemUiContext(int displayId) {
         synchronized (this) {
             if (mDisplaySystemUiContexts == null) {
                 mDisplaySystemUiContexts = new ArrayList<>();
@@ -3222,7 +3222,7 @@
 
             mDisplaySystemUiContexts.removeIf(contextRef -> contextRef.refersTo(null));
 
-            ContextImpl context = getSystemUiContextNoCreateLocked(displayId);
+            Context context = getSystemUiContextNoCreateLocked(displayId);
             if (context != null) {
                 return context;
             }
@@ -3233,9 +3233,20 @@
         }
     }
 
+    /**
+     * Creates a {@code SystemUiContext} for testing.
+     * <p>
+     * DO NOT use it in production code.
+     */
+    @VisibleForTesting
+    @NonNull
+    public Context createSystemUiContextForTesting(int displayId) {
+        return ContextImpl.createSystemUiContext(getSystemContext(), displayId);
+    }
+
     @Nullable
     @Override
-    public ContextImpl getSystemUiContextNoCreate() {
+    public Context getSystemUiContextNoCreate() {
         synchronized (this) {
             if (mDisplaySystemUiContexts == null) {
                 return null;
@@ -3246,9 +3257,9 @@
 
     @GuardedBy("this")
     @Nullable
-    private ContextImpl getSystemUiContextNoCreateLocked(int displayId) {
+    private Context getSystemUiContextNoCreateLocked(int displayId) {
         for (int i = 0; i < mDisplaySystemUiContexts.size(); i++) {
-            ContextImpl context = mDisplaySystemUiContexts.get(i).get();
+            Context context = mDisplaySystemUiContexts.get(i).get();
             if (context != null && context.getDisplayId() == displayId) {
                 return context;
             }
@@ -3267,7 +3278,8 @@
     public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
         synchronized (this) {
             getSystemContext().installSystemApplicationInfo(info, classLoader);
-            getSystemUiContext().installSystemApplicationInfo(info, classLoader);
+            final ContextImpl sysUiContextImpl = ContextImpl.getImpl(getSystemUiContext());
+            sysUiContextImpl.installSystemApplicationInfo(info, classLoader);
 
             // give ourselves a default profiler
             mProfiler = new Profiler();
diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java
index 72506b9..70876da 100644
--- a/core/java/android/app/ActivityThreadInternal.java
+++ b/core/java/android/app/ActivityThreadInternal.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.content.ComponentCallbacks2;
+import android.content.Context;
 
 import java.util.ArrayList;
 
@@ -28,7 +29,7 @@
 interface ActivityThreadInternal {
     ContextImpl getSystemContext();
 
-    ContextImpl getSystemUiContextNoCreate();
+    Context getSystemUiContextNoCreate();
 
     boolean isInDensityCompatMode();
 
diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java
index 62a50db..f491e3d 100644
--- a/core/java/android/app/ConfigurationController.java
+++ b/core/java/android/app/ConfigurationController.java
@@ -169,7 +169,7 @@
 
         // Get theme outside of synchronization to avoid nested lock.
         final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
-        final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate();
+        final Context systemUiContext = mActivityThread.getSystemUiContextNoCreate();
         final Resources.Theme systemUiTheme =
                 systemUiContext != null ? systemUiContext.getTheme() : null;
         synchronized (mResourcesManager) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d8aa8b3..0519695 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -97,6 +97,7 @@
 import android.view.Display;
 import android.view.DisplayAdjustments;
 import android.view.autofill.AutofillManager.AutofillClient;
+import android.window.SystemUiContext;
 import android.window.WindowContext;
 import android.window.WindowTokenClient;
 import android.window.WindowTokenClientController;
@@ -3477,15 +3478,28 @@
      *                      {@link #createSystemContext(ActivityThread)}.
      * @param displayId The ID of the display where the UI is shown.
      */
-    static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) {
+    static Context createSystemUiContext(ContextImpl systemContext, int displayId) {
+        // Step 1. Create a ContextImpl associated with its own resources.
         final WindowTokenClient token = new WindowTokenClient();
         final ContextImpl context = systemContext.createWindowContextBase(token, displayId);
-        token.attachContext(context);
+
+        // Step 2. Create a SystemUiContext to wrap the ContextImpl, which enables to listen to
+        // its config updates.
+        final Context systemUiContext;
+        if (com.android.window.flags.Flags.trackSystemUiContextBeforeWms()) {
+            systemUiContext = new SystemUiContext(context);
+            context.setOuterContext(systemUiContext);
+        } else {
+            systemUiContext = context;
+        }
+        token.attachContext(systemUiContext);
+
+        // Step 3. Associate the SystemUiContext with the display specified with ID.
         WindowTokenClientController.getInstance().attachToDisplayContent(token, displayId);
         context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
         context.mOwnsToken = true;
 
-        return context;
+        return systemUiContext;
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
index ca1017b..23da747 100644
--- a/core/java/android/window/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -115,6 +115,7 @@
     ENABLE_WINDOWING_SCALED_RESIZING(Flags::enableWindowingScaledResizing, true),
     ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS(
             Flags::enableWindowingTransitionHandlersObservers, false),
+    EXCLUDE_CAPTION_FROM_APP_BOUNDS(Flags::excludeCaptionFromAppBounds, false),
     INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC(
             Flags::includeTopTransparentFullscreenTaskInDesktopHeuristic, true)
     // go/keep-sorted end
diff --git a/core/java/android/window/SystemUiContext.java b/core/java/android/window/SystemUiContext.java
new file mode 100644
index 0000000..1e9a720
--- /dev/null
+++ b/core/java/android/window/SystemUiContext.java
@@ -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 android.window;
+
+import android.annotation.NonNull;
+import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacksController;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.Configuration;
+
+import com.android.window.flags.Flags;
+
+/**
+ * System Context to be used for UI. This Context has resources that can be themed.
+ *
+ * @see android.app.ActivityThread#getSystemUiContext(int)
+ *
+ * @hide
+ */
+public class SystemUiContext extends ContextWrapper implements ConfigurationDispatcher {
+
+    private final ComponentCallbacksController mCallbacksController =
+            new ComponentCallbacksController();
+
+    public SystemUiContext(Context base) {
+        super(base);
+        if (!Flags.trackSystemUiContextBeforeWms()) {
+            throw new UnsupportedOperationException("SystemUiContext can only be used after"
+                    + " flag is enabled.");
+        }
+    }
+
+    @Override
+    public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) {
+        mCallbacksController.registerCallbacks(callback);
+    }
+
+    @Override
+    public void unregisterComponentCallbacks(@NonNull ComponentCallbacks callback) {
+        mCallbacksController.unregisterCallbacks(callback);
+    }
+
+    /** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */
+    @Override
+    public void dispatchConfigurationChanged(@NonNull Configuration newConfig) {
+        mCallbacksController.dispatchConfigurationChanged(newConfig);
+    }
+
+    @Override
+    public boolean shouldReportPrivateChanges() {
+        // We should report all config changes to update fields obtained from resources.
+        return true;
+    }
+}
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialog.java b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
index 61e63d1..621ec50 100644
--- a/core/java/com/android/internal/app/MediaRouteControllerDialog.java
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
@@ -16,13 +16,10 @@
 
 package com.android.internal.app;
 
-import com.android.internal.R;
-
 import android.app.AlertDialog;
 import android.app.MediaRouteActionProvider;
 import android.app.MediaRouteButton;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.AnimationDrawable;
@@ -39,6 +36,8 @@
 import android.widget.LinearLayout;
 import android.widget.SeekBar;
 
+import com.android.internal.R;
+
 /**
  * This class implements the route controller dialog for {@link MediaRouter}.
  * <p>
@@ -60,7 +59,6 @@
     private final MediaRouterCallback mCallback;
     private final MediaRouter.RouteInfo mRoute;
 
-    private boolean mCreated;
     private Drawable mMediaRouteButtonDrawable;
     private int[] mMediaRouteConnectingState = { R.attr.state_checked, R.attr.state_enabled };
     private int[] mMediaRouteOnState = { R.attr.state_activated, R.attr.state_enabled };
@@ -102,31 +100,6 @@
     }
 
     /**
-     * Gets the media control view that was created by {@link #onCreateMediaControlView(Bundle)}.
-     *
-     * @return The media control view, or null if none.
-     */
-    public View getMediaControlView() {
-        return mControlView;
-    }
-
-    /**
-     * Sets whether to enable the volume slider and volume control using the volume keys
-     * when the route supports it.
-     * <p>
-     * The default value is true.
-     * </p>
-     */
-    public void setVolumeControlEnabled(boolean enable) {
-        if (mVolumeControlEnabled != enable) {
-            mVolumeControlEnabled = enable;
-            if (mCreated) {
-                updateVolume();
-            }
-        }
-    }
-
-    /**
      * Returns whether to enable the volume slider and volume control using the volume keys
      * when the route supports it.
      */
@@ -139,18 +112,15 @@
         setTitle(mRoute.getName());
         Resources res = getContext().getResources();
         setButton(BUTTON_NEGATIVE, res.getString(R.string.media_route_controller_disconnect),
-                new OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialogInterface, int id) {
-                        if (mRoute.isSelected()) {
-                            if (mRoute.isBluetooth()) {
-                                mRouter.getDefaultRoute().select();
-                            } else {
-                                mRouter.getFallbackRoute().select();
-                            }
+                (dialogInterface, id) -> {
+                    if (mRoute.isSelected()) {
+                        if (mRoute.isBluetooth()) {
+                            mRouter.getDefaultRoute().select();
+                        } else {
+                            mRouter.getFallbackRoute().select();
                         }
-                        dismiss();
                     }
+                    dismiss();
                 });
         View customView = getLayoutInflater().inflate(R.layout.media_route_controller_dialog, null);
         setView(customView, 0, 0, 0, 0);
@@ -160,8 +130,8 @@
         if (customPanelView != null) {
             customPanelView.setMinimumHeight(0);
         }
-        mVolumeLayout = (LinearLayout) customView.findViewById(R.id.media_route_volume_layout);
-        mVolumeSlider = (SeekBar) customView.findViewById(R.id.media_route_volume_slider);
+        mVolumeLayout = customView.findViewById(R.id.media_route_volume_layout);
+        mVolumeSlider = customView.findViewById(R.id.media_route_volume_slider);
         mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
             private final Runnable mStopTrackingTouch = new Runnable() {
                 @Override
@@ -199,11 +169,10 @@
         });
 
         mMediaRouteButtonDrawable = obtainMediaRouteButtonDrawable();
-        mCreated = true;
         if (update()) {
             mControlView = onCreateMediaControlView(savedInstanceState);
             FrameLayout controlFrame =
-                    (FrameLayout) customView.findViewById(R.id.media_route_control_frame);
+                    customView.findViewById(R.id.media_route_control_frame);
             if (mControlView != null) {
                 controlFrame.addView(mControlView);
                 controlFrame.setVisibility(View.VISIBLE);
@@ -261,8 +230,7 @@
         Drawable icon = getIconDrawable();
         if (icon != mCurrentIconDrawable) {
             mCurrentIconDrawable = icon;
-            if (icon instanceof AnimationDrawable) {
-                AnimationDrawable animDrawable = (AnimationDrawable) icon;
+            if (icon instanceof AnimationDrawable animDrawable) {
                 if (!mAttachedToWindow && !mRoute.isConnecting()) {
                     // When the route is already connected before the view is attached, show the
                     // last frame of the connected animation immediately.
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index e3137e2..ac1e841 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -116,14 +116,14 @@
     <public name="alternateLauncherIcons"/>
     <!-- @FlaggedApi(android.content.pm.Flags.FLAG_CHANGE_LAUNCHER_BADGING) -->
     <public name="alternateLauncherLabels"/>
-    <!-- @hide Only for device overlay to use this. -->
-    <public name="pointerIconVectorFill"/>
-    <!-- @hide Only for device overlay to use this. -->
-    <public name="pointerIconVectorFillInverse"/>
-    <!-- @hide Only for device overlay to use this. -->
-    <public name="pointerIconVectorStroke"/>
-    <!-- @hide Only for device overlay to use this. -->
-    <public name="pointerIconVectorStrokeInverse"/>
+    <!-- @hide Wrongly added here. -->
+    <public name="removed_pointerIconVectorFill"/>
+    <!-- @hide Wrongly added here. -->
+    <public name="removed_pointerIconVectorFillInverse"/>
+    <!-- @hide Wrongly added here. -->
+    <public name="removed_pointerIconVectorStroke"/>
+    <!-- @hide Wrongly added here. -->
+    <public name="removed_pointerIconVectorStrokeInverse"/>
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01b20000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ffcfce9..06861b11 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1726,10 +1726,12 @@
   <java-symbol type="style" name="PointerIconVectorStyleFillBlue" />
   <java-symbol type="style" name="PointerIconVectorStyleFillPurple" />
   <java-symbol type="attr" name="pointerIconVectorFill" />
+  <java-symbol type="attr" name="pointerIconVectorFillInverse" />
   <java-symbol type="style" name="PointerIconVectorStyleStrokeWhite" />
   <java-symbol type="style" name="PointerIconVectorStyleStrokeBlack" />
   <java-symbol type="style" name="PointerIconVectorStyleStrokeNone" />
   <java-symbol type="attr" name="pointerIconVectorStroke" />
+  <java-symbol type="attr" name="pointerIconVectorStrokeInverse" />
   <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Title" />
   <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Info" />
 
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index c06ad64..4c49ff8 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -10,8 +10,8 @@
 filegroup {
     name: "FrameworksCoreTests-aidl",
     srcs: [
-        "src/**/I*.aidl",
         "aidl/**/I*.aidl",
+        "src/**/I*.aidl",
     ],
     visibility: ["//visibility:private"],
 }
@@ -19,13 +19,13 @@
 filegroup {
     name: "FrameworksCoreTests-helpers",
     srcs: [
-        "DisabledTestApp/src/**/*.java",
-        "EnabledTestApp/src/**/*.java",
+        "AppThatCallsBinderMethods/src/**/*.kt",
+        "BinderDeathRecipientHelperApp/src/**/*.java",
         "BinderFrozenStateChangeCallbackTestApp/src/**/*.java",
         "BinderProxyCountingTestApp/src/**/*.java",
         "BinderProxyCountingTestService/src/**/*.java",
-        "BinderDeathRecipientHelperApp/src/**/*.java",
-        "AppThatCallsBinderMethods/src/**/*.kt",
+        "DisabledTestApp/src/**/*.java",
+        "EnabledTestApp/src/**/*.java",
     ],
     visibility: ["//visibility:private"],
 }
@@ -45,11 +45,11 @@
     defaults: ["FrameworksCoreTests-resources"],
 
     srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
+        ":FrameworksCoreTestDoubles-sources",
         ":FrameworksCoreTests-aidl",
         ":FrameworksCoreTests-helpers",
-        ":FrameworksCoreTestDoubles-sources",
+        "src/**/*.java",
+        "src/**/*.kt",
     ],
 
     aidl: {
@@ -65,74 +65,74 @@
         "-c fa",
     ],
     static_libs: [
-        "collector-device-lib-platform",
-        "frameworks-base-testutils",
-        "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
-        "core-tests-support",
-        "cts-input-lib",
+        "TestParameterInjector",
         "android-common",
-        "frameworks-core-util-lib",
-        "mockwebserver",
-        "guava",
-        "guava-android-testlib",
         "android.app.usage.flags-aconfig-java",
+        "android.content.res.flags-aconfig-java",
+        "android.security.flags-aconfig-java",
         "android.view.accessibility.flags-aconfig-java",
         "androidx.core_core",
         "androidx.core_core-ktx",
         "androidx.test.core",
         "androidx.test.espresso.core",
         "androidx.test.ext.junit",
-        "androidx.test.runner",
         "androidx.test.rules",
-        "flag-junit",
-        "junit-params",
-        "kotlin-test",
-        "mockito-target-minus-junit4",
+        "androidx.test.runner",
         "androidx.test.uiautomator_uiautomator",
-        "platform-parametric-runner-lib",
-        "platform-test-annotations",
-        "platform-compat-test-rules",
-        "truth",
-        "print-test-util-lib",
-        "testng",
-        "servicestests-utils",
-        "device-time-shell-utils",
-        "testables",
+        "collector-device-lib-platform",
         "com.android.text.flags-aconfig-java",
+        "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
+        "core-tests-support",
+        "cts-input-lib",
+        "device-time-shell-utils",
         "flag-junit",
-        "ravenwood-junit",
-        "perfetto_trace_java_protos",
+        "flag-junit",
         "flickerlib-parsers",
         "flickerlib-trace_processor_shell",
-        "mockito-target-extended-minus-junit4",
-        "TestParameterInjector",
-        "android.content.res.flags-aconfig-java",
-        "android.security.flags-aconfig-java",
+        "frameworks-base-testutils",
+        "frameworks-core-util-lib",
+        "guava",
+        "guava-android-testlib",
+        "junit-params",
+        "kotlin-test",
         "mockito-kotlin2",
+        "mockito-target-extended-minus-junit4",
+        "mockito-target-minus-junit4",
+        "mockwebserver",
+        "perfetto_trace_java_protos",
+        "platform-compat-test-rules",
+        "platform-parametric-runner-lib",
+        "platform-test-annotations",
+        "print-test-util-lib",
+        "ravenwood-junit",
+        "servicestests-utils",
+        "testables",
+        "testng",
+        "truth",
     ],
 
     libs: [
-        "android.test.runner.stubs",
-        "org.apache.http.legacy.stubs",
         "android.test.base.stubs",
         "android.test.mock.stubs",
-        "framework",
-        "ext",
-        "framework-res",
+        "android.test.runner.stubs",
         "android.view.flags-aconfig-java",
+        "ext",
+        "framework",
+        "framework-res",
+        "org.apache.http.legacy.stubs",
     ],
     jni_libs: [
+        "libAppOpsTest_jni",
         "libpowermanagertest_jni",
         "libviewRootImplTest_jni",
         "libworksourceparceltest_jni",
-        "libAppOpsTest_jni",
     ],
 
     sdk_version: "core_platform",
     test_suites: [
-        "device-tests",
-        "device-platinum-tests",
         "automotive-tests",
+        "device-platinum-tests",
+        "device-tests",
     ],
 
     certificate: "platform",
@@ -141,21 +141,21 @@
     java_resources: [":FrameworksCoreTests_unit_test_cert_der"],
 
     data: [
+        ":AppThatCallsBinderMethods",
+        ":AppThatUsesAppOps",
         ":BinderDeathRecipientHelperApp1",
         ":BinderDeathRecipientHelperApp2",
-        ":com.android.cts.helpers.aosp",
         ":BinderFrozenStateChangeCallbackTestApp",
         ":BinderProxyCountingTestApp",
         ":BinderProxyCountingTestService",
-        ":AppThatUsesAppOps",
-        ":AppThatCallsBinderMethods",
-        ":HelloWorldSdk1",
-        ":HelloWorldUsingSdk1AndSdk1",
-        ":HelloWorldUsingSdk1And2",
-        ":HelloWorldUsingSdkMalformedNegativeVersion",
         ":CtsStaticSharedLibConsumerApp1",
         ":CtsStaticSharedLibConsumerApp3",
         ":CtsStaticSharedLibProviderApp1",
+        ":HelloWorldSdk1",
+        ":HelloWorldUsingSdk1And2",
+        ":HelloWorldUsingSdk1AndSdk1",
+        ":HelloWorldUsingSdkMalformedNegativeVersion",
+        ":com.android.cts.helpers.aosp",
     ],
 }
 
@@ -170,8 +170,8 @@
     // FrameworksCoreTestsRavenwood references the .aapt.srcjar
     use_resource_processor: false,
     libs: [
-        "framework-res",
         "android.test.runner.stubs",
+        "framework-res",
         "org.apache.http.legacy.stubs",
     ],
     uses_libs: [
@@ -231,16 +231,16 @@
     static_libs: [
         "androidx.test.espresso.core",
         "androidx.test.ext.junit",
-        "androidx.test.runner",
         "androidx.test.rules",
+        "androidx.test.runner",
         "mockito-target-minus-junit4",
         "truth",
     ],
 
     libs: [
-        "android.test.runner.stubs.system",
         "android.test.base.stubs.system",
         "android.test.mock.stubs.system",
+        "android.test.runner.stubs.system",
         "framework",
         "framework-res",
     ],
@@ -249,43 +249,43 @@
 android_ravenwood_test {
     name: "FrameworksCoreTestsRavenwood",
     libs: [
-        "android.test.runner.stubs.system",
         "android.test.base.stubs.system",
+        "android.test.runner.stubs.system",
     ],
     static_libs: [
-        "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
+        "androidx.annotation_annotation",
         "androidx.core_core",
         "androidx.core_core-ktx",
-        "androidx.annotation_annotation",
-        "androidx.test.rules",
         "androidx.test.ext.junit",
+        "androidx.test.rules",
         "androidx.test.uiautomator_uiautomator",
         "compatibility-device-util-axt-ravenwood",
+        "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
         "flag-junit",
-        "platform-test-annotations",
+        "flag-junit",
         "perfetto_trace_java_protos",
-        "flag-junit",
+        "platform-test-annotations",
         "testng",
     ],
     srcs: [
         "src/android/app/ActivityManagerTest.java",
+        "src/android/app/PropertyInvalidatedCacheTests.java",
         "src/android/colormodel/CamTest.java",
         "src/android/content/ContextTest.java",
+        "src/android/content/TestComponentCallbacks2.java",
         "src/android/content/pm/PackageManagerTest.java",
         "src/android/content/pm/UserInfoTest.java",
-        "src/android/app/PropertyInvalidatedCacheTests.java",
-        "src/android/database/CursorWindowTest.java",
-        "src/android/os/**/*.java",
         "src/android/content/res/*.java",
         "src/android/content/res/*.kt",
+        "src/android/database/CursorWindowTest.java",
+        "src/android/os/**/*.java",
         "src/android/telephony/PinResultTest.java",
         "src/android/util/**/*.java",
         "src/android/view/DisplayAdjustmentsTests.java",
-        "src/android/view/DisplayTest.java",
         "src/android/view/DisplayInfoTest.java",
+        "src/android/view/DisplayTest.java",
         "src/com/android/internal/logging/**/*.java",
         "src/com/android/internal/os/**/*.java",
-        "src/com/android/internal/util/**/*.java",
         "src/com/android/internal/power/EnergyConsumerStatsTest.java",
         "src/com/android/internal/ravenwood/**/*.java",
 
@@ -293,10 +293,12 @@
         // to avoid having a dependency to FrameworksCoreTests.
         // This way, when updating source files and running this test, we don't need to
         // rebuild the entire FrameworksCoreTests, which would be slow.
-        ":FrameworksCoreTests-resonly{.aapt.srcjar}",
+        "src/com/android/internal/util/**/*.java",
+
+        ":FrameworksCoreTestDoubles-sources",
         ":FrameworksCoreTests-aidl",
         ":FrameworksCoreTests-helpers",
-        ":FrameworksCoreTestDoubles-sources",
+        ":FrameworksCoreTests-resonly{.aapt.srcjar}",
     ],
     exclude_srcs: [
         "src/android/content/res/FontScaleConverterActivityTest.java",
@@ -320,8 +322,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
 }
@@ -331,12 +333,12 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
-        "com.android.internal.inputmethod",
         "android.view.inputmethod",
+        "com.android.internal.inputmethod",
     ],
     exclude_annotations: ["androidx.test.filters.FlakyTest"],
 }
@@ -346,8 +348,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.content.ContextTest"],
 }
@@ -357,8 +359,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.app.KeyguardManagerTest"],
 }
@@ -368,8 +370,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.app.PropertyInvalidatedCacheTests"],
 }
@@ -379,12 +381,12 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
-        "android.content.ContextTest",
         "android.content.ComponentCallbacksControllerTest",
+        "android.content.ContextTest",
         "android.content.ContextWrapperTest",
     ],
 }
@@ -394,8 +396,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.database.sqlite.SQLiteRawStatementTest"],
 }
@@ -405,8 +407,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.net"],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
@@ -417,8 +419,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.os.BatteryStatsTests"],
     exclude_annotations: ["com.android.internal.os.SkipPresubmit"],
@@ -429,8 +431,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.os.EnvironmentTest"],
 }
@@ -440,12 +442,12 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
-        "com.android.internal.util.FastDataTest",
         "android.util.CharsetUtilsTest",
+        "com.android.internal.util.FastDataTest",
     ],
 }
 
@@ -454,12 +456,12 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
-        "android.util.XmlTest",
         "android.util.BinaryXmlTest",
+        "android.util.XmlTest",
     ],
 }
 
@@ -468,8 +470,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.util.apk.SourceStampVerifierTest"],
 }
@@ -479,8 +481,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.view.textclassifier"],
     exclude_annotations: ["androidx.test.filters.FlakyTest"],
@@ -491,13 +493,13 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.app."],
     exclude_filters: [
-        "com.android.internal.app.WindowDecorActionBarTest",
         "com.android.internal.app.IntentForwarderActivityTest",
+        "com.android.internal.app.WindowDecorActionBarTest",
     ],
 }
 
@@ -506,8 +508,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.content."],
 }
@@ -517,8 +519,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.infra."],
 }
@@ -528,8 +530,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.jank"],
 }
@@ -539,16 +541,16 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
-        "android.os.BinderProxyTest",
         "android.os.BinderDeathRecipientTest",
         "android.os.BinderFrozenStateChangeNotificationTest",
         "android.os.BinderProxyCountingTest",
-        "android.os.BinderUncaughtExceptionHandlerTest",
+        "android.os.BinderProxyTest",
         "android.os.BinderThreadPriorityTest",
+        "android.os.BinderUncaughtExceptionHandlerTest",
         "android.os.BinderWorkSourceTest",
         "android.os.ParcelNullabilityTest",
         "android.os.ParcelTest",
@@ -562,13 +564,13 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
-        "com.android.internal.os.KernelCpuUidClusterTimeReaderTest",
-        "com.android.internal.os.KernelCpuUidBpfMapReaderTest",
         "com.android.internal.os.KernelCpuUidActiveTimeReaderTest",
+        "com.android.internal.os.KernelCpuUidBpfMapReaderTest",
+        "com.android.internal.os.KernelCpuUidClusterTimeReaderTest",
         "com.android.internal.os.KernelCpuUidFreqTimeReaderTest",
         "com.android.internal.os.KernelSingleUidTimeReaderTest",
     ],
@@ -579,8 +581,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.server.power.stats.BstatsCpuTimesValidationTest"],
 }
@@ -590,8 +592,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.security."],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
@@ -602,8 +604,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.util.LatencyTrackerTest"],
 }
@@ -613,8 +615,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.content.ContentCaptureOptionsTest"],
 }
@@ -624,8 +626,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.content.integrity."],
 }
@@ -635,8 +637,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.content.pm."],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
@@ -647,8 +649,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.content.pm."],
     include_annotations: ["android.platform.test.annotations.Postsubmit"],
@@ -659,14 +661,14 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.content.res."],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
     exclude_annotations: [
-        "androidx.test.filters.FlakyTest",
         "android.platform.test.annotations.Postsubmit",
+        "androidx.test.filters.FlakyTest",
         "org.junit.Ignore",
     ],
 }
@@ -676,8 +678,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.content.res."],
     include_annotations: ["android.platform.test.annotations.Postsubmit"],
@@ -688,17 +690,17 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
+        "android.service.controls",
+        "android.service.controls.actions",
+        "android.service.controls.templates",
         "android.service.euicc",
         "android.service.notification",
         "android.service.quicksettings",
         "android.service.settings.suggestions",
-        "android.service.controls.templates",
-        "android.service.controls.actions",
-        "android.service.controls",
     ],
     exclude_annotations: ["org.junit.Ignore"],
 }
@@ -708,8 +710,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.view.contentcapture"],
 }
@@ -719,8 +721,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.view.contentprotection"],
 }
@@ -730,8 +732,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.content."],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
@@ -742,8 +744,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.graphics.drawable.IconTest"],
 }
@@ -753,13 +755,13 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
-        "com.android.internal.accessibility",
         "android.accessibilityservice",
         "android.view.accessibility",
+        "com.android.internal.accessibility",
     ],
 }
 
@@ -768,8 +770,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.app.usage"],
 }
@@ -779,8 +781,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["com.android.internal.util.FastDataTest"],
 }
@@ -790,8 +792,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: ["android.hardware.input"],
 }
@@ -801,12 +803,12 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
-        "android.view.VerifiedMotionEventTest",
         "android.view.VerifiedKeyEventTest",
+        "android.view.VerifiedMotionEventTest",
     ],
 }
 
@@ -839,8 +841,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_filters: [
         "com.android.internal.jank.FrameTrackerTest",
@@ -854,8 +856,8 @@
     base: "FrameworksCoreTests",
     test_suites: [
         "automotive-tests",
-        "device-tests",
         "device-platinum-tests",
+        "device-tests",
     ],
     include_annotations: ["android.platform.test.annotations.PlatinumTest"],
 }
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index a02af78..2505500 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -35,17 +36,24 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.media.ImageReader;
+import android.os.Looper;
 import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.platform.test.ravenwood.RavenwoodRule;
 import android.view.Display;
+import android.window.WindowTokenClient;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.window.flags.Flags;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -61,6 +69,9 @@
     @Rule
     public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build();
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Test
     public void testInstrumentationContext() {
         // Confirm that we have a valid Context
@@ -280,4 +291,44 @@
         return appContext.createDisplayContext(display)
                 .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */);
     }
+
+    @Test
+    @DisabledOnRavenwood(blockedBy = Context.class)
+    @DisableFlags(Flags.FLAG_TRACK_SYSTEM_UI_CONTEXT_BEFORE_WMS)
+    public void testSysUiContextRegisterComponentCallbacks_disableFlag() {
+        Looper.prepare();
+
+        // Use createSystemActivityThreadForTesting to initialize
+        // systemUiContext#getApplicationContext.
+        final Context systemUiContext = ActivityThread.createSystemActivityThreadForTesting()
+                .getSystemUiContext();
+        final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2();
+        systemUiContext.registerComponentCallbacks(callbacks);
+
+        final WindowTokenClient windowTokenClient =
+                (WindowTokenClient) systemUiContext.getWindowContextToken();
+        windowTokenClient.onConfigurationChanged(Configuration.EMPTY, DEFAULT_DISPLAY);
+
+        assertWithMessage("ComponentCallbacks should delegate to the app Context "
+                + "if the flag is disabled.").that(callbacks.mConfiguration).isNull();
+    }
+
+    @Test
+    @DisabledOnRavenwood(blockedBy = Context.class)
+    @EnableFlags(Flags.FLAG_TRACK_SYSTEM_UI_CONTEXT_BEFORE_WMS)
+    public void testSysUiContextRegisterComponentCallbacks_enableFlag() {
+        final Context systemUiContext = ActivityThread.currentActivityThread()
+                .createSystemUiContextForTesting(DEFAULT_DISPLAY);
+        final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2();
+        final Configuration config = Configuration.EMPTY;
+
+        systemUiContext.registerComponentCallbacks(callbacks);
+
+        final WindowTokenClient windowTokenClient =
+                (WindowTokenClient) systemUiContext.getWindowContextToken();
+        windowTokenClient.onConfigurationChanged(config, DEFAULT_DISPLAY);
+
+        assertWithMessage("ComponentCallbacks should delegate to SystemUiContext "
+                + "if the flag is enabled.").that(callbacks.mConfiguration).isEqualTo(config);
+    }
 }
diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl
index 87cb942..0241f36 100644
--- a/data/keyboards/Vendor_0957_Product_0001.kl
+++ b/data/keyboards/Vendor_0957_Product_0001.kl
@@ -72,6 +72,8 @@
 key usage 0x000c008D    GUIDE
 key usage 0x000c0089    TV
 
+key usage 0x000c0187    FEATURED_APP_1    WAKE #FreeTv
+
 key usage 0x000c009C    CHANNEL_UP
 key usage 0x000c009D    CHANNEL_DOWN
 
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt
index 126ab3d..14338a4 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt
@@ -24,7 +24,6 @@
 import android.content.pm.ActivityInfo.OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS
 import android.window.DesktopModeFlags
 import com.android.internal.R
-import com.android.window.flags.Flags
 
 /**
  * Class to decide whether to apply app compat policies in desktop mode.
@@ -64,7 +63,7 @@
      * is enabled.
      */
     fun shouldExcludeCaptionFromAppBounds(taskInfo: TaskInfo): Boolean =
-        Flags.excludeCaptionFromAppBounds()
+        DesktopModeFlags.EXCLUDE_CAPTION_FROM_APP_BOUNDS.isTrue
                 && isAnyForceConsumptionFlagsEnabled()
                 && taskInfo.topActivityInfo?.let {
             isInsetsCoupledWithConfiguration(it) && (!taskInfo.isResizeable || it.isChangeEnabled(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index 9b850de6..c5ee313 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -33,6 +33,7 @@
 import com.android.wm.shell.R
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
+import kotlin.math.ceil
 
 val DESKTOP_MODE_INITIAL_BOUNDS_SCALE: Float =
     SystemProperties.getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f
@@ -190,22 +191,22 @@
     val finalWidth: Int
     // Get orientation either through top activity or task's orientation
     if (taskInfo.hasPortraitTopActivity()) {
-        val tempWidth = (targetHeight / aspectRatio).toInt()
+        val tempWidth = ceil(targetHeight / aspectRatio).toInt()
         if (tempWidth <= targetWidth) {
             finalHeight = targetHeight
             finalWidth = tempWidth
         } else {
             finalWidth = targetWidth
-            finalHeight = (finalWidth * aspectRatio).toInt()
+            finalHeight = ceil(finalWidth * aspectRatio).toInt()
         }
     } else {
-        val tempWidth = (targetHeight * aspectRatio).toInt()
+        val tempWidth = ceil(targetHeight * aspectRatio).toInt()
         if (tempWidth <= targetWidth) {
             finalHeight = targetHeight
             finalWidth = tempWidth
         } else {
             finalWidth = targetWidth
-            finalHeight = (finalWidth / aspectRatio).toInt()
+            finalHeight = ceil(finalWidth / aspectRatio).toInt()
         }
     }
     return Size(finalWidth, finalHeight + captionInsets)
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 e2c3dda..fcd92ac 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
@@ -285,7 +285,7 @@
     private val DEFAULT_PORTRAIT_BOUNDS = Rect(200, 165, 1400, 2085)
     private val RESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 435, 1575, 1635)
     private val RESIZABLE_PORTRAIT_BOUNDS = Rect(680, 75, 1880, 1275)
-    private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 449, 1575, 1611)
+    private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 448, 1575, 1611)
     private val UNRESIZABLE_PORTRAIT_BOUNDS = Rect(830, 75, 1730, 1275)
     private val wallpaperToken = MockToken().token()
     private val homeComponentName = ComponentName(HOME_LAUNCHER_PACKAGE_NAME, /* class */ "")
@@ -2900,7 +2900,10 @@
     }
 
     @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
+    @EnableFlags(
+        FLAG_ENABLE_DESKTOP_WINDOWING_PIP,
+        Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+    )
     fun onDesktopWindowClose_minimizedPipNotPresent_exitDesktop() {
         val freeformTask = setUpFreeformTask()
         val pipTask = setUpPipTask(autoEnterEnabled = true)
@@ -2915,10 +2918,8 @@
         val wct = WindowContainerTransaction()
         controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, freeformTask)
 
-        // Remove wallpaper operation
-        wct.hierarchyOps.any { hop ->
-            hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder()
-        }
+        // Moves wallpaper activity to back when leaving desktop
+        wct.assertReorder(wallpaperToken, toTop = false)
     }
 
     @Test
@@ -3224,6 +3225,24 @@
     }
 
     @Test
+    fun onDesktopWindowMinimize_triesToStopTiling() {
+        val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
+        val transition = Binder()
+        whenever(
+                freeformTaskTransitionStarter.startMinimizedModeTransition(
+                    any(),
+                    anyInt(),
+                    anyBoolean(),
+                )
+            )
+            .thenReturn(transition)
+
+        controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
+
+        verify(snapEventHandler).removeTaskIfTiled(eq(DEFAULT_DISPLAY), eq(task.taskId))
+    }
+
+    @Test
     fun handleRequest_fullscreenTask_freeformVisible_returnSwitchToFreeformWCT() {
         val homeTask = setUpHomeTask()
         val freeformTask = setUpFreeformTask()
@@ -4338,7 +4357,10 @@
     }
 
     @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
+    @EnableFlags(
+        FLAG_ENABLE_DESKTOP_WINDOWING_PIP,
+        Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+    )
     fun moveFocusedTaskToFullscreen_minimizedPipPresent_removeWallpaperActivity() {
         val freeformTask = setUpFreeformTask()
         val pipTask = setUpPipTask(autoEnterEnabled = true)
@@ -4356,10 +4378,8 @@
         val taskChange = assertNotNull(wct.changes[freeformTask.token.asBinder()])
         assertThat(taskChange.windowingMode)
             .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
-        // Remove wallpaper operation
-        wct.hierarchyOps.any { hop ->
-            hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder()
-        }
+        // Moves wallpaper activity to back when leaving desktop
+        wct.assertReorder(wallpaperToken, toTop = false)
     }
 
     @Test
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 1af3bc8..5590ca72 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -39,6 +39,7 @@
 import android.system.StructStat;
 import android.util.ArrayMap;
 import android.util.Base64;
+import android.util.Dumpable;
 import android.util.Log;
 
 import com.android.tools.r8.keepanno.annotations.KeepTarget;
@@ -52,18 +53,24 @@
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
 /**
  * Backup transport for stashing stuff into a known location on disk, and
  * later restoring from there.  For testing only.
+ *
+ * <p>Note: the quickest way to build and sync this class is:
+ * {@code m LocalTransport && adb install $OUT/system/priv-app/LocalTransport/LocalTransport.apk}
  */
 
 public class LocalTransport extends BackupTransport {
-    private static final String TAG = "LocalTransport";
-    private static final boolean DEBUG = false;
+    static final String TAG = "LocalTransport";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
 
     private static final String TRANSPORT_DIR_NAME
             = "com.android.localtransport.LocalTransport";
@@ -124,6 +131,8 @@
     }
 
     public LocalTransport(Context context, LocalTransportParameters parameters) {
+        Log.i(TAG, "Creating LocalTransport for user " + context.getUserId()
+                + " (DEBUG=" + DEBUG + ")");
         mContext = context;
         mParameters = parameters;
         makeDataDirs();
@@ -910,25 +919,70 @@
         return mMonitor;
     }
 
-    private class TestBackupManagerMonitor extends BackupManagerMonitor {
+    private class TestBackupManagerMonitor extends BackupManagerMonitor implements Dumpable {
+
+        private final List<DataTypeResult> mReceivedResults = new ArrayList<>();
+        private int mNumberReceivedEvents;
+
         @Override
         public void onEvent(Bundle event) {
-            if (event == null || !mParameters.logAgentResults()) {
+            if (event == null) {
+                if (DEBUG) {
+                    Log.w(TAG, "onEvent() called with null");
+                }
                 return;
             }
-
-            if (event.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID)
-                    == BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS) {
+            int eventId = event.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID);
+            if (eventId != BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS) {
+                if (DEBUG) Log.v(TAG, "ignoring event with id " + eventId);
+                return;
+            }
+            mNumberReceivedEvents++;
+            boolean logResults = mParameters.logAgentResults();
+            ArrayList<DataTypeResult> results = event.getParcelableArrayList(
+                    BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS,
+                    DataTypeResult.class);
+            int size = results.size();
+            if (size == 0) {
+                if (logResults) {
+                    Log.i(TAG, "no agent_logging_results on event #" + mNumberReceivedEvents);
+                }
+                return;
+            }
+            if (logResults) {
                 Log.i(TAG, "agent_logging_results {");
-                ArrayList<DataTypeResult> results = event.getParcelableArrayList(
-                        BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS,
-                        DataTypeResult.class);
-                for (DataTypeResult result : results) {
+            }
+            for (int i = 0; i < size; i++) {
+                var result = results.get(i);
+                mReceivedResults.add(result);
+                if (logResults) {
                     Log.i(TAG, "\t" + BackupRestoreEventLogger.toString(result));
                 }
+            }
+            if (logResults) {
                 Log.i(TAG, "}");
             }
         }
+
+        @Override
+        public void dump(PrintWriter pw, String[] args) {
+            pw.println("TestBackupManagerMonitor");
+            pw.printf("%d events received", mNumberReceivedEvents);
+            if (mNumberReceivedEvents == 0) {
+                pw.println();
+                return;
+            }
+            int size = mReceivedResults.size();
+            if (size == 0) {
+                pw.println("; no results on them");
+                return;
+            }
+            pw.printf("; %d results on them:\n", size);
+            for (int i = 0; i < size; i++) {
+                DataTypeResult result = mReceivedResults.get(i);
+                pw.printf("  #%d: %s\n", i, BackupRestoreEventLogger.toString(result));
+            }
+        }
     }
 
     @NonNull
@@ -941,4 +995,60 @@
         }
         return mParameters.noRestrictedModePackages();
     }
+
+    @Override
+    public String toString() {
+        try {
+            try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
+                dump(pw, /* args= */ null);
+                pw.flush();
+                return sw.toString();
+            }
+        } catch (IOException e) {
+            // Shouldn't happen...
+            Log.e(TAG, "toString(): failed to dump", e);
+            return super.toString();
+        }
+    }
+
+    void dump(PrintWriter pw, String[] args) {
+        pw.printf("mDataDir: %s\n", mDataDir);
+        pw.printf("mCurrentSetDir: %s\n", mCurrentSetDir);
+        pw.printf("mCurrentSetIncrementalDir: %s\n", mCurrentSetIncrementalDir);
+        pw.printf("mCurrentSetFullDir: %s\n", mCurrentSetFullDir);
+
+        pw.printf("mRestorePackages: %s\n", Arrays.toString(mRestorePackages));
+        pw.printf("mRestorePackage: %d\n", mRestorePackage);
+        pw.printf("mRestoreType: %d\n", mRestoreType);
+        pw.printf("mRestoreSetDir: %s\n", mRestoreSetDir);
+        pw.printf("mRestoreSetIncrementalDir: %s\n", mRestoreSetIncrementalDir);
+        pw.printf("mRestoreSetFullDir: %s\n", mRestoreSetFullDir);
+
+        pw.printf("mFullTargetPackage: %s\n", mFullTargetPackage);
+        pw.printf("mSocket: %s\n", mSocket);
+        pw.printf("mSocketInputStream: %s\n", mSocketInputStream);
+        pw.printf("mFullBackupOutputStream: %s\n", mFullBackupOutputStream);
+        dumpByteArray(pw, "mFullBackupBuffer", mFullBackupBuffer);
+        pw.printf("mFullBackupSize: %d\n", mFullBackupSize);
+
+        pw.printf("mCurFullRestoreStream: %s\n", mCurFullRestoreStream);
+        dumpByteArray(pw, "mFullRestoreBuffer", mFullRestoreBuffer);
+        if (mParameters == null) {
+            pw.println("No LocalTransportParameters");
+        } else {
+            pw.println(mParameters);
+        }
+        if (mMonitor instanceof Dumpable) {
+            ((Dumpable) mMonitor).dump(pw, args);
+        }
+
+        pw.printf("currentDestinationString(): %s\n", currentDestinationString());
+        pw.printf("dataManagementIntent(): %s\n", dataManagementIntent());
+        pw.printf("dataManagementIntentLabel(): %s\n", dataManagementIntentLabel());
+        pw.printf("transportDirName(): %s\n", transportDirName());
+    }
+
+    private void dumpByteArray(PrintWriter pw, String name, byte[] array) {
+        pw.printf("%s size: %d\n", name, (array == null ? 0 : array.length));
+    }
 }
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index c980913..c7cfc5b 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -16,11 +16,15 @@
 
 package com.android.localtransport;
 
+import static com.android.localtransport.LocalTransport.DEBUG;
+import static com.android.localtransport.LocalTransport.TAG;
+
 import android.content.ContentResolver;
 import android.os.Handler;
 import android.provider.Settings;
 import android.util.KeyValueListParser;
 import android.util.KeyValueSettingObserver;
+import android.util.Log;
 
 import java.util.Arrays;
 import java.util.List;
@@ -76,15 +80,30 @@
     }
 
     public String getSettingValue(ContentResolver resolver) {
-        return Settings.Secure.getString(resolver, SETTING);
+        String value = Settings.Secure.getString(resolver, SETTING);
+        if (DEBUG) {
+            Log.d(TAG, "LocalTransportParameters.getSettingValue(): returning " + value);
+        }
+        return value;
     }
 
     public void update(KeyValueListParser parser) {
-        mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
-        mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
-        mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false);
-        mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, false);
-        mLogAgentResults = parser.getBoolean(KEY_LOG_AGENT_RESULTS, /* def */ false);
+        mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, /* def= */ false);
+        mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, /* def= */ false);
+        mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, /* def= */ false);
+        mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, /* def= */ false);
+        mLogAgentResults = parser.getBoolean(KEY_LOG_AGENT_RESULTS, /* def= */ false);
         mNoRestrictedModePackages = parser.getString(KEY_NO_RESTRICTED_MODE_PACKAGES, /* def */ "");
     }
+
+    @Override
+    public String toString() {
+        return "LocalTransportParameters[mFakeEncryptionFlag=" + mFakeEncryptionFlag
+                + ", mIsNonIncrementalOnly=" + mIsNonIncrementalOnly
+                + ", mIsDeviceTransfer=" + mIsDeviceTransfer
+                + ", mIsEncrypted=" + mIsEncrypted
+                + ", mLogAgentResults=" + mLogAgentResults
+                + ", noRestrictedModePackages()=" + noRestrictedModePackages()
+                + "]";
+    }
 }
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java
index ac4f418..2f6c57a 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java
@@ -16,15 +16,28 @@
 
 package com.android.localtransport;
 
+import static com.android.localtransport.LocalTransport.DEBUG;
+import static com.android.localtransport.LocalTransport.TAG;
+
+import android.annotation.Nullable;
 import android.app.Service;
 import android.content.Intent;
 import android.os.IBinder;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 
 public class LocalTransportService extends Service {
-    private static LocalTransport sTransport = null;
+
+    @Nullable
+    private static LocalTransport sTransport;
 
     @Override
     public void onCreate() {
+        if (DEBUG) {
+            Log.d(TAG, "LocalTransportService.onCreate()");
+        }
         if (sTransport == null) {
             LocalTransportParameters parameters =
                     new LocalTransportParameters(getMainThreadHandler(), getContentResolver());
@@ -35,11 +48,27 @@
 
     @Override
     public void onDestroy() {
+        if (DEBUG) {
+            Log.d(TAG, "LocalTransportService.onDestroy()");
+        }
         sTransport.getParameters().stop();
     }
 
     @Override
     public IBinder onBind(Intent intent) {
+        if (DEBUG) {
+            Log.d(TAG, "LocalTransportService.onBind(" + intent + "): parameters="
+                    + sTransport.getParameters());
+        }
         return sTransport.getBinder();
     }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (sTransport == null) {
+            pw.println("No sTransport");
+            return;
+        }
+        sTransport.dump(pw, args);
+    }
 }
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt
index c61a2ac..481023e 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt
@@ -16,9 +16,6 @@
 
 package com.android.packageinstaller.v2.ui
 
-import android.app.Activity.RESULT_CANCELED
-import android.app.Activity.RESULT_FIRST_USER
-import android.app.Activity.RESULT_OK
 import android.app.AppOpsManager
 import android.content.ActivityNotFoundException
 import android.content.Intent
@@ -67,6 +64,7 @@
             InstallLaunch::class.java.packageName + ".callingPkgName"
         private val LOG_TAG = InstallLaunch::class.java.simpleName
         private const val TAG_DIALOG = "dialog"
+        private const val ARGS_SAVED_INTENT = "saved_intent"
     }
 
     /**
@@ -96,7 +94,15 @@
             intent.getStringExtra(EXTRA_CALLING_PKG_NAME),
             intent.getIntExtra(EXTRA_CALLING_PKG_UID, Process.INVALID_UID)
         )
-        installViewModel!!.preprocessIntent(intent, info)
+
+        var savedIntent: Intent? = null
+        if (savedInstanceState != null) {
+            savedIntent = savedInstanceState.getParcelable(ARGS_SAVED_INTENT, Intent::class.java)
+        }
+        if (!intent.filterEquals(savedIntent)) {
+            installViewModel!!.preprocessIntent(intent, info)
+        }
+
         installViewModel!!.currentInstallStage.observe(this) { installStage: InstallStage ->
             onInstallStageChange(installStage)
         }
@@ -344,6 +350,11 @@
         appOpsManager!!.stopWatchingMode(listener)
     }
 
+    override fun onSaveInstanceState(outState: Bundle) {
+        outState.putParcelable(ARGS_SAVED_INTENT, intent)
+        super.onSaveInstanceState(outState)
+    }
+
     override fun onDestroy() {
         super.onDestroy()
         while (activeUnknownSourcesListeners.isNotEmpty()) {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt
index c4ca272..0a02845e 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt
@@ -16,7 +16,6 @@
 
 package com.android.packageinstaller.v2.ui
 
-import android.app.Activity
 import android.app.NotificationManager
 import android.content.Intent
 import android.os.Bundle
@@ -51,6 +50,7 @@
             UninstallLaunch::class.java.packageName + ".callingActivityName"
         val LOG_TAG = UninstallLaunch::class.java.simpleName
         private const val TAG_DIALOG = "dialog"
+        private const val ARGS_SAVED_INTENT = "saved_intent"
     }
 
     private var uninstallViewModel: UninstallViewModel? = null
@@ -76,7 +76,15 @@
             intent.getStringExtra(EXTRA_CALLING_ACTIVITY_NAME),
             intent.getIntExtra(EXTRA_CALLING_PKG_UID, Process.INVALID_UID)
         )
-        uninstallViewModel!!.preprocessIntent(intent, callerInfo)
+
+        var savedIntent: Intent? = null
+        if (savedInstanceState != null) {
+            savedIntent = savedInstanceState.getParcelable(ARGS_SAVED_INTENT, Intent::class.java)
+        }
+        if (!intent.filterEquals(savedIntent)) {
+            uninstallViewModel!!.preprocessIntent(intent, callerInfo)
+        }
+
         uninstallViewModel!!.currentUninstallStage.observe(this) { uninstallStage: UninstallStage ->
             onUninstallStageChange(uninstallStage)
         }
@@ -171,6 +179,11 @@
             Log.d(LOG_TAG, "Cancelling uninstall")
         }
         uninstallViewModel!!.cancelUninstall()
-        setResult(Activity.RESULT_FIRST_USER, null, true)
+        setResult(RESULT_FIRST_USER, null, true)
+    }
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        outState.putParcelable(ARGS_SAVED_INTENT, intent)
+        super.onSaveInstanceState(outState)
     }
 }
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt
index 388e03f..5a2b122 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt
@@ -49,6 +49,20 @@
                 _currentInstallStage.value = installStage
             }
         }
+
+        // Since staging is an async operation, we will get the staging result later in time.
+        // Result of the file staging will be set in InstallRepository#mStagingResult.
+        // As such, mCurrentInstallStage will need to add another MutableLiveData
+        // as a data source
+        _currentInstallStage.addSource(
+            repository.stagingResult.distinctUntilChanged()
+        ) { installStage: InstallStage ->
+            if (installStage.stageCode != InstallStage.STAGE_READY) {
+                _currentInstallStage.value = installStage
+            } else {
+                checkIfAllowedAndInitiateInstall()
+            }
+        }
     }
 
     fun preprocessIntent(intent: Intent, callerInfo: InstallRepository.CallerInfo) {
@@ -56,18 +70,7 @@
         if (stage.stageCode == InstallStage.STAGE_ABORTED) {
             _currentInstallStage.value = stage
         } else {
-            // Since staging is an async operation, we will get the staging result later in time.
-            // Result of the file staging will be set in InstallRepository#mStagingResult.
-            // As such, mCurrentInstallStage will need to add another MutableLiveData
-            // as a data source
             repository.stageForInstall()
-            _currentInstallStage.addSource(repository.stagingResult) { installStage: InstallStage ->
-                if (installStage.stageCode != InstallStage.STAGE_READY) {
-                    _currentInstallStage.value = installStage
-                } else {
-                    checkIfAllowedAndInitiateInstall()
-                }
-            }
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index a00484a..522a436 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -555,22 +555,17 @@
      * connected 2) is Hearing Aid or LE Audio OR 3) connected profile matches currentAudioProfile
      *
      * @param cachedDevice the CachedBluetoothDevice
-     * @param audioManager audio manager to get the current audio profile
+     * @param isOngoingCall get the current audio profile based on if in phone call
      * @return if the device is AvailableMediaBluetoothDevice
      */
     @WorkerThread
     public static boolean isAvailableMediaBluetoothDevice(
-            CachedBluetoothDevice cachedDevice, AudioManager audioManager) {
-        int audioMode = audioManager.getMode();
+            CachedBluetoothDevice cachedDevice, boolean isOngoingCall) {
         int currentAudioProfile;
 
-        if (audioMode == AudioManager.MODE_RINGTONE
-                || audioMode == AudioManager.MODE_IN_CALL
-                || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
-            // in phone call
+        if (isOngoingCall) {
             currentAudioProfile = BluetoothProfile.HEADSET;
         } else {
-            // without phone call
             currentAudioProfile = BluetoothProfile.A2DP;
         }
 
@@ -859,22 +854,17 @@
      * currentAudioProfile
      *
      * @param cachedDevice the CachedBluetoothDevice
-     * @param audioManager audio manager to get the current audio profile
+     * @param isOngoingCall get the current audio profile based on if in phone call
      * @return if the device is AvailableMediaBluetoothDevice
      */
     @WorkerThread
     public static boolean isConnectedBluetoothDevice(
-            CachedBluetoothDevice cachedDevice, AudioManager audioManager) {
-        int audioMode = audioManager.getMode();
+            CachedBluetoothDevice cachedDevice, boolean isOngoingCall) {
         int currentAudioProfile;
 
-        if (audioMode == AudioManager.MODE_RINGTONE
-                || audioMode == AudioManager.MODE_IN_CALL
-                || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
-            // in phone call
+        if (isOngoingCall) {
             currentAudioProfile = BluetoothProfile.HEADSET;
         } else {
-            // without phone call
             currentAudioProfile = BluetoothProfile.A2DP;
         }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index 7c46db9..ebe6128 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -87,7 +87,6 @@
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private BluetoothDevice mBluetoothDevice;
 
-    @Mock private AudioManager mAudioManager;
     @Mock private PackageManager mPackageManager;
     @Mock private LeAudioProfile mA2dpProfile;
     @Mock private LeAudioProfile mLeAudioProfile;
@@ -446,13 +445,12 @@
 
         assertThat(
                         BluetoothUtils.isAvailableMediaBluetoothDevice(
-                                mCachedBluetoothDevice, mAudioManager))
+                                mCachedBluetoothDevice, /* isOngoingCall= */ false))
                 .isTrue();
     }
 
     @Test
     public void isAvailableMediaBluetoothDevice_isHeadset_isConnectedA2dpDevice_returnFalse() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
@@ -460,13 +458,12 @@
 
         assertThat(
                         BluetoothUtils.isAvailableMediaBluetoothDevice(
-                                mCachedBluetoothDevice, mAudioManager))
+                                mCachedBluetoothDevice,  /* isOngoingCall= */ true))
                 .isFalse();
     }
 
     @Test
     public void isAvailableMediaBluetoothDevice_isA2dp_isConnectedA2dpDevice_returnTrue() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
@@ -474,13 +471,12 @@
 
         assertThat(
                         BluetoothUtils.isAvailableMediaBluetoothDevice(
-                                mCachedBluetoothDevice, mAudioManager))
+                                mCachedBluetoothDevice,  /* isOngoingCall= */ false))
                 .isTrue();
     }
 
     @Test
     public void isAvailableMediaBluetoothDevice_isHeadset_isConnectedHfpDevice_returnTrue() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
         when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
@@ -488,7 +484,7 @@
 
         assertThat(
                         BluetoothUtils.isAvailableMediaBluetoothDevice(
-                                mCachedBluetoothDevice, mAudioManager))
+                                mCachedBluetoothDevice, /* isOngoingCall= */ true))
                 .isTrue();
     }
 
@@ -499,56 +495,52 @@
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         when(mBluetoothDevice.isConnected()).thenReturn(true);
 
-        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager))
-                .isFalse();
+        assertThat(BluetoothUtils.isConnectedBluetoothDevice(
+                mCachedBluetoothDevice, /* isOngoingCall= */ false)).isFalse();
     }
 
     @Test
     public void isConnectedBluetoothDevice_isHeadset_isConnectedA2dpDevice_returnTrue() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         when(mBluetoothDevice.isConnected()).thenReturn(true);
 
-        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager))
-                .isTrue();
+        assertThat(BluetoothUtils.isConnectedBluetoothDevice(
+                mCachedBluetoothDevice,  /* isOngoingCall= */ true)).isTrue();
     }
 
     @Test
     public void isConnectedBluetoothDevice_isA2dp_isConnectedA2dpDevice_returnFalse() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         when(mBluetoothDevice.isConnected()).thenReturn(true);
 
-        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager))
-                .isFalse();
+        assertThat(BluetoothUtils.isConnectedBluetoothDevice(
+                mCachedBluetoothDevice, /* isOngoingCall= */ false)).isFalse();
     }
 
     @Test
     public void isConnectedBluetoothDevice_isHeadset_isConnectedHfpDevice_returnFalse() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
         when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         when(mBluetoothDevice.isConnected()).thenReturn(true);
 
-        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager))
-                .isFalse();
+        assertThat(BluetoothUtils.isConnectedBluetoothDevice(
+                mCachedBluetoothDevice,  /* isOngoingCall= */ true)).isFalse();
     }
 
     @Test
     public void isConnectedBluetoothDevice_isNotConnected_returnFalse() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         when(mBluetoothDevice.isConnected()).thenReturn(false);
 
-        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager))
-                .isFalse();
+        assertThat(BluetoothUtils.isConnectedBluetoothDevice(
+                mCachedBluetoothDevice,  /* isOngoingCall= */ true)).isFalse();
     }
 
     @Test
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
index fffc7f9..2d2a8154 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
@@ -16,6 +16,8 @@
 
 package com.android.compose.animation.scene
 
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.MotionScheme
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
@@ -59,4 +61,8 @@
 
     override val layoutDirection: LayoutDirection
         get() = layoutImpl.layoutDirection
+
+    @ExperimentalMaterial3ExpressiveApi
+    override val motionScheme: MotionScheme
+        get() = layoutImpl.state.motionScheme
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index e0b4218..613afe2 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -18,7 +18,8 @@
 
 import androidx.compose.animation.core.Easing
 import androidx.compose.animation.core.LinearEasing
-import androidx.compose.ui.geometry.Offset
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.MotionScheme
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
@@ -29,8 +30,8 @@
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.ElementStateScope
-import com.android.compose.animation.scene.Scale
 import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.PropertyTransformation.Property
 import kotlinx.coroutines.CoroutineScope
 
 /** A transformation applied to one or more elements during a transition. */
@@ -126,9 +127,13 @@
     ): T
 }
 
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
 interface PropertyTransformationScope : Density, ElementStateScope {
     /** The current [direction][LayoutDirection] of the layout. */
     val layoutDirection: LayoutDirection
+
+    /** The [MotionScheme] in use by the [SceneTransitionLayout]. */
+    val motionScheme: MotionScheme
 }
 
 /** Defines the transformation-type to be applied to all elements matching [matcher]. */
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 e4539b7..0b13900 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
@@ -45,7 +45,6 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
-import android.os.Handler;
 import android.platform.test.annotations.EnableFlags;
 import android.provider.Settings;
 import android.testing.TestableLooper;
@@ -75,6 +74,8 @@
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.After;
 import org.junit.Before;
@@ -107,6 +108,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 final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Mock
     private SystemUIDialogManager mSystemUIDialogManager;
@@ -150,11 +152,9 @@
     private SystemUIDialog mDialog;
     private SystemUIDialog.Factory mDialogFactory;
     private HearingDevicesDialogDelegate mDialogDelegate;
-    private TestableLooper mTestableLooper;
 
     @Before
     public void setUp() {
-        mTestableLooper = TestableLooper.get(this);
         when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter);
         when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
         when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
@@ -186,6 +186,7 @@
     public void clickPairNewDeviceButton_intentActionMatch() {
         setUpDeviceDialogWithPairNewDeviceButton();
         mDialog.show();
+        mExecutor.runAllReady();
 
         getPairNewDeviceButton(mDialog).performClick();
 
@@ -232,6 +233,7 @@
 
         setUpDeviceDialogWithoutPairNewDeviceButton();
         mDialog.show();
+        mExecutor.runAllReady();
 
         assertToolsUi(0);
     }
@@ -246,6 +248,7 @@
 
         setUpDeviceDialogWithoutPairNewDeviceButton();
         mDialog.show();
+        mExecutor.runAllReady();
 
         assertToolsUi(1);
     }
@@ -267,6 +270,7 @@
 
         setUpDeviceDialogWithoutPairNewDeviceButton();
         mDialog.show();
+        mExecutor.runAllReady();
 
         assertToolsUi(2);
     }
@@ -278,6 +282,7 @@
 
         setUpDeviceDialogWithoutPairNewDeviceButton();
         mDialog.show();
+        mExecutor.runAllReady();
 
         ViewGroup presetLayout = getPresetLayout(mDialog);
         assertThat(presetLayout.getVisibility()).isEqualTo(View.GONE);
@@ -291,7 +296,7 @@
 
         setUpDeviceDialogWithoutPairNewDeviceButton();
         mDialog.show();
-        mTestableLooper.processAllMessages();
+        mExecutor.runAllReady();
 
         ViewGroup presetLayout = getPresetLayout(mDialog);
         assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE);
@@ -306,6 +311,7 @@
 
         setUpDeviceDialogWithoutPairNewDeviceButton();
         mDialog.show();
+        mExecutor.runAllReady();
 
         ViewGroup ambientLayout = getAmbientLayout(mDialog);
         assertThat(ambientLayout.getVisibility()).isEqualTo(View.GONE);
@@ -318,6 +324,7 @@
 
         setUpDeviceDialogWithoutPairNewDeviceButton();
         mDialog.show();
+        mExecutor.runAllReady();
 
         ViewGroup ambientLayout = getAmbientLayout(mDialog);
         assertThat(ambientLayout.getVisibility()).isEqualTo(View.GONE);
@@ -343,6 +350,7 @@
     public void onActiveDeviceChanged_presetExist_presetSelected() {
         setUpDeviceDialogWithoutPairNewDeviceButton();
         mDialog.show();
+        mExecutor.runAllReady();
         BluetoothHapPresetInfo info = getTestPresetInfo();
         when(mHapClientProfile.getAllPresetInfo(mDevice)).thenReturn(List.of(info));
         when(mHapClientProfile.getActivePresetIndex(mDevice)).thenReturn(TEST_PRESET_INDEX);
@@ -351,7 +359,7 @@
         assertThat(spinner.getSelectedItemPosition()).isEqualTo(-1);
 
         mDialogDelegate.onActiveDeviceChanged(mCachedDevice, BluetoothProfile.LE_AUDIO);
-        mTestableLooper.processAllMessages();
+        mExecutor.runAllReady();
 
         ViewGroup presetLayout = getPresetLayout(mDialog);
         assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE);
@@ -381,7 +389,8 @@
                 mActivityStarter,
                 mDialogTransitionAnimator,
                 mLocalBluetoothManager,
-                new Handler(mTestableLooper.getLooper()),
+                mExecutor,
+                mExecutor,
                 mAudioManager,
                 mUiEventLogger
         );
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 438184d..22ecb0a 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -30,7 +30,6 @@
 import android.content.res.Resources;
 import android.media.AudioManager;
 import android.os.Bundle;
-import android.os.Handler;
 import android.provider.Settings;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -49,6 +48,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -57,7 +57,6 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
-import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.accessibility.hearingaid.HearingDevicesListAdapter.HearingDeviceItemCallback;
 import com.android.systemui.animation.DialogTransitionAnimator;
 import com.android.systemui.bluetooth.qsdialog.ActiveHearingDeviceItemFactory;
@@ -67,6 +66,7 @@
 import com.android.systemui.bluetooth.qsdialog.DeviceItemFactory;
 import com.android.systemui.bluetooth.qsdialog.DeviceItemType;
 import com.android.systemui.bluetooth.qsdialog.SavedHearingDeviceItemFactory;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.res.R;
@@ -79,6 +79,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.stream.Collectors;
 
 /**
@@ -101,7 +102,8 @@
     private final DialogTransitionAnimator mDialogTransitionAnimator;
     private final ActivityStarter mActivityStarter;
     private final LocalBluetoothManager mLocalBluetoothManager;
-    private final Handler mMainHandler;
+    private final Executor mMainExecutor;
+    private final Executor mBgExecutor;
     private final AudioManager mAudioManager;
     private final LocalBluetoothProfileManager mProfileManager;
     private final HearingDevicesUiEventLogger mUiEventLogger;
@@ -109,8 +111,6 @@
     private final int mLaunchSourceId;
 
     private SystemUIDialog mDialog;
-
-    private List<DeviceItem> mHearingDeviceItemList;
     private HearingDevicesListAdapter mDeviceListAdapter;
 
     private View mPresetLayout;
@@ -122,14 +122,14 @@
                 @Override
                 public void onPresetInfoUpdated(List<BluetoothHapPresetInfo> presetInfos,
                         int activePresetIndex) {
-                    mMainHandler.post(
+                    mMainExecutor.execute(
                             () -> refreshPresetUi(presetInfos, activePresetIndex));
                 }
 
                 @Override
                 public void onPresetCommandFailed(int reason) {
                     mPresetController.refreshPresetInfo();
-                    mMainHandler.post(() -> {
+                    mMainExecutor.execute(() -> {
                         showErrorToast(R.string.hearing_devices_presets_error);
                     });
                 }
@@ -166,7 +166,8 @@
             ActivityStarter activityStarter,
             DialogTransitionAnimator dialogTransitionAnimator,
             @Nullable LocalBluetoothManager localBluetoothManager,
-            @Main Handler handler,
+            @Main Executor mainExecutor,
+            @Background Executor bgExecutor,
             AudioManager audioManager,
             HearingDevicesUiEventLogger uiEventLogger) {
         mShowPairNewDevice = showPairNewDevice;
@@ -174,7 +175,8 @@
         mActivityStarter = activityStarter;
         mDialogTransitionAnimator = dialogTransitionAnimator;
         mLocalBluetoothManager = localBluetoothManager;
-        mMainHandler = handler;
+        mMainExecutor = mainExecutor;
+        mBgExecutor = bgExecutor;
         mAudioManager = audioManager;
         mProfileManager = localBluetoothManager.getProfileManager();
         mUiEventLogger = uiEventLogger;
@@ -227,9 +229,10 @@
     @Override
     public void onActiveDeviceChanged(@Nullable CachedBluetoothDevice activeDevice,
             int bluetoothProfile) {
-        refreshDeviceUi();
-        mMainHandler.post(() -> {
-            CachedBluetoothDevice device = getActiveHearingDevice();
+        List<DeviceItem> hearingDeviceItemList = getHearingDeviceItemList();
+        refreshDeviceUi(hearingDeviceItemList);
+        mMainExecutor.execute(() -> {
+            CachedBluetoothDevice device = getActiveHearingDevice(hearingDeviceItemList);
             if (mPresetController != null) {
                 mPresetController.setDevice(device);
                 mPresetLayout.setVisibility(
@@ -244,13 +247,15 @@
     @Override
     public void onProfileConnectionStateChanged(@NonNull CachedBluetoothDevice cachedDevice,
             int state, int bluetoothProfile) {
-        refreshDeviceUi();
+        List<DeviceItem> hearingDeviceItemList = getHearingDeviceItemList();
+        refreshDeviceUi(hearingDeviceItemList);
     }
 
     @Override
     public void onAclConnectionStateChanged(@NonNull CachedBluetoothDevice cachedDevice,
             int state) {
-        refreshDeviceUi();
+        List<DeviceItem> hearingDeviceItemList = getHearingDeviceItemList();
+        refreshDeviceUi(hearingDeviceItemList);
     }
 
     @Override
@@ -280,18 +285,25 @@
 
         mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DIALOG_SHOW, mLaunchSourceId);
 
-        setupDeviceListView(dialog);
-        setupPairNewDeviceButton(dialog);
-        setupPresetSpinner(dialog);
-        if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) {
-            setupAmbientControls();
-        }
-        setupRelatedToolsView(dialog);
+        mBgExecutor.execute(() -> {
+            List<DeviceItem> hearingDeviceItemList = getHearingDeviceItemList();
+            CachedBluetoothDevice activeHearingDevice = getActiveHearingDevice(
+                    hearingDeviceItemList);
+            mMainExecutor.execute(() -> {
+                setupDeviceListView(dialog, hearingDeviceItemList);
+                setupPairNewDeviceButton(dialog);
+                setupPresetSpinner(dialog, activeHearingDevice);
+                if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) {
+                    setupAmbientControls(activeHearingDevice);
+                }
+                setupRelatedToolsView(dialog);
+            });
+        });
     }
 
     @Override
     public void onStart(@NonNull SystemUIDialog dialog) {
-        ThreadUtils.postOnBackgroundThread(() -> {
+        mBgExecutor.execute(() -> {
             if (mLocalBluetoothManager != null) {
                 mLocalBluetoothManager.getEventManager().registerCallback(this);
             }
@@ -306,7 +318,7 @@
 
     @Override
     public void onStop(@NonNull SystemUIDialog dialog) {
-        ThreadUtils.postOnBackgroundThread(() -> {
+        mBgExecutor.execute(() -> {
             if (mLocalBluetoothManager != null) {
                 mLocalBluetoothManager.getEventManager().unregisterCallback(this);
             }
@@ -319,17 +331,18 @@
         });
     }
 
-    private void setupDeviceListView(SystemUIDialog dialog) {
+    private void setupDeviceListView(SystemUIDialog dialog,
+            List<DeviceItem> hearingDeviceItemList) {
         final RecyclerView deviceList = dialog.requireViewById(R.id.device_list);
         deviceList.setLayoutManager(new LinearLayoutManager(dialog.getContext()));
-        mHearingDeviceItemList = getHearingDeviceItemList();
-        mDeviceListAdapter = new HearingDevicesListAdapter(mHearingDeviceItemList, this);
+        mDeviceListAdapter = new HearingDevicesListAdapter(hearingDeviceItemList, this);
         deviceList.setAdapter(mDeviceListAdapter);
     }
 
-    private void setupPresetSpinner(SystemUIDialog dialog) {
+    private void setupPresetSpinner(SystemUIDialog dialog,
+            CachedBluetoothDevice activeHearingDevice) {
         mPresetController = new HearingDevicesPresetsController(mProfileManager, mPresetCallback);
-        mPresetController.setDevice(getActiveHearingDevice());
+        mPresetController.setDevice(activeHearingDevice);
 
         mPresetSpinner = dialog.requireViewById(R.id.preset_spinner);
         mPresetInfoAdapter = new HearingDevicesSpinnerAdapter(dialog.getContext());
@@ -367,12 +380,12 @@
         mPresetLayout.setVisibility(mPresetController.isPresetControlAvailable() ? VISIBLE : GONE);
     }
 
-    private void setupAmbientControls() {
+    private void setupAmbientControls(CachedBluetoothDevice activeHearingDevice) {
         final AmbientVolumeLayout ambientLayout = mDialog.requireViewById(R.id.ambient_layout);
         mAmbientController = new AmbientVolumeUiController(
                 mDialog.getContext(), mLocalBluetoothManager, ambientLayout);
         mAmbientController.setShowUiWhenLocalDataExist(false);
-        mAmbientController.loadDevice(getActiveHearingDevice());
+        mAmbientController.loadDevice(activeHearingDevice);
     }
 
     private void setupPairNewDeviceButton(SystemUIDialog dialog) {
@@ -429,10 +442,11 @@
         }
     }
 
-    private void refreshDeviceUi() {
-        mHearingDeviceItemList = getHearingDeviceItemList();
-        mMainHandler.post(() -> {
-            mDeviceListAdapter.refreshDeviceItemList(mHearingDeviceItemList);
+    private void refreshDeviceUi(List<DeviceItem> hearingDeviceItemList) {
+        mMainExecutor.execute(() -> {
+            if (mDeviceListAdapter != null) {
+                mDeviceListAdapter.refreshDeviceItemList(hearingDeviceItemList);
+            }
         });
     }
 
@@ -463,21 +477,27 @@
     }
 
     @Nullable
-    private CachedBluetoothDevice getActiveHearingDevice() {
-        return mHearingDeviceItemList.stream()
+    private static CachedBluetoothDevice getActiveHearingDevice(
+            List<DeviceItem> hearingDeviceItemList) {
+        return hearingDeviceItemList.stream()
                 .filter(item -> item.getType() == DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE)
                 .map(DeviceItem::getCachedBluetoothDevice)
                 .findFirst()
                 .orElse(null);
     }
 
+    @WorkerThread
     private DeviceItem createHearingDeviceItem(CachedBluetoothDevice cachedDevice) {
         final Context context = mDialog.getContext();
         if (cachedDevice == null) {
             return null;
         }
+        int mode = mAudioManager.getMode();
+        boolean isOngoingCall = mode == AudioManager.MODE_RINGTONE
+                || mode == AudioManager.MODE_IN_CALL
+                || mode == AudioManager.MODE_IN_COMMUNICATION;
         for (DeviceItemFactory itemFactory : mHearingDeviceItemFactoryList) {
-            if (itemFactory.isFilterMatched(context, cachedDevice, mAudioManager)) {
+            if (itemFactory.isFilterMatched(context, cachedDevice, isOngoingCall)) {
                 return itemFactory.create(context, cachedDevice);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt
index ff2d9ef..1c9cf8d 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt
@@ -31,6 +31,7 @@
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.UiEventLogger
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
 import com.android.systemui.Prefs
 import com.android.systemui.animation.DialogCuj
 import com.android.systemui.animation.DialogTransitionAnimator
@@ -71,6 +72,7 @@
     private val bluetoothStateInteractor: BluetoothStateInteractor,
     private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor,
     private val audioSharingInteractor: AudioSharingInteractor,
+    private val audioModeInteractor: AudioModeInteractor,
     private val audioSharingButtonViewModelFactory: AudioSharingButtonViewModel.Factory,
     private val bluetoothDeviceMetadataInteractor: BluetoothDeviceMetadataInteractor,
     private val dialogTransitionAnimator: DialogTransitionAnimator,
@@ -167,6 +169,7 @@
                 // the device item list and animate the progress bar.
                 merge(
                         deviceItemInteractor.deviceItemUpdateRequest,
+                        audioModeInteractor.isOngoingCall,
                         bluetoothDeviceMetadataInteractor.metadataUpdate,
                         if (
                             audioSharingInteractor.audioSharingAvailable() &&
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 095e6e7..bfbc27d 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
@@ -18,7 +18,6 @@
 
 import android.bluetooth.BluetoothDevice
 import android.content.Context
-import android.media.AudioManager
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
@@ -43,7 +42,7 @@
     abstract fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean
 
@@ -51,8 +50,8 @@
     fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
-    ): Boolean = isFilterMatched(context, cachedDevice, audioManager, false)
+        isOngoingCall: Boolean,
+    ): Boolean = isFilterMatched(context, cachedDevice, isOngoingCall, false)
 
     abstract fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem
 
@@ -88,11 +87,11 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return BluetoothUtils.isActiveMediaDevice(cachedDevice) &&
-            BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, audioManager)
+            BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, isOngoingCall)
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -113,10 +112,11 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return audioSharingAvailable &&
+            !isOngoingCall &&
             BluetoothUtils.hasConnectedBroadcastSource(cachedDevice, localBluetoothManager)
     }
 
@@ -140,11 +140,12 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return audioSharingAvailable &&
-            super.isFilterMatched(context, cachedDevice, audioManager, true) &&
+            !isOngoingCall &&
+            super.isFilterMatched(context, cachedDevice, false, true) &&
             BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice(
                 cachedDevice,
                 localBluetoothManager,
@@ -170,7 +171,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return BluetoothUtils.isActiveMediaDevice(cachedDevice) &&
@@ -182,11 +183,11 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return !BluetoothUtils.isActiveMediaDevice(cachedDevice) &&
-            BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, audioManager)
+            BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, isOngoingCall)
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -206,7 +207,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return !BluetoothUtils.isActiveMediaDevice(cachedDevice) &&
@@ -218,14 +219,14 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
             !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
-                BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
+                BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, isOngoingCall)
         } else {
-            BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
+            BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, isOngoingCall)
         }
     }
 
@@ -246,7 +247,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
@@ -275,7 +276,7 @@
     override fun isFilterMatched(
         context: Context,
         cachedDevice: CachedBluetoothDevice,
-        audioManager: AudioManager,
+        isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
         return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
index 1e0ba8e..b606c19 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt
@@ -19,10 +19,10 @@
 import android.bluetooth.BluetoothAdapter
 import android.bluetooth.BluetoothDevice
 import android.content.Context
-import android.media.AudioManager
 import com.android.settingslib.bluetooth.BluetoothCallback
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
@@ -39,6 +39,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.shareIn
 import kotlinx.coroutines.isActive
@@ -51,7 +52,6 @@
 constructor(
     private val bluetoothTileDialogRepository: BluetoothTileDialogRepository,
     private val audioSharingInteractor: AudioSharingInteractor,
-    private val audioManager: AudioManager,
     private val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter(),
     private val localBluetoothManager: LocalBluetoothManager?,
     private val systemClock: SystemClock,
@@ -60,6 +60,7 @@
     private val deviceItemDisplayPriority: List<@JvmSuppressWildcards DeviceItemType>,
     @Application private val coroutineScope: CoroutineScope,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val audioModeInteractor: AudioModeInteractor,
 ) {
 
     private val mutableDeviceItemUpdate: MutableSharedFlow<List<DeviceItem>> =
@@ -118,8 +119,12 @@
 
     internal suspend fun updateDeviceItems(context: Context, trigger: DeviceFetchTrigger) {
         withContext(backgroundDispatcher) {
+            if (!isActive) {
+                return@withContext
+            }
             val start = systemClock.elapsedRealtime()
             val audioSharingAvailable = audioSharingInteractor.audioSharingAvailable()
+            val isOngoingCall = audioModeInteractor.isOngoingCall.first()
             val deviceItems =
                 bluetoothTileDialogRepository.cachedDevices
                     .mapNotNull { cachedDevice ->
@@ -128,7 +133,7 @@
                                 it.isFilterMatched(
                                     context,
                                     cachedDevice,
-                                    audioManager,
+                                    isOngoingCall,
                                     audioSharingAvailable,
                                 )
                             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java
index 3b6b9ed..47e725c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.headsup;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.RemoteException;
 import android.view.MotionEvent;
@@ -210,10 +211,12 @@
                         if (mHeadsUpManager.shouldSwallowClick(
                                 mPickedChild.getEntry().getSbn().getKey())) {
                             endMotion();
+                            setTrackingHeadsUp(false);
                             return true;
                         }
                     }
                     endMotion();
+                    setTrackingHeadsUp(false);
                     return false;
             }
             return false;
@@ -258,7 +261,7 @@
         void setHeadsUpDraggingStartingHeight(int startHeight);
 
         /** Sets notification that is being expanded. */
-        void setTrackedHeadsUp(ExpandableNotificationRow expandableNotificationRow);
+        void setTrackedHeadsUp(@Nullable ExpandableNotificationRow expandableNotificationRow);
 
         /** Called when a MotionEvent is about to trigger expansion. */
         void startExpand(float newX, float newY, boolean startTracking, float expandedHeight);
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 1568e9e..d383bee 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
@@ -2920,7 +2920,11 @@
         if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
                 && !mChildrenContainer.showingAsLowPriority()) {
             final boolean wasExpanded = isGroupExpanded();
-            mGroupExpansionManager.setGroupExpanded(mEntry, userExpanded);
+            if (NotificationBundleUi.isEnabled()) {
+                mGroupExpansionManager.setGroupExpanded(mEntryAdapter, userExpanded);
+            } else {
+                mGroupExpansionManager.setGroupExpanded(mEntry, userExpanded);
+            }
             onExpansionChanged(true /* userAction */, wasExpanded);
             return;
         }
@@ -3399,7 +3403,11 @@
     public void makeActionsVisibile() {
         setUserExpanded(true, true);
         if (isChildInGroup()) {
-            mGroupExpansionManager.setGroupExpanded(mEntry, true);
+            if (NotificationBundleUi.isEnabled()) {
+                mGroupExpansionManager.setGroupExpanded(mEntryAdapter, true);
+            } else {
+                mGroupExpansionManager.setGroupExpanded(mEntry, true);
+            }
         }
         notifyHeightChanged(/* needsAnimation= */ false);
     }
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 3ee8273..c694a19 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
@@ -3644,6 +3644,9 @@
                     mScrollViewFields.sendCurrentGestureInGuts(false);
                     mScrollViewFields.sendCurrentGestureOverscroll(false);
                     setIsBeingDragged(false);
+                    // dispatch to touchHandlers, so they can still finalize a previously started
+                    // motion, while the shade is being dragged
+                    return super.dispatchTouchEvent(ev);
                 }
                 return false;
             }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt
index bfc5361..f04fc86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt
@@ -43,6 +43,7 @@
 import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.volume.domain.interactor.audioModeInteractor
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.MutableSharedFlow
@@ -146,6 +147,7 @@
                     )
                 ),
                 kosmos.audioSharingInteractor,
+                kosmos.audioModeInteractor,
                 kosmos.audioSharingButtonViewModelFactory,
                 bluetoothDeviceMetadataInteractor,
                 mDialogTransitionAnimator,
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 0aa5199..7c8822b 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,7 +18,6 @@
 
 import android.bluetooth.BluetoothDevice
 import android.graphics.drawable.Drawable
-import android.media.AudioManager
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.testing.TestableLooper
@@ -61,8 +60,6 @@
     private val connectedDeviceItemFactory = ConnectedDeviceItemFactory()
     private val savedDeviceItemFactory = SavedDeviceItemFactory()
 
-    private val audioManager = context.getSystemService(AudioManager::class.java)!!
-
     @Before
     fun setup() {
         mockitoSession =
@@ -132,7 +129,12 @@
     fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_flagOff_returnsFalse() {
         assertThat(
                 AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
-                    .isFilterMatched(context, cachedDevice, audioManager, false)
+                    .isFilterMatched(
+                        context,
+                        cachedDevice,
+                        isOngoingCall = false,
+                        audioSharingAvailable = false,
+                    )
             )
             .isFalse()
     }
@@ -143,7 +145,12 @@
 
         assertThat(
                 AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
-                    .isFilterMatched(context, cachedDevice, audioManager, true)
+                    .isFilterMatched(
+                        context,
+                        cachedDevice,
+                        isOngoingCall = false,
+                        audioSharingAvailable = true,
+                    )
             )
             .isFalse()
     }
@@ -157,7 +164,26 @@
 
         assertThat(
                 AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
-                    .isFilterMatched(context, cachedDevice, audioManager, true)
+                    .isFilterMatched(
+                        context,
+                        cachedDevice,
+                        isOngoingCall = false,
+                        audioSharingAvailable = true,
+                    )
+            )
+            .isFalse()
+    }
+
+    @Test
+    fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_inCall_false() {
+        assertThat(
+                AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
+                    .isFilterMatched(
+                        context,
+                        cachedDevice,
+                        isOngoingCall = true,
+                        audioSharingAvailable = true,
+                    )
             )
             .isFalse()
     }
@@ -171,7 +197,12 @@
 
         assertThat(
                 AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
-                    .isFilterMatched(context, cachedDevice, audioManager, true)
+                    .isFilterMatched(
+                        context,
+                        cachedDevice,
+                        isOngoingCall = false,
+                        audioSharingAvailable = true,
+                    )
             )
             .isTrue()
     }
@@ -182,7 +213,9 @@
         `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
         `when`(cachedDevice.isConnected).thenReturn(false)
 
-        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
+            )
             .isTrue()
     }
 
@@ -192,7 +225,9 @@
         `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
         `when`(cachedDevice.isConnected).thenReturn(true)
 
-        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
+            )
             .isFalse()
     }
 
@@ -201,7 +236,9 @@
     fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() {
         `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
 
-        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
+            )
             .isFalse()
     }
 
@@ -211,7 +248,9 @@
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true)
 
-        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
+            )
             .isFalse()
     }
 
@@ -223,7 +262,9 @@
         `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
         `when`(cachedDevice.isConnected).thenReturn(false)
 
-        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
+            )
             .isTrue()
     }
 
@@ -235,7 +276,9 @@
         `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
         `when`(cachedDevice.isConnected).thenReturn(true)
 
-        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
+            )
             .isFalse()
     }
 
@@ -244,14 +287,26 @@
     fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() {
         `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(true)
 
-        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        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, audioManager))
+        assertThat(
+                connectedDeviceItemFactory.isFilterMatched(
+                    context,
+                    cachedDevice,
+                    isOngoingCall = false,
+                )
+            )
             .isFalse()
     }
 
@@ -261,7 +316,13 @@
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true)
 
-        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                connectedDeviceItemFactory.isFilterMatched(
+                    context,
+                    cachedDevice,
+                    isOngoingCall = false,
+                )
+            )
             .isFalse()
     }
 
@@ -272,7 +333,13 @@
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
         `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(true)
 
-        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                connectedDeviceItemFactory.isFilterMatched(
+                    context,
+                    cachedDevice,
+                    isOngoingCall = false,
+                )
+            )
             .isTrue()
     }
 
@@ -283,7 +350,13 @@
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
         `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(false)
 
-        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+        assertThat(
+                connectedDeviceItemFactory.isFilterMatched(
+                    context,
+                    cachedDevice,
+                    isOngoingCall = false,
+                )
+            )
             .isFalse()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
index 42dc50d..943b89a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.testKosmos
 import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.volume.domain.interactor.audioModeInteractor
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.test.TestScope
@@ -102,7 +103,6 @@
                 DeviceItemInteractor(
                     bluetoothTileDialogRepository,
                     kosmos.audioSharingInteractor,
-                    audioManager,
                     adapter,
                     localBluetoothManager,
                     fakeSystemClock,
@@ -111,6 +111,7 @@
                     emptyList(),
                     testScope.backgroundScope,
                     dispatcher,
+                    kosmos.audioModeInteractor,
                 )
 
             val latest by collectLastValue(interactor.deviceItemUpdate)
@@ -130,7 +131,6 @@
                 DeviceItemInteractor(
                     bluetoothTileDialogRepository,
                     kosmos.audioSharingInteractor,
-                    audioManager,
                     adapter,
                     localBluetoothManager,
                     fakeSystemClock,
@@ -139,6 +139,7 @@
                     emptyList(),
                     testScope.backgroundScope,
                     dispatcher,
+                    kosmos.audioModeInteractor,
                 )
 
             val latest by collectLastValue(interactor.deviceItemUpdate)
@@ -158,7 +159,6 @@
                 DeviceItemInteractor(
                     bluetoothTileDialogRepository,
                     kosmos.audioSharingInteractor,
-                    audioManager,
                     adapter,
                     localBluetoothManager,
                     fakeSystemClock,
@@ -167,6 +167,7 @@
                     emptyList(),
                     testScope.backgroundScope,
                     dispatcher,
+                    kosmos.audioModeInteractor,
                 )
 
             val latest by collectLastValue(interactor.deviceItemUpdate)
@@ -186,7 +187,6 @@
                 DeviceItemInteractor(
                     bluetoothTileDialogRepository,
                     kosmos.audioSharingInteractor,
-                    audioManager,
                     adapter,
                     localBluetoothManager,
                     fakeSystemClock,
@@ -198,6 +198,7 @@
                     emptyList(),
                     testScope.backgroundScope,
                     dispatcher,
+                    kosmos.audioModeInteractor,
                 )
 
             val latest by collectLastValue(interactor.deviceItemUpdate)
@@ -217,7 +218,6 @@
                 DeviceItemInteractor(
                     bluetoothTileDialogRepository,
                     kosmos.audioSharingInteractor,
-                    audioManager,
                     adapter,
                     localBluetoothManager,
                     fakeSystemClock,
@@ -238,6 +238,7 @@
                     ),
                     testScope.backgroundScope,
                     dispatcher,
+                    kosmos.audioModeInteractor,
                 )
             `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
             `when`(deviceItem2.type).thenReturn(DeviceItemType.SAVED_BLUETOOTH_DEVICE)
@@ -259,7 +260,6 @@
                 DeviceItemInteractor(
                     bluetoothTileDialogRepository,
                     kosmos.audioSharingInteractor,
-                    audioManager,
                     adapter,
                     localBluetoothManager,
                     fakeSystemClock,
@@ -277,6 +277,7 @@
                     listOf(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE),
                     testScope.backgroundScope,
                     dispatcher,
+                    kosmos.audioModeInteractor,
                 )
             `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
             `when`(deviceItem2.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
@@ -300,7 +301,6 @@
                 DeviceItemInteractor(
                     bluetoothTileDialogRepository,
                     kosmos.audioSharingInteractor,
-                    audioManager,
                     adapter,
                     localBluetoothManager,
                     fakeSystemClock,
@@ -309,6 +309,7 @@
                     emptyList(),
                     testScope.backgroundScope,
                     dispatcher,
+                    kosmos.audioModeInteractor,
                 )
             val latest by collectLastValue(interactor.deviceItemUpdate)
             val latestShowSeeAll by collectLastValue(interactor.showSeeAllUpdate)
@@ -327,7 +328,7 @@
             override fun isFilterMatched(
                 context: Context,
                 cachedDevice: CachedBluetoothDevice,
-                audioManager: AudioManager,
+                isOngoingCall: Boolean,
                 audioSharingAvailable: Boolean,
             ) = isFilterMatchFunc(cachedDevice)
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d4bb1d5..258c955 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -812,7 +812,7 @@
             handleMinimalPostProcessingAllowedSettingChange();
 
             if (mFlags.isDisplayContentModeManagementEnabled()) {
-                updateMirrorBuiltInDisplaySettingLocked();
+                updateMirrorBuiltInDisplaySettingLocked(/*shouldSendDisplayChangeEvent=*/ true);
             }
 
             final UserManager userManager = getUserManager();
@@ -868,7 +868,7 @@
                 updateHdrConversionModeSettingsLocked();
             }
             if (mFlags.isDisplayContentModeManagementEnabled()) {
-                updateMirrorBuiltInDisplaySettingLocked();
+                updateMirrorBuiltInDisplaySettingLocked(/*shouldSendDisplayChangeEvent=*/ false);
             }
         }
 
@@ -1237,8 +1237,11 @@
             }
 
             if (Settings.Secure.getUriFor(MIRROR_BUILT_IN_DISPLAY).equals(uri)) {
-                if (mFlags.isDisplayContentModeManagementEnabled()) {
-                    updateMirrorBuiltInDisplaySettingLocked();
+                synchronized (mSyncRoot) {
+                    if (mFlags.isDisplayContentModeManagementEnabled()) {
+                        updateMirrorBuiltInDisplaySettingLocked(/*shouldSendDisplayChangeEvent=*/
+                                true);
+                    }
                 }
                 return;
             }
@@ -1258,18 +1261,19 @@
                 1, UserHandle.USER_CURRENT) != 0);
     }
 
-    private void updateMirrorBuiltInDisplaySettingLocked() {
-        synchronized (mSyncRoot) {
-            ContentResolver resolver = mContext.getContentResolver();
-            final boolean mirrorBuiltInDisplay = Settings.Secure.getIntForUser(resolver,
-                    MIRROR_BUILT_IN_DISPLAY, 0, UserHandle.USER_CURRENT) != 0;
-            if (mMirrorBuiltInDisplay == mirrorBuiltInDisplay) {
-                return;
-            }
-            mMirrorBuiltInDisplay = mirrorBuiltInDisplay;
-            if (mFlags.isDisplayContentModeManagementEnabled()) {
-                mLogicalDisplayMapper.forEachLocked(this::updateCanHostTasksIfNeededLocked);
-            }
+    private void updateMirrorBuiltInDisplaySettingLocked(boolean shouldSendDisplayChangeEvent) {
+        ContentResolver resolver = mContext.getContentResolver();
+        final boolean mirrorBuiltInDisplay = Settings.Secure.getIntForUser(resolver,
+                MIRROR_BUILT_IN_DISPLAY, 0, UserHandle.USER_CURRENT) != 0;
+        if (mMirrorBuiltInDisplay == mirrorBuiltInDisplay) {
+            return;
+        }
+        mMirrorBuiltInDisplay = mirrorBuiltInDisplay;
+        if (mFlags.isDisplayContentModeManagementEnabled()) {
+            mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
+                    updateCanHostTasksIfNeededLocked(logicalDisplay,
+                            shouldSendDisplayChangeEvent);
+            });
         }
     }
 
@@ -2380,7 +2384,7 @@
                 new BrightnessPair(brightnessDefault, brightnessDefault));
 
         if (mFlags.isDisplayContentModeManagementEnabled()) {
-            updateCanHostTasksIfNeededLocked(display);
+            updateCanHostTasksIfNeededLocked(display, /*shouldSendDisplayChangeEvent=*/ false);
         }
 
         DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -2703,8 +2707,9 @@
         }
     }
 
-    private void updateCanHostTasksIfNeededLocked(LogicalDisplay display) {
-        if (display.setCanHostTasksLocked(!mMirrorBuiltInDisplay)) {
+    private void updateCanHostTasksIfNeededLocked(LogicalDisplay display,
+            boolean shouldSendDisplayChangeEvent) {
+        if (display.setCanHostTasksLocked(!mMirrorBuiltInDisplay) && shouldSendDisplayChangeEvent) {
             sendDisplayEventIfEnabledLocked(display,
                     DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED);
         }
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 6cc17d4..a941838 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -857,8 +857,7 @@
         info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);
         info.mIsDrawn = true;
         final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
-        if (info.mLoggedTransitionStarting || (!r.mDisplayContent.mOpeningApps.contains(r)
-                && !r.mTransitionController.isCollecting(r))) {
+        if (info.mLoggedTransitionStarting || !r.mTransitionController.isCollecting(r)) {
             done(false /* abort */, info, "notifyWindowsDrawn", timestampNs);
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c37b5a0..333d91a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -159,7 +159,6 @@
 import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
 import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
 import static com.android.server.wm.ActivityRecordProto.IS_USER_FULLSCREEN_OVERRIDE_ENABLED;
-import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
 import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
 import static com.android.server.wm.ActivityRecordProto.LAST_DROP_INPUT_MODE;
 import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING;
@@ -330,7 +329,6 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowInsets;
-import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.TransitionOldType;
@@ -1519,17 +1517,7 @@
         this.task = newTask;
 
         if (shouldStartChangeTransition(newParent, oldParent)) {
-            if (mTransitionController.isShellTransitionsEnabled()) {
-                // For Shell transition, call #initializeChangeTransition directly to take the
-                // screenshot at the Activity level. And Shell will be in charge of handling the
-                // surface reparent and crop.
-                initializeChangeTransition(getBounds());
-            } else {
-                // For legacy app transition, we want to take a screenshot of the Activity surface,
-                // but animate the change transition on TaskFragment level to get the correct window
-                // crop.
-                newParent.initializeChangeTransition(getBounds(), getSurfaceControl());
-            }
+            mTransitionController.collectVisibleChange(this);
         }
 
         super.onParentChanged(newParent, oldParent);
@@ -1557,16 +1545,6 @@
             mLastReportedPictureInPictureMode = inPinnedWindowingMode();
         }
 
-        // When the associated task is {@code null}, the {@link ActivityRecord} can no longer
-        // access visual elements like the {@link DisplayContent}. We must remove any associations
-        // such as animations.
-        if (task == null) {
-            // It is possible we have been marked as a closing app earlier. We must remove ourselves
-            // from this list so we do not participate in any future animations.
-            if (getDisplayContent() != null) {
-                getDisplayContent().mClosingApps.remove(this);
-            }
-        }
         final Task rootTask = getRootTask();
         if (task == mLastParentBeforePip && task != null) {
             // Notify the TaskFragmentOrganizer that the activity is reparented back from pip.
@@ -1749,14 +1727,6 @@
             return;
         }
         prevDc.onRunningActivityChanged();
-
-        if (prevDc.mOpeningApps.remove(this)) {
-            // Transfer opening transition to new display.
-            mDisplayContent.mOpeningApps.add(this);
-            mDisplayContent.executeAppTransition();
-        }
-
-        prevDc.mClosingApps.remove(this);
         prevDc.getDisplayPolicy().removeRelaunchingApp(this);
 
         if (prevDc.mFocusedApp == this) {
@@ -4392,7 +4362,6 @@
 
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app token: %s", this);
 
-        getDisplayContent().mOpeningApps.remove(this);
         getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
         mWmService.mSnapshotController.onAppRemoved(this);
         mAtmService.mStartingProcessActivities.remove(this);
@@ -4404,20 +4373,9 @@
         mAppCompatController.getTransparentPolicy().stop();
 
         // Defer removal of this activity when either a child is animating, or app transition is on
-        // going. App transition animation might be applied on the parent task not on the activity,
-        // but the actual frame buffer is associated with the activity, so we have to keep the
-        // activity while a parent is animating.
-        boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN,
-                ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION);
-        if (getDisplayContent().mClosingApps.contains(this)) {
-            delayed = true;
-        } else if (getDisplayContent().mAppTransition.isTransitionSet()) {
-            getDisplayContent().mClosingApps.add(this);
-            delayed = true;
-        } else if (mTransitionController.inTransition()) {
-            delayed = true;
-        }
-
+        // going. The handleCompleteDeferredRemoval will continue the removal.
+        final boolean delayed = isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION)
+                || mTransitionController.inTransition();
         // Don't commit visibility if it is waiting to animate. It will be set post animation.
         if (!delayed) {
             commitVisibility(false /* visible */, true /* performLayout */);
@@ -5552,9 +5510,6 @@
 
         mAtmService.mBackNavigationController.onAppVisibilityChanged(this, visible);
 
-        final DisplayContent displayContent = getDisplayContent();
-        displayContent.mOpeningApps.remove(this);
-        displayContent.mClosingApps.remove(this);
         setVisibleRequested(visible);
         mLastDeferHidingClient = deferHidingClient;
 
@@ -5567,13 +5522,6 @@
                 setClientVisible(false);
             }
         } else {
-            if (!appTransition.isTransitionSet()
-                    && appTransition.isReady()) {
-                // Add the app mOpeningApps if transition is unset but ready. This means
-                // we're doing a screen freeze, and the unfreeze will wait for all opening
-                // apps to be ready.
-                displayContent.mOpeningApps.add(this);
-            }
             startingMoved = false;
             // If the token is currently hidden (should be the common case), or has been
             // stopped, then we need to set up to wait for its windows to be ready.
@@ -6775,7 +6723,7 @@
         setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
 
         // We can now show all of the drawn windows!
-        if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) {
+        if (canShowWindows()) {
             showAllWindowsLocked();
         }
     }
@@ -7449,15 +7397,6 @@
         return boundsLayer;
     }
 
-    @Override
-    boolean isWaitingForTransitionStart() {
-        final DisplayContent dc = getDisplayContent();
-        return dc != null && dc.mAppTransition.isTransitionSet()
-                && (dc.mOpeningApps.contains(this)
-                || dc.mClosingApps.contains(this)
-                || dc.mChangingContainers.contains(this));
-    }
-
     boolean isTransitionForward() {
         return (mStartingData != null && mStartingData.mIsTransitionForward)
                 || mDisplayContent.isNextTransitionForward();
@@ -9561,7 +9500,6 @@
         writeNameToProto(proto, NAME);
         super.dumpDebug(proto, WINDOW_TOKEN, logLevel);
         proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
-        proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
         proto.write(IS_ANIMATING, isAnimating(TRANSITION | PARENTS | CHILDREN,
                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION));
         proto.write(FILLS_PARENT, fillsParent());
diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
index dff072e..57811e2 100644
--- a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
@@ -16,12 +16,14 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.window.DesktopModeFlags.EXCLUDE_CAPTION_FROM_APP_BOUNDS;
 
 import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
 import static com.android.server.wm.AppCompatConfiguration.letterboxBackgroundTypeToString;
@@ -48,6 +50,8 @@
  */
 class AppCompatLetterboxPolicy {
 
+    private static final int DIFF_TOLERANCE_PX = 1;
+
     @NonNull
     private final ActivityRecord mActivityRecord;
     @NonNull
@@ -56,6 +60,9 @@
     private final AppCompatRoundedCorners mAppCompatRoundedCorners;
     @NonNull
     private final AppCompatConfiguration mAppCompatConfiguration;
+    // Convenience temporary object to save allocation when calculating Rect.
+    @NonNull
+    private final Rect mTmpRect = new Rect();
 
     private boolean mLastShouldShowLetterboxUi;
 
@@ -71,7 +78,7 @@
                 : new LegacyLetterboxPolicyState();
         // TODO (b/358334569) Improve cutout logic dependency on app compat.
         mAppCompatRoundedCorners = new AppCompatRoundedCorners(mActivityRecord,
-                this::isLetterboxedNotForDisplayCutout);
+                this::ieEligibleForRoundedCorners);
         mAppCompatConfiguration = appCompatConfiguration;
     }
 
@@ -84,7 +91,7 @@
         mLetterboxPolicyState.stop();
     }
 
-    /** @return {@value true} if the letterbox policy is running and the activity letterboxed. */
+    /** @return {@code true} if the letterbox policy is running and the activity letterboxed. */
     boolean isRunning() {
         return mLetterboxPolicyState.isRunning();
     }
@@ -130,7 +137,7 @@
      *     <li>The activity is in fullscreen.
      *     <li>The activity is portrait-only.
      *     <li>The activity doesn't have a starting window (education should only be displayed
-     *     once the starting window is removed in {@link #removeStartingWindow}).
+     *     once the starting window is removed in {@link ActivityRecord#removeStartingWindow}).
      * </ul>
      */
     boolean isEligibleForLetterboxEducation() {
@@ -294,16 +301,40 @@
         }
     }
 
+    private boolean ieEligibleForRoundedCorners(@NonNull WindowState mainWindow) {
+        return isLetterboxedNotForDisplayCutout(mainWindow)
+                && !isFreeformActivityMatchParentAppBoundsHeight();
+    }
+
     private boolean isLetterboxedNotForDisplayCutout(@NonNull WindowState mainWindow) {
         return shouldShowLetterboxUi(mainWindow)
                 && !mainWindow.isLetterboxedForDisplayCutout();
     }
 
+    private boolean isFreeformActivityMatchParentAppBoundsHeight() {
+        if (!EXCLUDE_CAPTION_FROM_APP_BOUNDS.isTrue()) {
+            return false;
+        }
+        final Task task = mActivityRecord.getTask();
+        if (task == null) {
+            return false;
+        }
+        final Rect parentAppBounds = task.getWindowConfiguration().getAppBounds();
+        if (parentAppBounds == null) {
+            return false;
+        }
+
+        mLetterboxPolicyState.getLetterboxInnerBounds(mTmpRect);
+        final int diff = parentAppBounds.height() - mTmpRect.height();
+        // Compare bounds with tolerance of 1 px to account for rounding error calculations.
+        return task.getWindowingMode() == WINDOWING_MODE_FREEFORM && diff <= DIFF_TOLERANCE_PX;
+    }
+
     private static boolean shouldNotLayoutLetterbox(@Nullable WindowState w) {
         if (w == null) {
             return true;
         }
-        final int type = w.mAttrs.type;
+        final int type = w.getAttrs().type;
         // Allow letterbox to be displayed early for base application or application starting
         // windows even if it is not on the top z order to prevent flickering when the
         // letterboxed window is brought to the top
diff --git a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
index 92d76e5..8165638 100644
--- a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
+++ b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
@@ -35,12 +35,12 @@
     @NonNull
     private final ActivityRecord mActivityRecord;
     @NonNull
-    private final Predicate<WindowState> mIsLetterboxedNotForDisplayCutout;
+    private final Predicate<WindowState> mRoundedCornersWindowCondition;
 
     AppCompatRoundedCorners(@NonNull ActivityRecord  activityRecord,
-            @NonNull Predicate<WindowState> isLetterboxedNotForDisplayCutout) {
+            @NonNull Predicate<WindowState> roundedCornersWindowCondition) {
         mActivityRecord = activityRecord;
-        mIsLetterboxedNotForDisplayCutout = isLetterboxedNotForDisplayCutout;
+        mRoundedCornersWindowCondition = roundedCornersWindowCondition;
     }
 
     void updateRoundedCornersIfNeeded(@NonNull final WindowState mainWindow) {
@@ -136,7 +136,7 @@
     private boolean requiresRoundedCorners(@NonNull final WindowState mainWindow) {
         final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord
                 .mAppCompatController.getLetterboxOverrides();
-        return mIsLetterboxedNotForDisplayCutout.test(mainWindow)
+        return mRoundedCornersWindowCondition.test(mainWindow)
                 && letterboxOverrides.isLetterboxActivityCornersRounded();
     }
 
diff --git a/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java b/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java
index 26cf32b..6a46f57 100644
--- a/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.wm;
 
+import static android.window.DesktopModeFlags.EXCLUDE_CAPTION_FROM_APP_BOUNDS;
+
 import static com.android.server.wm.AppCompatUtils.isInDesktopMode;
 
 import android.annotation.NonNull;
@@ -22,8 +24,6 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 
-import com.android.window.flags.Flags;
-
 /**
  * Encapsulate logic related to sandboxing for app compatibility.
  */
@@ -48,7 +48,7 @@
      */
     void sandboxBoundsIfNeeded(@NonNull Configuration resolvedConfig,
             @WindowingMode int windowingMode) {
-        if (!Flags.excludeCaptionFromAppBounds()) {
+        if (!EXCLUDE_CAPTION_FROM_APP_BOUNDS.isTrue()) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index d98ad8b..12d4a21 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -89,7 +89,6 @@
 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;
 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;
@@ -1554,26 +1553,6 @@
     }
 
     private void handleAppTransitionTimeout() {
-        synchronized (mService.mGlobalLock) {
-            final DisplayContent dc = mDisplayContent;
-            if (dc == null) {
-                return;
-            }
-            notifyAppTransitionTimeoutLocked();
-            if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()
-                    || !dc.mChangingContainers.isEmpty()) {
-                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
-                            "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b "
-                                    + "mOpeningApps.size()=%d mClosingApps.size()=%d "
-                                    + "mChangingApps.size()=%d",
-                            dc.getDisplayId(), dc.mAppTransition.isTransitionSet(),
-                            dc.mOpeningApps.size(), dc.mClosingApps.size(),
-                            dc.mChangingContainers.size());
-
-                setTimeout();
-                mService.mWindowPlacerLocked.performSurfacePlacement();
-            }
-        }
     }
 
     private static void doAnimationCallback(@NonNull IRemoteCallback callback) {
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 05dcbb7..aaa18ad 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -257,10 +257,12 @@
         // This should be the only place override the configuration for ActivityRecord. Override
         // the value if not calculated yet.
         Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+        Rect outConfigBounds = new Rect(outAppBounds);
         if (outAppBounds == null || outAppBounds.isEmpty()) {
             inOutConfig.windowConfiguration.setAppBounds(
                     newParentConfiguration.windowConfiguration.getBounds());
             outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+            outConfigBounds.set(outAppBounds);
             if (task != null) {
                 task = task.getCreatedByOrganizerTask();
                 if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) {
@@ -279,6 +281,12 @@
                     outAppBounds.inset(decor.mOverrideNonDecorInsets);
                 }
             }
+            if (!outConfigBounds.intersect(decor.mOverrideConfigFrame)) {
+                if (inOutConfig.windowConfiguration.getWindowingMode()
+                        == WINDOWING_MODE_MULTI_WINDOW) {
+                    outAppBounds.inset(decor.mOverrideConfigInsets);
+                }
+            }
             if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) {
                 outAppBounds.offset(-task.mOffsetXForInsets, -task.mOffsetYForInsets);
             }
@@ -289,10 +297,10 @@
         }
         density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
         if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
-            inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
+            inOutConfig.screenWidthDp = (int) (outConfigBounds.width() / density + 0.5f);
         }
         if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-            inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
+            inOutConfig.screenHeightDp = (int) (outConfigBounds.height() / density + 0.5f);
         }
         if (inOutConfig.smallestScreenWidthDp == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
                 && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 703ce7d..7eebbba 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -108,7 +108,6 @@
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
 import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
-import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
 import static com.android.server.wm.DisplayContentProto.CURRENT_FOCUS;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
@@ -125,7 +124,6 @@
 import static com.android.server.wm.DisplayContentProto.IS_SLEEPING;
 import static com.android.server.wm.DisplayContentProto.KEEP_CLEAR_AREAS;
 import static com.android.server.wm.DisplayContentProto.MIN_SIZE_OF_RESIZEABLE_TASK_DP;
-import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
 import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
 import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
 import static com.android.server.wm.DisplayContentProto.SLEEP_TOKENS;
@@ -164,6 +162,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.content.ComponentCallbacks;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -196,7 +195,6 @@
 import android.os.UserManager;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.DisplayUtils;
@@ -367,15 +365,7 @@
 
     final AppTransition mAppTransition;
 
-    final ArraySet<ActivityRecord> mOpeningApps = new ArraySet<>();
-    final ArraySet<ActivityRecord> mClosingApps = new ArraySet<>();
-    final ArraySet<WindowContainer> mChangingContainers = new ArraySet<>();
     final UnknownAppVisibilityController mUnknownAppVisibilityController;
-    /**
-     * If a container is closing when resizing, keeps track of its starting bounds when it is
-     * removed from {@link #mChangingContainers}.
-     */
-    final ArrayMap<WindowContainer, Rect> mClosingChangingContainers = new ArrayMap<>();
 
     private MetricsLogger mMetricsLogger;
 
@@ -467,6 +457,7 @@
     private DisplayInfo mLastDisplayInfoOverride;
 
     private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+    @NonNull
     private final DisplayPolicy mDisplayPolicy;
     private final DisplayRotation mDisplayRotation;
 
@@ -553,6 +544,7 @@
     /** Remove this display when animation on it has completed. */
     private boolean mDeferredRemoval;
 
+    @NonNull
     final PinnedTaskController mPinnedTaskController;
 
     private final LinkedList<ActivityRecord> mTmpUpdateAllDrawn = new LinkedList();
@@ -1113,6 +1105,29 @@
     };
 
     /**
+     * Called to update fields retrieve from {@link #getDisplayUiContext()} resources when
+     * there's a configuration update on {@link #getDisplayUiContext()}.
+     */
+    @NonNull
+    private final ComponentCallbacks mSysUiContextConfigCallback = new ComponentCallbacks() {
+
+        @Override
+        public void onConfigurationChanged(@NonNull Configuration newConfig) {
+            synchronized (mWmService.mGlobalLock) {
+                if (mDisplayReady) {
+                    mDisplayPolicy.onConfigurationChanged();
+                    mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
+                }
+            }
+        }
+
+        @Override
+        public void onLowMemory() {
+            // Do nothing.
+        }
+    };
+
+    /**
      * Create new {@link DisplayContent} instance, add itself to the root window container and
      * initialize direct children.
      * @param display May not be null.
@@ -1910,17 +1925,10 @@
             return false;
         }
         if (checkOpening) {
-            if (mTransitionController.isShellTransitionsEnabled()) {
-                if (!mTransitionController.isCollecting(r)) {
-                    return false;
-                }
-            } else {
-                if (!mAppTransition.isTransitionSet() || !mOpeningApps.contains(r)) {
-                    // Apply normal rotation animation in case of the activity set different
-                    // requested orientation without activity switch, or the transition is unset due
-                    // to starting window was transferred ({@link #mSkipAppTransitionAnimation}).
-                    return false;
-                }
+            if (!mTransitionController.isCollecting(r)) {
+                // Apply normal rotation animation in case the activity changes requested
+                // orientation without activity switch.
+                return false;
             }
             if (r.isState(RESUMED) && !r.getTask().mInResumeTopActivity) {
                 // If the activity is executing or has done the lifecycle callback, use normal
@@ -2815,11 +2823,10 @@
         final int lastOrientation = getConfiguration().orientation;
         final int lastWindowingMode = getWindowingMode();
         super.onConfigurationChanged(newParentConfig);
-        if (mDisplayPolicy != null) {
-            mDisplayPolicy.onConfigurationChanged();
-            mPinnedTaskController.onPostDisplayConfigurationChanged();
-            mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
+        if (!Flags.trackSystemUiContextBeforeWms()) {
+            mSysUiContextConfigCallback.onConfigurationChanged(newParentConfig);
         }
+        mPinnedTaskController.onPostDisplayConfigurationChanged();
         // Update IME parent if needed.
         updateImeParent();
 
@@ -3256,7 +3263,12 @@
         }
     }
 
-    private boolean allowContentModeSwitch() {
+     /**
+      * 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.
+      */
+     boolean allowContentModeSwitch() {
         // The default display should always show system decorations.
         if (isDefaultDisplay) {
             return false;
@@ -3372,10 +3384,6 @@
     void removeImmediately() {
         mDeferredRemoval = false;
         try {
-            // Clear all transitions & screen frozen states when removing display.
-            mOpeningApps.clear();
-            mClosingApps.clear();
-            mChangingContainers.clear();
             mUnknownAppVisibilityController.clear();
             mAppTransition.removeAppTransitionTimeoutCallbacks();
             mTransitionController.unregisterLegacyListener(mFixedRotationTransitionListener);
@@ -3398,6 +3406,9 @@
                     .getKeyguardController().onDisplayRemoved(mDisplayId);
             mWallpaperController.resetLargestDisplay(mDisplay);
             mWmService.mDisplayWindowSettings.onDisplayRemoved(this);
+            if (Flags.trackSystemUiContextBeforeWms()) {
+                getDisplayUiContext().unregisterComponentCallbacks(mSysUiContextConfigCallback);
+            }
         } finally {
             mDisplayReady = false;
         }
@@ -3567,12 +3578,6 @@
         if (mFocusedApp != null) {
             mFocusedApp.writeNameToProto(proto, FOCUSED_APP);
         }
-        for (int i = mOpeningApps.size() - 1; i >= 0; i--) {
-            mOpeningApps.valueAt(i).writeIdentifierToProto(proto, OPENING_APPS);
-        }
-        for (int i = mClosingApps.size() - 1; i >= 0; i--) {
-            mClosingApps.valueAt(i).writeIdentifierToProto(proto, CLOSING_APPS);
-        }
 
         final Task focusedRootTask = getFocusedRootTask();
         if (focusedRootTask != null) {
@@ -4831,19 +4836,6 @@
             }
         }
 
-        if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingContainers.isEmpty()) {
-            pw.println();
-            if (mOpeningApps.size() > 0) {
-                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
-            }
-            if (mClosingApps.size() > 0) {
-                pw.print("  mClosingApps="); pw.println(mClosingApps);
-            }
-            if (mChangingContainers.size() > 0) {
-                pw.print("  mChangingApps="); pw.println(mChangingContainers);
-            }
-        }
-
         mUnknownAppVisibilityController.dump(pw, "  ");
     }
 
@@ -5465,7 +5457,7 @@
             reconfigureDisplayLocked();
             onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
             mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
-            // Attach the SystemUiContext to this DisplayContent the get latest configuration.
+            // Attach the SystemUiContext to this DisplayContent to get latest configuration.
             // Note that the SystemUiContext will be removed automatically if this DisplayContent
             // is detached.
             registerSystemUiContext();
@@ -5473,11 +5465,15 @@
     }
 
     private void registerSystemUiContext() {
+        final Context systemUiContext = getDisplayUiContext();
         final WindowProcessController wpc = mAtmService.getProcessController(
-                getDisplayUiContext().getIApplicationThread());
+                systemUiContext.getIApplicationThread());
         mWmService.mWindowContextListenerController.registerWindowContainerListener(
-                wpc, getDisplayUiContext().getWindowContextToken(), this,
+                wpc, systemUiContext.getWindowContextToken(), this,
                 INVALID_WINDOW_TYPE, null /* options */);
+        if (Flags.trackSystemUiContextBeforeWms()) {
+            systemUiContext.registerComponentCallbacks(mSysUiContextConfigCallback);
+        }
     }
 
     @Override
@@ -6656,6 +6652,7 @@
         forAllTasks((t) -> { t.getRootTask().removeChild(t, "removeAllTasks"); });
     }
 
+    @NonNull
     Context getDisplayUiContext() {
         return mDisplayPolicy.getSystemUiContext();
     }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 10f591c..fbe8501 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1865,6 +1865,7 @@
         return mContext;
     }
 
+    @NonNull
     Context getSystemUiContext() {
         return mUiContext;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 539fc12..1173875 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -247,12 +247,7 @@
 
     void setShouldShowSystemDecorsLocked(@NonNull DisplayContent dc, boolean shouldShow) {
         final boolean changed = (shouldShow != shouldShowSystemDecorsLocked(dc));
-
-        final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final SettingsProvider.SettingsEntry overrideSettings =
-                mSettingsProvider.getOverrideSettings(displayInfo);
-        overrideSettings.mShouldShowSystemDecors = shouldShow;
-        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
+        setShouldShowSystemDecorsInternalLocked(dc, shouldShow);
 
         if (enableDisplayContentModeManagement()) {
             if (dc.isDefaultDisplay || dc.isPrivate() || !changed) {
@@ -269,6 +264,15 @@
         }
     }
 
+     void setShouldShowSystemDecorsInternalLocked(@NonNull DisplayContent dc,
+            boolean shouldShow) {
+        final DisplayInfo displayInfo = dc.getDisplayInfo();
+        final SettingsProvider.SettingsEntry overrideSettings =
+                mSettingsProvider.getOverrideSettings(displayInfo);
+        overrideSettings.mShouldShowSystemDecors = shouldShow;
+        mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
+    }
+
     boolean isHomeSupportedLocked(@NonNull DisplayContent dc) {
         if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
             // Default display should show home.
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c93efd3..40f16c1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2775,6 +2775,12 @@
                 return;
             }
 
+            if (enableDisplayContentModeManagement() && display.allowContentModeSwitch()) {
+                mWindowManager.mDisplayWindowSettings
+                        .setShouldShowSystemDecorsInternalLocked(display,
+                                display.mDisplay.canHostTasks());
+            }
+
             startSystemDecorations(display, "displayAdded");
 
             // Drop any cached DisplayInfos associated with this display id - the values are now
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index bf9883c76..6b3499a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2028,7 +2028,7 @@
         }
 
         if (shouldStartChangeTransition(prevWinMode, mTmpPrevBounds)) {
-            initializeChangeTransition(mTmpPrevBounds);
+            mTransitionController.collectVisibleChange(this);
         }
 
         // If the configuration supports persistent bounds (eg. Freeform), keep track of the
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 74059c1..a698a9e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2779,9 +2779,7 @@
         }
 
         // If this TaskFragment is closing while resizing, crop to the starting bounds instead.
-        final Rect bounds = isClosingWhenResizing()
-                ? mDisplayContent.mClosingChangingContainers.get(this)
-                : getBounds();
+        final Rect bounds = getBounds();
         final int width = bounds.width();
         final int height = bounds.height();
         if (!forceUpdate && width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index c1ef208..a8b9fed 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -292,12 +292,6 @@
         return false;
     }
 
-    boolean isWallpaperTargetAnimating() {
-        return mWallpaperTarget != null && mWallpaperTarget.isAnimating(TRANSITION | PARENTS)
-                && (mWallpaperTarget.mActivityRecord == null
-                        || !mWallpaperTarget.mActivityRecord.isWaitingForTransitionStart());
-    }
-
     void hideDeferredWallpapersIfNeededLegacy() {
         for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(i);
@@ -837,14 +831,6 @@
             // Use the old target if new target is hidden but old target
             // is not. If they're both hidden, still use the new target.
             mWallpaperTarget = prevWallpaperTarget;
-        } else if (newTargetHidden == oldTargetHidden
-                && !mDisplayContent.mOpeningApps.contains(wallpaperTarget.mActivityRecord)
-                && (mDisplayContent.mOpeningApps.contains(prevWallpaperTarget.mActivityRecord)
-                || mDisplayContent.mClosingApps.contains(prevWallpaperTarget.mActivityRecord))) {
-            // If they're both hidden (or both not hidden), prefer the one that's currently in
-            // opening or closing app list, this allows transition selection logic to better
-            // determine the wallpaper status of opening/closing apps.
-            mWallpaperTarget = prevWallpaperTarget;
         }
 
         result.setWallpaperTarget(wallpaperTarget);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 95cdf46..45202a2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -34,7 +34,6 @@
 import static android.view.SurfaceControl.Transaction;
 import static android.view.WindowInsets.Type.InsetsType;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
-import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR;
 import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
 
@@ -901,10 +900,6 @@
      */
     @CallSuper
     void removeImmediately() {
-        final DisplayContent dc = getDisplayContent();
-        if (dc != null) {
-            dc.mClosingChangingContainers.remove(this);
-        }
         while (!mChildren.isEmpty()) {
             final E child = mChildren.getLast();
             child.removeImmediately();
@@ -1116,10 +1111,6 @@
             if (asWindowState() == null) {
                 mTransitionController.collect(this);
             }
-            // Cancel any change transition queued-up for this container on the old display when
-            // this container is moved from the old display.
-            mDisplayContent.mClosingChangingContainers.remove(this);
-            mDisplayContent.mChangingContainers.remove(this);
         }
         mDisplayContent = dc;
         if (dc != null && dc != this && mPendingTransaction != null) {
@@ -1268,14 +1259,6 @@
     }
 
     /**
-     * @return {@code true} when the container is waiting the app transition start, {@code false}
-     *         otherwise.
-     */
-    boolean isWaitingForTransitionStart() {
-        return false;
-    }
-
-    /**
      * @return {@code true} if in this subtree of the hierarchy we have an
      *         {@code ActivityRecord#isAnimating(TRANSITION)}, {@code false} otherwise.
      */
@@ -1302,13 +1285,6 @@
         return isAnimating(0 /* self only */);
     }
 
-    /**
-     * @return {@code true} if the container is in changing app transition.
-     */
-    boolean isChangingAppTransition() {
-        return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this);
-    }
-
     boolean inTransition() {
         return mTransitionController.inTransition(this);
     }
@@ -1427,12 +1403,6 @@
         return setVisibleRequested(newVisReq);
     }
 
-    /** Whether this window is closing while resizing. */
-    boolean isClosingWhenResizing() {
-        return mDisplayContent != null
-                && mDisplayContent.mClosingChangingContainers.containsKey(this);
-    }
-
     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
@@ -3044,36 +3014,6 @@
                 || (getParent() != null && getParent().inPinnedWindowingMode());
     }
 
-    /**
-     * Initializes a change transition.
-     *
-     * For now, this will only be called for the following cases:
-     * 1. {@link Task} is changing windowing mode between fullscreen and freeform.
-     * 2. {@link TaskFragment} is organized and is changing window bounds.
-     * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}. (The
-     *    transition will happen on the {@link TaskFragment} for this case).
-     *
-     * This shouldn't be called on other {@link WindowContainer} unless there is a valid
-     * use case.
-     *
-     * @param startBounds The original bounds (on screen) of the surface we are snapshotting.
-     */
-    void initializeChangeTransition(Rect startBounds, @Nullable SurfaceControl freezeTarget) {
-        if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
-            mDisplayContent.mTransitionController.collectVisibleChange(this);
-            return;
-        }
-        mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
-        mDisplayContent.mChangingContainers.add(this);
-        // Calculate the relative position in parent container.
-        final Rect parentBounds = getParent().getBounds();
-        mTmpPoint.set(startBounds.left - parentBounds.left, startBounds.top - parentBounds.top);
-    }
-
-    void initializeChangeTransition(Rect startBounds) {
-        initializeChangeTransition(startBounds, null /* freezeTarget */);
-    }
-
     ArraySet<WindowContainer> getAnimationSources() {
         return mSurfaceAnimationSources;
     }
@@ -3166,8 +3106,7 @@
         getAnimationPosition(mTmpPoint);
         mTmpRect.offsetTo(0, 0);
 
-        final boolean isChanging = AppTransition.isChangeTransitOld(transit) && enter
-                && isChangingAppTransition();
+        final boolean isChanging = AppTransition.isChangeTransitOld(transit);
 
         if (isChanging) {
             final float durationScale = mWmService.getTransitionAnimationScaleLocked();
@@ -3519,9 +3458,6 @@
                 && (mSurfaceAnimator.getAnimationType() & typesToCheck) > 0) {
             return true;
         }
-        if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) {
-            return true;
-        }
         return false;
     }
 
@@ -3603,13 +3539,7 @@
             return;
         }
 
-        if (isClosingWhenResizing()) {
-            // This container is closing while resizing, keep its surface at the starting position
-            // to prevent animation flicker.
-            getRelativePosition(mDisplayContent.mClosingChangingContainers.get(this), mTmpPos);
-        } else {
-            getRelativePosition(mTmpPos);
-        }
+        getRelativePosition(mTmpPos);
         final int deltaRotation = getRelativeDisplayRotation();
         if (mTmpPos.equals(mLastSurfacePosition) && deltaRotation == mLastDeltaRotation) {
             return;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4c53ba5..4b4736e 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1060,7 +1060,7 @@
         effects |= applyChanges(taskFragment, c);
 
         if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) {
-            taskFragment.initializeChangeTransition(mTmpBounds0);
+            mTransitionController.collectVisibleChange(taskFragment);
         }
         taskFragment.continueOrganizedTaskFragmentSurfaceUpdate();
         return effects;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5897241..9f1289b2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3272,13 +3272,6 @@
                 mDestroying = false;
                 destroyedSomething = true;
             }
-
-            // Since mDestroying will affect ActivityRecord#allDrawn, we need to perform another
-            // traversal in case we are waiting on this window to start the transition.
-            if (getDisplayContent().mAppTransition.isTransitionSet()
-                    && getDisplayContent().mOpeningApps.contains(mActivityRecord)) {
-                mWmService.mWindowPlacerLocked.requestTraversal();
-            }
         }
 
         return destroyedSomething;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 9e7575f..f5bda9f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -104,7 +104,6 @@
                 .setTask(mTrampolineActivity.getTask())
                 .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TopActivity"))
                 .build();
-        mTopActivity.mDisplayContent.mOpeningApps.add(mTopActivity);
         mTransition = new Transition(TRANSIT_OPEN, 0 /* flags */,
                 mTopActivity.mTransitionController, createTestBLASTSyncEngine());
         mTransition.mParticipants.add(mTopActivity);
@@ -485,7 +484,6 @@
 
     @Test
     public void testActivityDrawnWithoutTransition() {
-        mTopActivity.mDisplayContent.mOpeningApps.remove(mTopActivity);
         mTransition.mParticipants.remove(mTopActivity);
         onIntentStarted(mTopActivity.intent);
         notifyAndVerifyActivityLaunched(mTopActivity);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index bb29614..280e432 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -3326,16 +3326,13 @@
         makeWindowVisibleAndDrawn(app);
 
         // Put the activity in close transition.
-        mDisplayContent.mOpeningApps.clear();
-        mDisplayContent.mClosingApps.add(app.mActivityRecord);
-        mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
+        requestTransition(app.mActivityRecord, WindowManager.TRANSIT_CLOSE);
 
         // Remove window during transition, so it is requested to hide, but won't be committed until
         // the transition is finished.
         app.mActivityRecord.onRemovedFromDisplay();
         app.mActivityRecord.prepareSurfaces();
 
-        assertTrue(mDisplayContent.mClosingApps.contains(app.mActivityRecord));
         assertFalse(app.mActivityRecord.isVisibleRequested());
         assertTrue(app.mActivityRecord.isVisible());
         assertTrue(app.mActivityRecord.isSurfaceShowing());
@@ -3353,11 +3350,6 @@
         makeWindowVisibleAndDrawn(app);
         app.mActivityRecord.prepareSurfaces();
 
-        // Put the activity in close transition.
-        mDisplayContent.mOpeningApps.clear();
-        mDisplayContent.mClosingApps.add(app.mActivityRecord);
-        mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
-
         // Commit visibility before start transition.
         app.mActivityRecord.commitVisibility(false, false);
 
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 018ea58..d016e735 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -151,6 +151,10 @@
         doReturn(taskBounds).when(mTaskStack.top()).getBounds();
     }
 
+    void configureTaskAppBounds(@NonNull Rect appBounds) {
+        mTaskStack.top().getWindowConfiguration().setAppBounds(appBounds);
+    }
+
     void configureTopActivityBounds(@NonNull Rect activityBounds) {
         doReturn(activityBounds).when(mActivityStack.top()).getBounds();
     }
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 0c31032..2603d78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
@@ -16,7 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -27,6 +29,7 @@
 import static org.mockito.Mockito.mock;
 
 import android.graphics.Rect;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.view.InsetsSource;
 import android.view.InsetsState;
@@ -40,6 +43,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
+import com.android.window.flags.Flags;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -225,6 +229,53 @@
         });
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS)
+    public void testGetRoundedCornersRadius_letterboxBoundsMatchHeightInFreeform_notRounded() {
+        runTestScenario((robot) -> {
+            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.activity().setTaskWindowingMode(WINDOWING_MODE_FREEFORM);
+            final Rect appBounds = new Rect(0, 0, 100, 500);
+            robot.configureWindowStateFrame(appBounds);
+            robot.activity().configureTaskAppBounds(appBounds);
+
+            robot.startLetterbox();
+
+            robot.checkWindowStateRoundedCornersRadius(/* expected */ 0);
+        });
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS)
+    public void testGetRoundedCornersRadius_letterboxBoundsNotMatchHeightInFreeform_rounded() {
+        runTestScenario((robot) -> {
+            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.activity().setTaskWindowingMode(WINDOWING_MODE_FREEFORM);
+            robot.configureWindowStateFrame(new Rect(0, 0, 500, 200));
+            robot.activity().configureTaskAppBounds(new Rect(0, 0, 500, 500));
+
+            robot.startLetterbox();
+
+            robot.checkWindowStateRoundedCornersRadius(/* expected */ 15);
+        });
+    }
+
     /**
      * Runs a test scenario providing a Robot.
      */
@@ -265,6 +316,10 @@
             spyOn(getTransparentPolicy());
         }
 
+        void startLetterbox() {
+            getAppCompatLetterboxPolicy().start(mWindowState);
+        }
+
         void configureWindowStateWithTaskBar(boolean hasInsetsRoundedCorners) {
             configureWindowState(/* withTaskBar */ true, hasInsetsRoundedCorners);
         }
@@ -273,6 +328,10 @@
             configureWindowState(/* withTaskBar */ false, /* hasInsetsRoundedCorners */ false);
         }
 
+        void configureWindowStateFrame(@NonNull Rect frame) {
+            doReturn(frame).when(mWindowState).getFrame();
+        }
+
         void configureInsetsRoundedCorners(@NonNull RoundedCorners roundedCorners) {
             mInsetsState.setRoundedCorners(roundedCorners);
         }
@@ -290,6 +349,7 @@
             }
             mWindowState.mInvGlobalScale = 1f;
             final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
+            attrs.type = TYPE_BASE_APPLICATION;
             doReturn(mInsetsState).when(mWindowState).getInsetsState();
             doReturn(attrs).when(mWindowState).getAttrs();
             doReturn(true).when(mWindowState).isDrawn();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 6e109a8..d5b9751 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1800,8 +1800,7 @@
         final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build();
         app.setVisible(false);
         app.setState(ActivityRecord.State.RESUMED, "test");
-        mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
-        mDisplayContent.mOpeningApps.add(app);
+        requestTransition(app, WindowManager.TRANSIT_OPEN);
         final int newOrientation = getRotatedOrientation(mDisplayContent);
         app.setRequestedOrientation(newOrientation);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 7ab55bf..cc2a76d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -189,11 +189,12 @@
         doReturn(true).when(mTaskFragment).isVisible();
         doReturn(true).when(mTaskFragment).isVisibleRequested();
 
+        spyOn(mTaskFragment.mTransitionController);
         clearInvocations(mTransaction);
         mTaskFragment.setBounds(endBounds);
 
         // No change transition, but update the organized surface position.
-        verify(mTaskFragment, never()).initializeChangeTransition(any(), any());
+        verify(mTaskFragment.mTransitionController, never()).collectVisibleChange(any());
         verify(mTransaction).setPosition(mLeash, endBounds.left, endBounds.top);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index edffab8..cee98fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -409,17 +409,6 @@
     }
 
     @Test
-    public void testIsAnimating_TransitionFlag() {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
-        final TestWindowContainer root = builder.setLayer(0).build();
-        final TestWindowContainer child1 = root.addChildWindow(
-                builder.setWaitForTransitionStart(true));
-
-        assertFalse(root.isAnimating(TRANSITION));
-        assertTrue(child1.isAnimating(TRANSITION));
-    }
-
-    @Test
     public void testIsAnimating_ParentsFlag() {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
@@ -1655,7 +1644,7 @@
         };
 
         TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating,
-                boolean isVisible, boolean waitTransitStart, Integer orientation, WindowState ws) {
+                boolean isVisible, Integer orientation, WindowState ws) {
             super(wm);
 
             mLayer = layer;
@@ -1663,7 +1652,6 @@
             mIsVisible = isVisible;
             mFillsParent = true;
             mOrientation = orientation;
-            mWaitForTransitStart = waitTransitStart;
             mWindowState = ws;
             spyOn(mSurfaceAnimator);
             doReturn(mIsAnimating).when(mSurfaceAnimator).isAnimating();
@@ -1729,11 +1717,6 @@
         }
 
         @Override
-        boolean isWaitingForTransitionStart() {
-            return mWaitForTransitStart;
-        }
-
-        @Override
         WindowState asWindowState() {
             return mWindowState;
         }
@@ -1744,7 +1727,6 @@
         private int mLayer;
         private boolean mIsAnimating;
         private boolean mIsVisible;
-        private boolean mIsWaitTransitStart;
         private Integer mOrientation;
         private WindowState mWindowState;
 
@@ -1782,14 +1764,9 @@
             return this;
         }
 
-        TestWindowContainerBuilder setWaitForTransitionStart(boolean waitTransitStart) {
-            mIsWaitTransitStart = waitTransitStart;
-            return this;
-        }
-
         TestWindowContainer build() {
             return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible,
-                    mIsWaitTransitStart, mOrientation, mWindowState);
+                    mOrientation, mWindowState);
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 1dfb20a..d228970 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
 import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -33,9 +34,11 @@
 import static com.android.server.wm.ActivityRecord.State.STARTED;
 import static com.android.server.wm.ActivityRecord.State.STOPPED;
 import static com.android.server.wm.ActivityRecord.State.STOPPING;
+import static com.android.server.wm.ConfigurationContainer.applySizeOverrideIfNeeded;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -58,6 +61,7 @@
 import android.graphics.Rect;
 import android.os.LocaleList;
 import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 
 import org.junit.Before;
@@ -453,6 +457,56 @@
         assertEquals(topDisplayArea, mWpc.getTopActivityDisplayArea());
     }
 
+    @Test
+    @EnableFlags(com.android.window.flags.Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION)
+    public void testOverrideConfigurationApplied() {
+        final DisplayContent displayContent = new TestDisplayContent.Builder(mAtm, 1000, 1500)
+                .setSystemDecorations(true).setDensityDpi(160).build();
+        final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
+        // Setup the decor insets info.
+        final DisplayPolicy.DecorInsets.Info decorInsetsInfo = new DisplayPolicy.DecorInsets.Info();
+        final Rect emptyRect = new Rect();
+        decorInsetsInfo.mNonDecorInsets.set(emptyRect);
+        decorInsetsInfo.mConfigInsets.set(emptyRect);
+        decorInsetsInfo.mOverrideConfigInsets.set(new Rect(0, 100, 0, 200));
+        decorInsetsInfo.mOverrideNonDecorInsets.set(new Rect(0, 0, 0, 200));
+        decorInsetsInfo.mNonDecorFrame.set(new Rect(0, 0, 1000, 1500));
+        decorInsetsInfo.mConfigFrame.set(new Rect(0, 0, 1000, 1500));
+        decorInsetsInfo.mOverrideConfigFrame.set(new Rect(0, 100, 1000, 1300));
+        decorInsetsInfo.mOverrideNonDecorFrame.set(new Rect(0, 0, 1000, 1300));
+        doReturn(decorInsetsInfo).when(displayPolicy)
+                .getDecorInsetsInfo(anyInt(), anyInt(), anyInt());
+
+        final Configuration newParentConfig = displayContent.getConfiguration();
+        final Configuration resolvedConfig = new Configuration();
+
+        // Mock the app info to not enforce the decoupled configuration to apply the override.
+        final ApplicationInfo appInfo = mock(ApplicationInfo.class);
+        doReturn(false).when(appInfo)
+                .isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED);
+        doReturn(false).when(appInfo)
+                .isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
+
+        // No value should be set before override.
+        assertNull(resolvedConfig.windowConfiguration.getAppBounds());
+        applySizeOverrideIfNeeded(
+                displayContent,
+                appInfo,
+                newParentConfig,
+                resolvedConfig,
+                false /* optsOutEdgeToEdge */,
+                false /* hasFixedRotationTransform */,
+                false /* hasCompatDisplayInsets */,
+                null /* task */);
+
+        // Assert the override config insets are applied.
+        // Status bars, and all non-decor insets should be deducted for the config screen size.
+        assertEquals(1200, resolvedConfig.screenHeightDp);
+        // Only the non-decor insets should be deducted for the app bounds.
+        assertNotNull(resolvedConfig.windowConfiguration.getAppBounds());
+        assertEquals(1300, resolvedConfig.windowConfiguration.getAppBounds().height());
+    }
+
     private TestDisplayContent createTestDisplayContentInContainer() {
         return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
     }