Merge cherrypicks of ['googleplex-android-review.googlesource.com/26621463', 'googleplex-android-review.googlesource.com/26681774', 'googleplex-android-review.googlesource.com/26741740', 'googleplex-android-review.googlesource.com/26837538', 'googleplex-android-review.googlesource.com/26875227', 'googleplex-android-review.googlesource.com/26905538', 'googleplex-android-review.googlesource.com/27015418'] into 24Q2-release.

Change-Id: I1853d6149b716bba6624a0cea2cba63f91b7dbdb
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 828004b..0ced3a6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8430,8 +8430,9 @@
      *            hierarchy
      * @param refocus when propagate is true, specifies whether to request the
      *            root view place new focus
+     * @hide
      */
-    void clearFocusInternal(View focused, boolean propagate, boolean refocus) {
+    public void clearFocusInternal(View focused, boolean propagate, boolean refocus) {
         if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
             mPrivateFlags &= ~PFLAG_FOCUSED;
             clearParentsWantFocus();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1721462..92dcf88 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9733,7 +9733,7 @@
                         return KEY_EVENT_HANDLED;
                     }
                     if (hasFocus()) {
-                        clearFocus();
+                        clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
                         InputMethodManager imm = getInputMethodManager();
                         if (imm != null) {
                             imm.hideSoftInputFromView(this, 0);
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 1d03301..ad864ec 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -994,7 +994,15 @@
 }
 
 void CanvasContext::onContextDestroyed() {
-    destroyHardwareResources();
+    // We don't want to destroyHardwareResources as that will invalidate display lists which
+    // the client may not be expecting. Instead just purge all scratch resources
+    if (mRenderPipeline->isContextReady()) {
+        freePrefetchedLayers();
+        for (const sp<RenderNode>& node : mRenderNodes) {
+            node->destroyLayers();
+        }
+        mRenderPipeline->onDestroyHardwareResources();
+    }
 }
 
 DeferredLayerUpdater* CanvasContext::createTextureLayer() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index b3b7bce..fd08daf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -1188,9 +1188,7 @@
     }
 
     boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
-        return (isPlayBackInfoLocal()
-                || device.getDeviceType() != MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE)
-                && !device.isVolumeFixed();
+        return !device.isVolumeFixed();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index dfe41eb..592df5e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -35,6 +35,7 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.inputmethodservice.InputMethodService;
 import android.net.Uri;
@@ -73,6 +74,7 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import dagger.Lazy;
@@ -100,7 +102,7 @@
         AccessibilityButtonModeObserver.ModeChangedListener,
         AccessibilityButtonTargetsObserver.TargetsChangedListener,
         OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
-        Dumpable, CommandQueue.Callbacks {
+        Dumpable, CommandQueue.Callbacks, ConfigurationController.ConfigurationListener {
     private static final String TAG = NavBarHelper.class.getSimpleName();
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -188,6 +190,7 @@
             UserTracker userTracker,
             DisplayTracker displayTracker,
             NotificationShadeWindowController notificationShadeWindowController,
+            ConfigurationController configurationController,
             DumpManager dumpManager,
             CommandQueue commandQueue,
             @Main Executor mainExecutor) {
@@ -214,6 +217,7 @@
 
         mNavBarMode = navigationModeController.addListener(this);
         mCommandQueue.addCallback(this);
+        configurationController.addCallback(this);
         overviewProxyService.addCallback(this);
         dumpManager.registerDumpable(this);
     }
@@ -358,6 +362,11 @@
         updateA11yState();
     }
 
+    @Override
+    public void onConfigChanged(Configuration newConfig) {
+        mEdgeBackGestureHandler.onConfigurationChanged(newConfig);
+    }
+
     /**
      * Updates the current accessibility button state. The accessibility button state is only
      * used for {@link Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} and
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 1793861..13ba9c3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -874,11 +874,6 @@
             refreshLayout(ld);
         }
         repositionNavigationBar(rotation);
-        // NOTE(b/260220098): In some cases, the recreated nav bar will already have the right
-        // configuration, which means that NavBarView will not receive a configuration change to
-        // propagate to EdgeBackGestureHandler (which is injected into this and NBV). As such, we
-        // should also force-update the gesture handler to ensure it updates to the right bounds
-        mEdgeBackGestureHandler.onConfigurationChanged(newConfig);
         if (canShowSecondaryHandle()) {
             if (rotation != mCurrentRotation) {
                 mCurrentRotation = rotation;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index 152f193..42a25bd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -160,14 +160,11 @@
         mIsLargeScreen = isLargeScreen(mContext);
         boolean willApplyConfig = mConfigChanges.applyNewConfig(mContext.getResources());
         boolean largeScreenChanged = mIsLargeScreen != isOldConfigLargeScreen;
-        // TODO(b/243765256): Disable this logging once b/243765256 is fixed.
+        // TODO(b/332635834): Disable this logging once b/332635834 is fixed.
         Log.i(DEBUG_MISSING_GESTURE_TAG, "NavbarController: newConfig=" + newConfig
                 + " mTaskbarDelegate initialized=" + mTaskbarDelegate.isInitialized()
                 + " willApplyConfigToNavbars=" + willApplyConfig
                 + " navBarCount=" + mNavigationBars.size());
-        if (mTaskbarDelegate.isInitialized()) {
-            mTaskbarDelegate.onConfigurationChanged(newConfig);
-        }
         // If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded
         if (largeScreenChanged && updateNavbarForTaskbar()) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index c5190a2..bc0a1da 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -1026,7 +1026,6 @@
         updateIcons(mTmpLastConfiguration);
         updateRecentsIcon();
         updateCurrentRotation();
-        mEdgeBackGestureHandler.onConfigurationChanged(mConfiguration);
         if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
                 || mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
             // If car mode or density changes, we need to reset the icons.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 5dd1bd8..f67973b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -39,7 +39,6 @@
 import android.app.StatusBarManager;
 import android.app.StatusBarManager.WindowVisibleState;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.inputmethodservice.InputMethodService;
@@ -72,7 +71,6 @@
 import com.android.systemui.statusbar.AutoHideUiElement;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoHideController;
-import com.android.systemui.statusbar.phone.BarTransitions;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -250,8 +248,6 @@
             mLightBarController.setNavigationBar(mLightBarTransitionsController);
             mPipOptional.ifPresent(this::addPipExclusionBoundsChangeListener);
             mEdgeBackGestureHandler.setBackAnimation(mBackAnimation);
-            mEdgeBackGestureHandler.onConfigurationChanged(
-                    mContext.getResources().getConfiguration());
             mTaskStackChangeListeners.registerTaskStackListener(mTaskStackListener);
             mInitialized = true;
         } finally {
@@ -495,10 +491,6 @@
         return mBehavior != BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
     }
 
-    public void onConfigurationChanged(Configuration configuration) {
-        mEdgeBackGestureHandler.onConfigurationChanged(configuration);
-    }
-
     @Override
     public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
         mOverviewProxyService.onNavigationBarLumaSamplingEnabled(displayId, enable);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 91c86df..d40949f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -1180,7 +1180,7 @@
             updateDisabledForQuickstep(newConfig);
         }
 
-        // TODO(b/243765256): Disable this logging once b/243765256 is fixed.
+        // TODO(b/332635834): Disable this logging once b/332635834 is fixed.
         Log.i(DEBUG_MISSING_GESTURE_TAG, "Config changed: newConfig=" + newConfig
                 + " lastReportedConfig=" + mLastReportedConfig);
         mLastReportedConfig.updateFrom(newConfig);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
index e5ba569..277119d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -35,6 +35,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
+import android.content.res.Configuration;
 import android.view.IWindowManager;
 import android.view.accessibility.AccessibilityManager;
 
@@ -54,6 +55,8 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.FakeConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
@@ -116,6 +119,7 @@
     EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
     @Mock
     NotificationShadeWindowController mNotificationShadeWindowController;
+    ConfigurationController mConfigurationController = new FakeConfigurationController();
 
     private AccessibilityManager.AccessibilityServicesStateChangeListener
             mAccessibilityServicesStateChangeListener;
@@ -143,9 +147,8 @@
                 mSystemActions, mOverviewProxyService, mAssistManagerLazy,
                 () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardStateController.class),
                 mNavigationModeController, mEdgeBackGestureHandlerFactory, mWm, mUserTracker,
-                mDisplayTracker, mNotificationShadeWindowController, mDumpManager, mCommandQueue,
-                mSynchronousExecutor);
-
+                mDisplayTracker, mNotificationShadeWindowController, mConfigurationController,
+                mDumpManager, mCommandQueue, mSynchronousExecutor);
     }
 
     @Test
@@ -334,6 +337,12 @@
         assertThat(state2.mWindowState).isNotEqualTo(newState);
     }
 
+    @Test
+    public void configUpdatePropagatesToEdgeBackGestureHandler() {
+        mConfigurationController.onConfigurationChanged(Configuration.EMPTY);
+        verify(mEdgeBackGestureHandler, times(1)).onConfigurationChanged(any());
+    }
+
     private List<String> createFakeShortcutTargets() {
         return new ArrayList<>(List.of("a", "b", "c", "d"));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
index 52859cd..df75ea7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
@@ -37,11 +37,8 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
-import android.content.res.Configuration;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.SparseArray;
@@ -292,23 +289,6 @@
     }
 
     @Test
-    public void testConfigurationChange_taskbarNotInitialized() {
-        Configuration configuration = mContext.getResources().getConfiguration();
-        mNavigationBarController.mIsLargeScreen = true;
-        mNavigationBarController.onConfigChanged(configuration);
-        verify(mTaskbarDelegate, never()).onConfigurationChanged(configuration);
-    }
-
-    @Test
-    public void testConfigurationChange_taskbarInitialized() {
-        Configuration configuration = mContext.getResources().getConfiguration();
-        mNavigationBarController.mIsLargeScreen = true;
-        when(mTaskbarDelegate.isInitialized()).thenReturn(true);
-        mNavigationBarController.onConfigChanged(configuration);
-        verify(mTaskbarDelegate, times(1)).onConfigurationChanged(configuration);
-    }
-
-    @Test
     public void testShouldRenderTaskbar_taskbarNotRenderedOnPhone() {
         mNavigationBarController.mIsLargeScreen = false;
         mNavigationBarController.mIsPhone = true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 31746a2..2382746 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -110,6 +110,7 @@
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.DeviceConfigProxyFake;
@@ -274,8 +275,8 @@
                     mKeyguardStateController, mock(NavigationModeController.class),
                     mEdgeBackGestureHandlerFactory, mock(IWindowManager.class),
                     mock(UserTracker.class), mock(DisplayTracker.class),
-                    mNotificationShadeWindowController, mock(DumpManager.class),
-                    mock(CommandQueue.class), mSynchronousExecutor));
+                    mNotificationShadeWindowController, mock(ConfigurationController.class),
+                    mock(DumpManager.class), mock(CommandQueue.class), mSynchronousExecutor));
             mNavigationBar = createNavBar(mContext);
             mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
         });
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 663ba8a..7f5a865 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4451,7 +4451,9 @@
             }
         }
 
-        if (packageName == null || uninstalling || packageStateStopped) {
+        final boolean clearPendingIntentsForStoppedApp = (android.content.pm.Flags.stayStopped()
+                && packageStateStopped);
+        if (packageName == null || uninstalling || clearPendingIntentsForStoppedApp) {
             didSomething |= mPendingIntentController.removePendingIntentsForPackage(
                     packageName, userId, appId, doit);
         }
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index 1715254..9d04682 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -196,8 +196,7 @@
                 File signatureFile = new File(dir, FONT_SIGNATURE_FILE);
                 if (!signatureFile.exists()) {
                     Slog.i(TAG, "The signature file is missing.");
-                    FileUtils.deleteContentsAndDir(dir);
-                    continue;
+                    return;
                 }
                 byte[] signature;
                 try {
@@ -222,10 +221,36 @@
 
                 FontFileInfo fontFileInfo = validateFontFile(fontFile, signature);
                 if (fontConfig == null) {
-                    fontConfig = getSystemFontConfig();
+                    // Use preinstalled font config for checking revision number.
+                    fontConfig = mConfigSupplier.apply(Collections.emptyMap());
                 }
                 addFileToMapIfSameOrNewer(fontFileInfo, fontConfig, true /* deleteOldFile */);
             }
+
+            // Treat as error if post script name of font family was not installed.
+            for (int i = 0; i < config.fontFamilies.size(); ++i) {
+                FontUpdateRequest.Family family = config.fontFamilies.get(i);
+                for (int j = 0; j < family.getFonts().size(); ++j) {
+                    FontUpdateRequest.Font font = family.getFonts().get(j);
+                    if (mFontFileInfoMap.containsKey(font.getPostScriptName())) {
+                        continue;
+                    }
+
+                    if (fontConfig == null) {
+                        fontConfig = mConfigSupplier.apply(Collections.emptyMap());
+                    }
+
+                    if (getFontByPostScriptName(font.getPostScriptName(), fontConfig) != null) {
+                        continue;
+                    }
+
+                    Slog.e(TAG, "Unknown font that has PostScript name "
+                            + font.getPostScriptName() + " is requested in FontFamily "
+                            + family.getName());
+                    return;
+                }
+            }
+
             success = true;
         } catch (Throwable t) {
             // If something happened during loading system fonts, clear all contents in finally
@@ -237,6 +262,7 @@
                 mFontFileInfoMap.clear();
                 mLastModifiedMillis = 0;
                 FileUtils.deleteContents(mFilesDir);
+                mConfigFile.delete();
             }
         }
     }
@@ -485,8 +511,7 @@
         return shouldAddToMap;
     }
 
-    private long getPreinstalledFontRevision(FontFileInfo info, FontConfig fontConfig) {
-        String psName = info.getPostScriptName();
+    private FontConfig.Font getFontByPostScriptName(String psName, FontConfig fontConfig) {
         FontConfig.Font targetFont = null;
         for (int i = 0; i < fontConfig.getFontFamilies().size(); i++) {
             FontConfig.FontFamily family = fontConfig.getFontFamilies().get(i);
@@ -511,6 +536,13 @@
                 }
             }
         }
+        return targetFont;
+    }
+
+    private long getPreinstalledFontRevision(FontFileInfo info, FontConfig fontConfig) {
+        String psName = info.getPostScriptName();
+        FontConfig.Font targetFont = getFontByPostScriptName(psName, fontConfig);
+
         if (targetFont == null) {
             return -1;
         }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1353ff0..2212724 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5770,7 +5770,7 @@
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
-        if (isTopRootTaskInDisplayArea() && mAtmService.mController != null) {
+        if (mAtmService.mController != null && isTopRootTaskInDisplayArea()) {
             ActivityRecord next = topRunningActivity(null, task.mTaskId);
             if (next == null) {
                 next = topRunningActivity(null, INVALID_TASK_ID);
@@ -5814,6 +5814,15 @@
                 + tr.mTaskId);
 
         if (mTransitionController.isShellTransitionsEnabled()) {
+            // TODO(b/277838915): Consider to make it concurrent to eliminate the special case.
+            final Transition collecting = mTransitionController.getCollectingTransition();
+            if (collecting != null && collecting.mType == TRANSIT_OPEN) {
+                // It can be a CLOSING participate of an OPEN transition. This avoids the deferred
+                // transition from moving task to back after the task was moved to front.
+                collecting.collect(tr);
+                moveTaskToBackInner(tr, collecting);
+                return true;
+            }
             final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */,
                     mTransitionController, mWmService.mSyncEngine);
             // Guarantee that this gets its own transition by queueing on SyncEngine
@@ -5842,7 +5851,7 @@
         return true;
     }
 
-    private boolean moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) {
+    private void moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) {
         final Transition.ReadyCondition movedToBack =
                 new Transition.ReadyCondition("moved-to-back", task);
         if (transition != null) {
@@ -5857,7 +5866,7 @@
 
             if (inPinnedWindowingMode()) {
                 mTaskSupervisor.removeRootTask(this);
-                return true;
+                return;
             }
 
             mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
@@ -5880,7 +5889,6 @@
         } else {
             mRootWindowContainer.resumeFocusedTasksTopActivities();
         }
-        return true;
     }
 
     boolean willActivityBeVisible(IBinder token) {
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index dacff4c..fa89278 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -999,6 +999,563 @@
         assertThat(mUpdatableFontFilesDir.list()).hasLength(0);
     }
 
+    private UpdatableFontDir createNewUpdateDir() {
+        UpdatableFontDir dir = new UpdatableFontDir(
+                mUpdatableFontFilesDir, mParser, mFakeFsverityUtil,
+                mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
+        dir.loadFontFileMap();
+        return dir;
+    }
+
+    private UpdatableFontDir installTestFontFamilies(int version) {
+        UpdatableFontDir dir = createNewUpdateDir();
+        try {
+            dir.update(Arrays.asList(
+                    newFontUpdateRequest("foo.ttf," + version + ",foo", GOOD_SIGNATURE),
+                    newFontUpdateRequest("bar.ttf," + version + ",bar", GOOD_SIGNATURE),
+                    newAddFontFamilyRequest("<family name='foobar'>"
+                            + "  <font>foo.ttf</font>"
+                            + "  <font>bar.ttf</font>"
+                            + "</family>")));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return dir;
+    }
+
+    private UpdatableFontDir installTestFontFile(int numFonts, int version) {
+        UpdatableFontDir dir = createNewUpdateDir();
+        List<FontUpdateRequest> requests = new ArrayList<>();
+        if (numFonts <= 0 || numFonts > 3) {
+            throw new IllegalArgumentException("numFont must be 1, 2 or 3");
+        }
+        try {
+            requests.add(newFontUpdateRequest("foo.ttf," + version + ",foo", GOOD_SIGNATURE));
+            if (numFonts >= 2) {
+                requests.add(newFontUpdateRequest("bar.ttf," + version + ",bar", GOOD_SIGNATURE));
+            }
+            if (numFonts == 3) {
+                requests.add(newFontUpdateRequest("baz.ttf," + version + ",baz", GOOD_SIGNATURE));
+            }
+            dir.update(requests);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return dir;
+    }
+
+    private List<File> collectSignatureFiles() {
+        return Arrays.stream(mUpdatableFontFilesDir.listFiles())
+                .map((file) -> file.listFiles((unused, s) -> s.endsWith(".fsv_sig")))
+                .flatMap(Arrays::stream)
+                .toList();
+    }
+
+    private List<File> collectFontFiles() {
+        return Arrays.stream(mUpdatableFontFilesDir.listFiles())
+                .map((file) -> file.listFiles((unused, s) -> s.endsWith(".ttf")))
+                .flatMap(Arrays::stream)
+                .toList();
+    }
+
+    private void removeAll(List<File> files) {
+        files.forEach((File file) -> {
+            if (file.isDirectory()) {
+                removeAll(List.of(file.listFiles()));
+            } else {
+                assertThat(file.delete()).isTrue();
+            }
+        });
+    }
+
+    private void assertTestFontFamilyInstalled(UpdatableFontDir dir, int version) {
+        try {
+            assertNamedFamilyExists(dir.getSystemFontConfig(), "foobar");
+            assertThat(dir.getFontFamilyMap()).containsKey("foobar");
+            assertThat(dir.getFontFamilyMap().get("foobar").getFamilies().size()).isEqualTo(1);
+            FontConfig.FontFamily foobar = dir.getFontFamilyMap().get("foobar").getFamilies()
+                    .get(0);
+            assertThat(foobar.getFontList()).hasSize(2);
+            assertThat(foobar.getFontList().get(0).getFile())
+                    .isEqualTo(dir.getPostScriptMap().get("foo"));
+            assertThat(mParser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(version);
+            assertThat(foobar.getFontList().get(1).getFile())
+                    .isEqualTo(dir.getPostScriptMap().get("bar"));
+            assertThat(mParser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(version);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void assertTestFontInstalled(UpdatableFontDir dir, int version) {
+        try {
+            assertThat(dir.getPostScriptMap().containsKey("foo")).isTrue();
+            assertThat(mParser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(version);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    public void signatureMissingCase_fontFamilyInstalled_fontFamilyInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete one signature file
+        assertThat(collectSignatureFiles().get(0).delete()).isTrue();
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void signatureMissingCase_fontFamilyInstalled_fontInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1);
+
+        // Delete one signature file
+        assertThat(collectSignatureFiles().get(0).delete()).isTrue();
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void signatureMissingCase_fontFileInstalled_fontFamilyInstallLater() {
+        // Install font file, foo.ttf and bar.ttf
+        installTestFontFile(2 /* numFonts */, 1 /* version */);
+
+        // Delete one signature file
+        assertThat(collectSignatureFiles().get(0).delete()).isTrue();
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void signatureMissingCase_fontFileInstalled_fontFileInstallLater() {
+        // Install font file, foo.ttf and bar.ttf
+        installTestFontFile(2 /* numFonts */, 1 /* version */);
+
+        // Delete one signature file
+        assertThat(collectSignatureFiles().get(0).delete()).isTrue();
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(2 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void signatureAllMissingCase_fontFamilyInstalled_fontFamilyInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete all signature files
+        removeAll(collectSignatureFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void signatureAllMissingCase_fontFamilyInstalled_fontInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete all signature files
+        removeAll(collectSignatureFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void signatureAllMissingCase_fontFileInstalled_fontFamilyInstallLater() {
+        // Install font file, foo.ttf
+        installTestFontFile(1 /* numFonts */, 1 /* version */);
+
+        // Delete all signature files
+        removeAll(collectSignatureFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void signatureAllMissingCase_fontFileInstalled_fontFileInstallLater() {
+        // Install font file, foo.ttf
+        installTestFontFile(1 /* numFonts */, 1 /* version */);
+
+        // Delete all signature files
+        removeAll(collectSignatureFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontMissingCase_fontFamilyInstalled_fontFamilyInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete one font file
+        assertThat(collectFontFiles().get(0).delete()).isTrue();
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontMissingCase_fontFamilyInstalled_fontInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1);
+
+        // Delete one font file
+        assertThat(collectFontFiles().get(0).delete()).isTrue();
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontMissingCase_fontFileInstalled_fontFamilyInstallLater() {
+        // Install font file, foo.ttf and bar.ttf
+        installTestFontFile(2 /* numFonts */, 1 /* version */);
+
+        // Delete one font file
+        assertThat(collectFontFiles().get(0).delete()).isTrue();
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontMissingCase_fontFileInstalled_fontFileInstallLater() {
+        // Install font file, foo.ttf and bar.ttf
+        installTestFontFile(2 /* numFonts */, 1 /* version */);
+
+        // Delete one font file
+        assertThat(collectFontFiles().get(0).delete()).isTrue();
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(2 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontAllMissingCase_fontFamilyInstalled_fontFamilyInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete all font files
+        removeAll(collectFontFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontAllMissingCase_fontFamilyInstalled_fontInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete all font files
+        removeAll(collectFontFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontAllMissingCase_fontFileInstalled_fontFamilyInstallLater() {
+        // Install font file, foo.ttf
+        installTestFontFile(1 /* numFonts */, 1 /* version */);
+
+        // Delete all font files
+        removeAll(collectFontFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontAllMissingCase_fontFileInstalled_fontFileInstallLater() {
+        // Install font file, foo.ttf
+        installTestFontFile(1 /* numFonts */, 1 /* version */);
+
+        // Delete all font files
+        removeAll(collectFontFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontDirAllMissingCase_fontFamilyInstalled_fontFamilyInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete all font files
+        removeAll(List.of(mUpdatableFontFilesDir.listFiles()));
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontDirAllMissingCase_fontFamilyInstalled_fontInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete all font files
+        removeAll(List.of(mUpdatableFontFilesDir.listFiles()));
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontDirAllMissingCase_fontFileInstalled_fontFamilyInstallLater() {
+        // Install font file, foo.ttf
+        installTestFontFile(1 /* numFonts */, 1 /* version */);
+
+        // Delete all font files
+        removeAll(List.of(mUpdatableFontFilesDir.listFiles()));
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void fontDirAllMissingCase_fontFileInstalled_fontFileInstallLater() {
+        // Install font file, foo.ttf
+        installTestFontFile(1 /* numFonts */, 1 /* version */);
+
+        // Delete all font files
+        removeAll(List.of(mUpdatableFontFilesDir.listFiles()));
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void dirContentAllMissingCase_fontFamilyInstalled_fontFamilyInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete all font files
+        removeAll(collectFontFiles());
+        removeAll(collectSignatureFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void dirContentAllMissingCase_fontFamilyInstalled_fontInstallLater() {
+        // Install font families, foo.ttf, bar.ttf.
+        installTestFontFamilies(1 /* version */);
+
+        // Delete all font files
+        removeAll(collectFontFiles());
+        removeAll(collectSignatureFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void dirContentAllMissingCase_fontFileInstalled_fontFamilyInstallLater() {
+        // Install font file, foo.ttf
+        installTestFontFile(1 /* numFonts */, 1 /* version */);
+
+        // Delete all font files
+        removeAll(collectFontFiles());
+        removeAll(collectSignatureFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFamilies(2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontFamilyInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontFamilyInstalled(nextDir, 2 /* version */);
+    }
+
+    @Test
+    public void dirContentAllMissingCase_fontFileInstalled_fontFileInstallLater() {
+        // Install font file, foo.ttf
+        installTestFontFile(1 /* numFonts */, 1 /* version */);
+
+        // Delete all font files
+        removeAll(collectFontFiles());
+        removeAll(collectSignatureFiles());
+
+        // New instance of UpdatableFontDir, this emulate a device reboot.
+        UpdatableFontDir dir = installTestFontFile(1 /* numFonts */, 2 /* version */);
+
+        // Make sure the font installation succeeds.
+        assertTestFontInstalled(dir, 2 /* version */);
+
+        // Make sure after the reboot, the configuration remains.
+        UpdatableFontDir nextDir = createNewUpdateDir();
+        assertTestFontInstalled(nextDir, 2 /* version */);
+    }
+
     private FontUpdateRequest newFontUpdateRequest(String content, String signature)
             throws Exception {
         File file = File.createTempFile("font", "ttf", mCacheDir);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index ce890f6..9657eb2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -64,8 +64,10 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -2367,9 +2369,7 @@
         assertTrue(transitA.isCollecting());
 
         // finish collecting A
-        transitA.start();
-        transitA.setAllReady();
-        mSyncEngine.tryFinishForTest(transitA.getSyncId());
+        tryFinishTransitionSyncSet(transitA);
         waitUntilHandlersIdle();
 
         assertTrue(transitA.isPlaying());
@@ -2475,6 +2475,36 @@
     }
 
     @Test
+    public void testDeferredMoveTaskToBack() {
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final Task task = activity.getTask();
+        registerTestTransitionPlayer();
+        final TransitionController controller = mWm.mRoot.mTransitionController;
+        mSyncEngine = createTestBLASTSyncEngine();
+        controller.setSyncEngine(mSyncEngine);
+        final Transition transition = createTestTransition(TRANSIT_CHANGE, controller);
+        controller.moveToCollecting(transition);
+        task.moveTaskToBack(task);
+        // Actual action will be deferred by current transition.
+        verify(task, never()).moveToBack(any(), any());
+
+        tryFinishTransitionSyncSet(transition);
+        waitUntilHandlersIdle();
+        // Continue to move task to back after the transition is done.
+        verify(task).moveToBack(any(), any());
+        final Transition moveBackTransition = controller.getCollectingTransition();
+        assertNotNull(moveBackTransition);
+        moveBackTransition.abort();
+
+        // The move-to-back can be collected in to a collecting OPEN transition.
+        clearInvocations(task);
+        final Transition transition2 = createTestTransition(TRANSIT_OPEN, controller);
+        controller.moveToCollecting(transition2);
+        task.moveTaskToBack(task);
+        verify(task).moveToBack(any(), any());
+    }
+
+    @Test
     public void testNoSyncFlagIfOneTrack() {
         final TransitionController controller = mAtm.getTransitionController();
         final TestTransitionPlayer player = registerTestTransitionPlayer();
@@ -2491,17 +2521,11 @@
         controller.startCollectOrQueue(transitC, (deferred) -> {});
 
         // Verify that, as-long as there is <= 1 track, we won't get a SYNC flag
-        transitA.start();
-        transitA.setAllReady();
-        mSyncEngine.tryFinishForTest(transitA.getSyncId());
+        tryFinishTransitionSyncSet(transitA);
         assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
-        transitB.start();
-        transitB.setAllReady();
-        mSyncEngine.tryFinishForTest(transitB.getSyncId());
+        tryFinishTransitionSyncSet(transitB);
         assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
-        transitC.start();
-        transitC.setAllReady();
-        mSyncEngine.tryFinishForTest(transitC.getSyncId());
+        tryFinishTransitionSyncSet(transitC);
         assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
     }
 
@@ -2610,6 +2634,12 @@
         assertEquals("reason1", condition1.mAlternate);
     }
 
+    private void tryFinishTransitionSyncSet(Transition transition) {
+        transition.setAllReady();
+        transition.start();
+        mSyncEngine.tryFinishForTest(transition.getSyncId());
+    }
+
     private static void makeTaskOrganized(Task... tasks) {
         final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
         for (Task t : tasks) {