Merge "Fix back animation doesn't work when triggered a second time" into udc-dev
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 210c9aa..04f8477 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -561,6 +561,9 @@
         }
         if (runner.isWaitingAnimation()) {
             ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Gesture released, but animation didn't ready.");
+            // Supposed it is in post commit animation state, and start the timeout to watch
+            // if the animation is ready.
+            mShellExecutor.executeDelayed(mAnimationTimeoutRunnable, MAX_ANIMATION_DURATION);
             return;
         } else if (runner.isAnimationCancelled()) {
             invokeOrCancelBack();
@@ -577,6 +580,8 @@
         if (mPostCommitAnimationInProgress) {
             return;
         }
+
+        mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable);
         ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: startPostCommitAnimation()");
         mPostCommitAnimationInProgress = true;
         mShellExecutor.executeDelayed(mAnimationTimeoutRunnable, MAX_ANIMATION_DURATION);
@@ -595,9 +600,6 @@
      */
     @VisibleForTesting
     void onBackAnimationFinished() {
-        if (!mPostCommitAnimationInProgress) {
-            return;
-        }
         // Stop timeout runner.
         mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable);
         mPostCommitAnimationInProgress = false;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 806bffe..0673484 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -166,6 +166,9 @@
         doMotionEvent(MotionEvent.ACTION_DOWN, 0);
         doMotionEvent(MotionEvent.ACTION_MOVE, 0);
         mController.setTriggerBack(true);
+    }
+
+    private void releaseBackGesture() {
         doMotionEvent(MotionEvent.ACTION_UP, 0);
     }
 
@@ -201,6 +204,8 @@
                     .setOnBackNavigationDone(new RemoteCallback(result)));
             triggerBackGesture();
             simulateRemoteAnimationStart(type);
+            mShellExecutor.flushAll();
+            releaseBackGesture();
             simulateRemoteAnimationFinished();
             mShellExecutor.flushAll();
 
@@ -252,6 +257,7 @@
         createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, false);
 
         triggerBackGesture();
+        releaseBackGesture();
 
         verify(mAppCallback, times(1)).onBackInvoked();
 
@@ -269,6 +275,8 @@
 
         triggerBackGesture();
         simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+        releaseBackGesture();
+
         // Check that back invocation is dispatched.
         verify(mAnimatorCallback).onBackInvoked();
         verify(mBackAnimationRunner).onAnimationStart(anyInt(), any(), any(), any(), any());
@@ -308,6 +316,9 @@
 
         triggerBackGesture();
         simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+        mShellExecutor.flushAll();
+
+        releaseBackGesture();
 
         // Simulate transition timeout.
         mShellExecutor.flushAll();
@@ -369,6 +380,9 @@
             simulateRemoteAnimationStart(type);
             mShellExecutor.flushAll();
 
+            releaseBackGesture();
+            mShellExecutor.flushAll();
+
             assertTrue("Navigation Done callback not called for "
                     + BackNavigationInfo.typeToString(type), result.mBackNavigationDone);
             assertTrue("TriggerBack should have been true", result.mTriggerBack);
@@ -395,6 +409,8 @@
                 .setOnBackNavigationDone(new RemoteCallback(result)));
         triggerBackGesture();
         mShellExecutor.flushAll();
+        releaseBackGesture();
+        mShellExecutor.flushAll();
 
         assertTrue("Navigation Done callback not called for "
                 + BackNavigationInfo.typeToString(type), result.mBackNavigationDone);
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 7b562b0..7453743 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -648,31 +648,28 @@
         if (finishedTransition == mWaitTransitionFinish) {
             clearBackAnimations();
         }
+
         if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) {
             return false;
         }
-
         ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
                 "Handling the deferred animation after transition finished");
 
-        // Show the target surface and its parents to prevent it or its parents hidden when
-        // the transition finished.
-        // The target could be affected by transition when :
-        // Open transition -> the open target in back navigation
-        // Close transition -> the close target in back navigation.
+        // Find the participated container collected by transition when :
+        // Open transition -> the open target in back navigation, the close target in transition.
+        // Close transition -> the close target in back navigation, the open target in transition.
         boolean hasTarget = false;
-        final SurfaceControl.Transaction t =
-                mPendingAnimationBuilder.mCloseTarget.getPendingTransaction();
-        for (int i = 0; i < targets.size(); i++) {
-            final WindowContainer wc = targets.get(i).mContainer;
-            if (wc.asActivityRecord() == null && wc.asTask() == null) {
-                continue;
-            } else if (!mPendingAnimationBuilder.containTarget(wc)) {
+        for (int i = 0; i < finishedTransition.mParticipants.size(); i++) {
+            final WindowContainer wc = finishedTransition.mParticipants.valueAt(i);
+            if (wc.asActivityRecord() == null && wc.asTask() == null
+                    && wc.asTaskFragment() == null) {
                 continue;
             }
 
-            hasTarget = true;
-            t.show(wc.getSurfaceControl());
+            if (mPendingAnimationBuilder.containTarget(wc)) {
+                hasTarget = true;
+                break;
+            }
         }
 
         if (!hasTarget) {
@@ -689,6 +686,12 @@
             return false;
         }
 
+        // Ensure the final animation targets which hidden by transition could be visible.
+        for (int i = 0; i < targets.size(); i++) {
+            final WindowContainer wc = targets.get(i).mContainer;
+            wc.prepareSurfaces();
+        }
+
         scheduleAnimation(mPendingAnimationBuilder);
         mPendingAnimationBuilder = null;
         return true;
@@ -1076,7 +1079,7 @@
 
             boolean containTarget(@NonNull WindowContainer wc) {
                 return wc == mOpenTarget || wc == mCloseTarget
-                        || wc.hasChild(mOpenTarget) || wc.hasChild(mCloseTarget);
+                        || mOpenTarget.hasChild(wc) || mCloseTarget.hasChild(wc);
             }
 
             /**
@@ -1151,6 +1154,11 @@
     private static void setLaunchBehind(@NonNull ActivityRecord activity) {
         if (!activity.isVisibleRequested()) {
             activity.setVisibility(true);
+            // The transition could commit the visibility and in the finishing state, that could
+            // skip commitVisibility call in setVisibility cause the activity won't visible here.
+            // Call it again to make sure the activity could be visible while handling the pending
+            // animation.
+            activity.commitVisibility(true, true);
         }
         activity.mLaunchTaskBehind = true;