Merge "Force-finish pending cancellation of the recents animation when process dies" into sc-dev
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index cb30f16..9e147b1 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1030,7 +1030,13 @@
 
     @Override
     public void binderDied() {
-        cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
+        if (!mCanceled) {
+            cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
+        } else {
+            // If we are already canceled but with a screenshot, and are waiting for the
+            // cleanupScreenshot() callback, then force-finish the animation now
+            continueDeferredCancelAnimation();
+        }
 
         synchronized (mService.getWindowManagerLock()) {
             // Clear associated input consumers on runner death
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 79feb8d..d88fbee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -307,6 +307,29 @@
     }
 
     @Test
+    public void testBinderDiedAfterCancelWithDeferredScreenshot() throws Exception {
+        mWm.setRecentsAnimationController(mController);
+        final ActivityRecord homeActivity = createHomeActivity();
+        final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+        final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
+        activity.addWindow(win1);
+
+        initializeRecentsAnimationController(mController, homeActivity);
+        mController.setWillFinishToHome(true);
+
+        // Verify cancel is called with a snapshot and that we've created an overlay
+        spyOn(mWm.mTaskSnapshotController);
+        doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(),
+                anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* isLowResolution */);
+        mController.cancelAnimationWithScreenshot(true /* screenshot */);
+        verify(mMockRunner).onAnimationCanceled(any());
+
+        // Simulate process crashing and ensure the animation is still canceled
+        mController.binderDied();
+        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
+    }
+
+    @Test
     public void testRecentViewInFixedPortraitWhenTopAppInLandscape() {
         unblockDisplayRotation(mDefaultDisplay);
         mWm.setRecentsAnimationController(mController);