Merge "Generalize back animation and transition sequence..."
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java
index 9b91cf2..a25e035 100644
--- a/core/java/android/window/BackNavigationInfo.java
+++ b/core/java/android/window/BackNavigationInfo.java
@@ -89,8 +89,6 @@
     @Nullable
     private final IOnBackInvokedCallback mOnBackInvokedCallback;
     private final boolean mPrepareRemoteAnimation;
-    @Nullable
-    private WindowContainerToken mDepartingWindowContainerToken;
 
     /**
      * Create a new {@link BackNavigationInfo} instance.
@@ -100,20 +98,15 @@
      *                                back preview.
      * @param onBackInvokedCallback   The back callback registered by the current top level window.
      * @param departingWindowContainerToken The {@link WindowContainerToken} of departing window.
-     * @param isPrepareRemoteAnimation  Return whether the core is preparing a back gesture
-     *                                  animation, if true, the caller of startBackNavigation should
-     *                                  be expected to receive an animation start callback.
      */
     private BackNavigationInfo(@BackTargetType int type,
             @Nullable RemoteCallback onBackNavigationDone,
             @Nullable IOnBackInvokedCallback onBackInvokedCallback,
-            boolean isPrepareRemoteAnimation,
-            @Nullable WindowContainerToken departingWindowContainerToken) {
+            boolean isPrepareRemoteAnimation) {
         mType = type;
         mOnBackNavigationDone = onBackNavigationDone;
         mOnBackInvokedCallback = onBackInvokedCallback;
         mPrepareRemoteAnimation = isPrepareRemoteAnimation;
-        mDepartingWindowContainerToken = departingWindowContainerToken;
     }
 
     private BackNavigationInfo(@NonNull Parcel in) {
@@ -121,7 +114,6 @@
         mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR);
         mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
         mPrepareRemoteAnimation = in.readBoolean();
-        mDepartingWindowContainerToken = in.readTypedObject(WindowContainerToken.CREATOR);
     }
 
     @Override
@@ -130,7 +122,6 @@
         dest.writeTypedObject(mOnBackNavigationDone, flags);
         dest.writeStrongInterface(mOnBackInvokedCallback);
         dest.writeBoolean(mPrepareRemoteAnimation);
-        dest.writeTypedObject(mDepartingWindowContainerToken, flags);
     }
 
     /**
@@ -164,18 +155,6 @@
     }
 
     /**
-     * Returns the {@link WindowContainerToken} of the highest container in the hierarchy being
-     * removed.
-     * <p>
-     * For example, if an Activity is the last one of its Task, the Task's token will be given.
-     * Otherwise, it will be the Activity's token.
-     */
-    @Nullable
-    public WindowContainerToken getDepartingWindowContainerToken() {
-        return mDepartingWindowContainerToken;
-    }
-
-    /**
      * Callback to be called when the back preview is finished in order to notify the server that
      * it can clean up the resources created for the animation.
      *
@@ -212,7 +191,6 @@
                 + "mType=" + typeToString(mType) + " (" + mType + ")"
                 + ", mOnBackNavigationDone=" + mOnBackNavigationDone
                 + ", mOnBackInvokedCallback=" + mOnBackInvokedCallback
-                + ", mWindowContainerToken=" + mDepartingWindowContainerToken
                 + '}';
     }
 
@@ -248,8 +226,6 @@
         @Nullable
         private IOnBackInvokedCallback mOnBackInvokedCallback = null;
         private boolean mPrepareRemoteAnimation;
-        @Nullable
-        private WindowContainerToken mDepartingWindowContainerToken = null;
 
         /**
          * @see BackNavigationInfo#getType()
@@ -285,20 +261,12 @@
         }
 
         /**
-         * @see BackNavigationInfo#getDepartingWindowContainerToken()
-         */
-        public void setDepartingWCT(@NonNull WindowContainerToken windowContainerToken) {
-            mDepartingWindowContainerToken = windowContainerToken;
-        }
-
-        /**
          * Builds and returns an instance of {@link BackNavigationInfo}
          */
         public BackNavigationInfo build() {
             return new BackNavigationInfo(mType, mOnBackNavigationDone,
                     mOnBackInvokedCallback,
-                    mPrepareRemoteAnimation,
-                    mDepartingWindowContainerToken);
+                    mPrepareRemoteAnimation);
         }
     }
 }
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 0956a71..c2da638 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -138,8 +138,11 @@
     /** The container is a system window, excluding wallpaper and input-method. */
     public static final int FLAG_IS_SYSTEM_WINDOW = 1 << 16;
 
+    /** The window was animated by back gesture. */
+    public static final int FLAG_BACK_GESTURE_ANIMATED = 1 << 17;
+
     /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
-    public static final int FLAG_FIRST_CUSTOM = 1 << 17;
+    public static final int FLAG_FIRST_CUSTOM = 1 << 18;
 
     /** The change belongs to a window that won't contain activities. */
     public static final int FLAGS_IS_NON_APP_WINDOW =
@@ -165,6 +168,7 @@
             FLAG_IS_BEHIND_STARTING_WINDOW,
             FLAG_IS_OCCLUDED,
             FLAG_IS_SYSTEM_WINDOW,
+            FLAG_BACK_GESTURE_ANIMATED,
             FLAG_FIRST_CUSTOM
     })
     public @interface ChangeFlags {}
@@ -380,6 +384,9 @@
         if ((flags & FLAG_IS_SYSTEM_WINDOW) != 0) {
             sb.append(sb.length() == 0 ? "" : "|").append("FLAG_IS_SYSTEM_WINDOW");
         }
+        if ((flags & FLAG_BACK_GESTURE_ANIMATED) != 0) {
+            sb.append(sb.length() == 0 ? "" : "|").append("FLAG_BACK_GESTURE_ANIMATED");
+        }
         if ((flags & FLAG_FIRST_CUSTOM) != 0) {
             sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
         }
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index c1b4dcc..4cc06e3 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2179,12 +2179,6 @@
       "group": "WM_DEBUG_ANIM",
       "at": "com\/android\/server\/wm\/WindowContainer.java"
     },
-    "-23020844": {
-      "message": "Back: Reset surfaces",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
     "-21399771": {
       "message": "activity %s already destroying, skipping request with reason:%s",
       "level": "VERBOSE",
@@ -3823,12 +3817,6 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1544805551": {
-      "message": "Skipping app transition animation. task=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "1557732761": {
       "message": "For Intent %s bringing to top: %s",
       "level": "DEBUG",
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 64220c8..b6327e5 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
@@ -62,7 +62,6 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -82,8 +81,6 @@
                     SETTING_VALUE_OFF) == SETTING_VALUE_ON;
     /** Predictive back animation developer option */
     private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
-    // TODO (b/241808055) Find a appropriate time to remove during refactor
-    private static final boolean ENABLE_SHELL_TRANSITIONS = Transitions.ENABLE_SHELL_TRANSITIONS;
     /**
      * Max duration to wait for a transition to finish before accepting another gesture start
      * request.
@@ -121,8 +118,6 @@
     private final TouchTracker mTouchTracker = new TouchTracker();
 
     private final SparseArray<BackAnimationRunner> mAnimationDefinition = new SparseArray<>();
-    private final Transitions mTransitions;
-    private BackTransitionHandler mBackTransitionHandler;
 
     @VisibleForTesting
     final IWindowFocusObserver mFocusObserver = new IWindowFocusObserver.Stub() {
@@ -148,11 +143,9 @@
             @NonNull ShellController shellController,
             @NonNull @ShellMainThread ShellExecutor shellExecutor,
             @NonNull @ShellBackgroundThread Handler backgroundHandler,
-            Context context,
-            Transitions transitions) {
+            Context context) {
         this(shellInit, shellController, shellExecutor, backgroundHandler,
-                ActivityTaskManager.getService(), context, context.getContentResolver(),
-                transitions);
+                ActivityTaskManager.getService(), context, context.getContentResolver());
     }
 
     @VisibleForTesting
@@ -162,8 +155,7 @@
             @NonNull @ShellMainThread ShellExecutor shellExecutor,
             @NonNull @ShellBackgroundThread Handler bgHandler,
             @NonNull IActivityTaskManager activityTaskManager,
-            Context context, ContentResolver contentResolver,
-            Transitions transitions) {
+            Context context, ContentResolver contentResolver) {
         mShellController = shellController;
         mShellExecutor = shellExecutor;
         mActivityTaskManager = activityTaskManager;
@@ -171,7 +163,6 @@
         mContentResolver = contentResolver;
         mBgHandler = bgHandler;
         shellInit.addInitCallback(this::onInit, this);
-        mTransitions = transitions;
     }
 
     @VisibleForTesting
@@ -182,10 +173,6 @@
     private void onInit() {
         setupAnimationDeveloperSettingsObserver(mContentResolver, mBgHandler);
         createAdapter();
-        if (ENABLE_SHELL_TRANSITIONS) {
-            mBackTransitionHandler = new BackTransitionHandler(this);
-            mTransitions.addHandler(mBackTransitionHandler);
-        }
         mShellController.addExternalInterface(KEY_EXTRA_SHELL_BACK_ANIMATION,
                 this::createExternalInterface, this);
 
@@ -335,17 +322,7 @@
             }
         }
 
-        // In legacy transition, it would use `Task.mBackGestureStarted` in core to handle the
-        // following transition when back callback is invoked.
-        // If the back callback is not invoked, we should reset the token and finish the whole back
-        // navigation without waiting the transition.
-        if (!ENABLE_SHELL_TRANSITIONS) {
-            finishBackNavigation();
-        } else if (!mTriggerBack) {
-            // reset the token to prevent it consume next transition.
-            mBackTransitionHandler.setDepartingWindowContainerToken(null);
-            finishBackNavigation();
-        }
+        finishBackNavigation();
     }
 
     /**
@@ -614,10 +591,6 @@
             return;
         }
         mTransitionInProgress = true;
-        if (ENABLE_SHELL_TRANSITIONS) {
-            mBackTransitionHandler.setDepartingWindowContainerToken(
-                    mBackNavigationInfo.getDepartingWindowContainerToken());
-        }
         mShellExecutor.executeDelayed(mResetTransitionRunnable, MAX_TRANSITION_DURATION);
     }
 
@@ -626,19 +599,6 @@
         mTransitionInProgress = false;
     }
 
-    /**
-     * This should be called from {@link BackTransitionHandler#startAnimation} when the following
-     * transition is triggered by the real back callback in {@link #onBackAnimationFinished}.
-     * Will consume the default transition and finish current back navigation.
-     */
-    void finishTransition(Transitions.TransitionFinishCallback finishCallback) {
-        ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishTransition()");
-        mShellExecutor.execute(() -> {
-            finishBackNavigation();
-            finishCallback.onTransitionFinished(null, null);
-        });
-    }
-
     private void createAdapter() {
         IBackAnimationRunner runner = new IBackAnimationRunner.Stub() {
             @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackTransitionHandler.java
deleted file mode 100644
index 6d72d9c..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackTransitionHandler.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.back;
-
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.window.TransitionInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.wm.shell.transition.Transitions;
-
-class BackTransitionHandler implements Transitions.TransitionHandler {
-    private BackAnimationController mBackAnimationController;
-    private WindowContainerToken mDepartingWindowContainerToken;
-
-    BackTransitionHandler(@NonNull BackAnimationController backAnimationController) {
-        mBackAnimationController = backAnimationController;
-    }
-
-    @Override
-    public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction startTransaction,
-            @NonNull SurfaceControl.Transaction finishTransaction,
-            @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        if (mDepartingWindowContainerToken != null) {
-            final TransitionInfo.Change change = info.getChange(mDepartingWindowContainerToken);
-            if (change == null) {
-                return false;
-            }
-
-            startTransaction.hide(change.getLeash());
-            startTransaction.apply();
-            mDepartingWindowContainerToken = null;
-            mBackAnimationController.finishTransition(finishCallback);
-            return true;
-        }
-
-        return false;
-    }
-
-    @Nullable
-    @Override
-    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
-            @NonNull TransitionRequestInfo request) {
-        return null;
-    }
-
-    @Override
-    public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
-            @NonNull Transitions.TransitionFinishCallback finishCallback) {
-    }
-
-    void setDepartingWindowContainerToken(
-            @Nullable WindowContainerToken departingWindowContainerToken) {
-        mDepartingWindowContainerToken = departingWindowContainerToken;
-    }
-}
-
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 1977dcb..962be9d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -260,13 +260,12 @@
             ShellInit shellInit,
             ShellController shellController,
             @ShellMainThread ShellExecutor shellExecutor,
-            @ShellBackgroundThread Handler backgroundHandler,
-            Transitions transitions
+            @ShellBackgroundThread Handler backgroundHandler
     ) {
         if (BackAnimationController.IS_ENABLED) {
             return Optional.of(
                     new BackAnimationController(shellInit, shellController, shellExecutor,
-                            backgroundHandler, context, transitions));
+                            backgroundHandler, context));
         }
         return Optional.empty();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 928e71f..63d4a6f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -41,6 +41,7 @@
 import static android.view.WindowManager.TRANSIT_RELAUNCH;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
 import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
 import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
 import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
@@ -395,6 +396,11 @@
                 }
             }
 
+            // The back gesture has animated this change before transition happen, so here we don't
+            // play the animation again.
+            if (change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)) {
+                continue;
+            }
             // Don't animate anything that isn't independent.
             if (!TransitionInfo.isIndependent(change, info)) continue;
 
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 7896247..7eccbf4 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
@@ -64,7 +64,6 @@
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.sysui.ShellSharedConstants;
-import com.android.wm.shell.transition.Transitions;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -103,9 +102,6 @@
     private IRemoteAnimationRunner mBackAnimationRunner;
 
     @Mock
-    private Transitions mTransitions;
-
-    @Mock
     private ShellController mShellController;
 
     private BackAnimationController mController;
@@ -127,7 +123,7 @@
         mController = new BackAnimationController(mShellInit, mShellController,
                 mShellExecutor, new Handler(mTestableLooper.getLooper()),
                 mActivityTaskManager, mContext,
-                mContentResolver, mTransitions);
+                mContentResolver);
         mController.setEnableUAnimation(true);
         mShellInit.init();
         mEventTime = 0;
@@ -225,7 +221,7 @@
         mController = new BackAnimationController(shellInit, mShellController,
                 mShellExecutor, new Handler(mTestableLooper.getLooper()),
                 mActivityTaskManager, mContext,
-                mContentResolver, mTransitions);
+                mContentResolver);
         shellInit.init();
         mController.setBackToLauncherCallback(mIOnBackInvokedCallback, mBackAnimationRunner);
 
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 9011533..bd22b32 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -215,9 +215,20 @@
         mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
                 mDisplayContent.mOpeningApps);
 
+        ArraySet<ActivityRecord> tmpOpenApps = mDisplayContent.mOpeningApps;
+        ArraySet<ActivityRecord> tmpCloseApps = mDisplayContent.mClosingApps;
+        if (mDisplayContent.mAtmService.mBackNavigationController.isWaitBackTransition()) {
+            tmpOpenApps = new ArraySet<>(mDisplayContent.mOpeningApps);
+            tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps);
+            if (mDisplayContent.mAtmService.mBackNavigationController
+                    .removeIfContainsBackAnimationTargets(tmpOpenApps, tmpCloseApps)) {
+                mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(null);
+            }
+        }
+
         @TransitionOldType final int transit = getTransitCompatType(
-                mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps,
-                mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers,
+                mDisplayContent.mAppTransition, tmpOpenApps,
+                tmpCloseApps, mDisplayContent.mChangingContainers,
                 mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
                 mDisplayContent.mSkipAppTransitionAnimation);
         mDisplayContent.mSkipAppTransitionAnimation = false;
@@ -225,22 +236,21 @@
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "handleAppTransitionReady: displayId=%d appTransition={%s}"
                 + " openingApps=[%s] closingApps=[%s] transit=%s",
-                mDisplayContent.mDisplayId, appTransition.toString(), mDisplayContent.mOpeningApps,
-                mDisplayContent.mClosingApps, AppTransition.appTransitionOldToString(transit));
+                mDisplayContent.mDisplayId, appTransition.toString(), tmpOpenApps,
+                tmpCloseApps, AppTransition.appTransitionOldToString(transit));
 
         // Find the layout params of the top-most application window in the tokens, which is
         // what will control the animation theme. If all closing windows are obscured, then there is
         // no need to do an animation. This is the case, for example, when this transition is being
         // done behind a dream window.
-        final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
-                mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
+        final ArraySet<Integer> activityTypes = collectActivityTypes(tmpOpenApps,
+                tmpCloseApps, mDisplayContent.mChangingContainers);
         final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes,
-                mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
-                mDisplayContent.mChangingContainers);
+                tmpOpenApps, tmpCloseApps, mDisplayContent.mChangingContainers);
         final ActivityRecord topOpeningApp =
-                getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
+                getTopApp(tmpOpenApps, false /* ignoreHidden */);
         final ActivityRecord topClosingApp =
-                getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
+                getTopApp(tmpCloseApps, false /* ignoreHidden */);
         final ActivityRecord topChangingApp =
                 getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
         final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
@@ -258,8 +268,7 @@
         final int layoutRedo;
         mService.mSurfaceAnimationRunner.deferStartingAnimations();
         try {
-            applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
-                    animLp, voiceInteraction);
+            applyAnimations(tmpOpenApps, tmpCloseApps, transit, animLp, voiceInteraction);
             handleClosingApps();
             handleOpeningApps();
             handleChangingApps(transit);
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 6ff2bb3..9398bbe 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -19,6 +19,8 @@
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
 
@@ -32,6 +34,7 @@
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.view.IWindowFocusObserver;
 import android.view.RemoteAnimationTarget;
@@ -41,7 +44,6 @@
 import android.window.IBackAnimationFinishedCallback;
 import android.window.OnBackInvokedCallbackInfo;
 import android.window.TaskSnapshot;
-import android.window.WindowContainerToken;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
@@ -60,9 +62,9 @@
     private boolean mShowWallpaper;
     private Runnable mPendingAnimation;
 
-    // TODO (b/241808055) Find a appropriate time to remove during refactor
-    // Execute back animation with legacy transition system. Temporary flag for easier debugging.
-    static final boolean ENABLE_SHELL_TRANSITIONS = WindowManagerService.sEnableShellTransitions;
+    private final AnimationTargets mAnimationTargets = new AnimationTargets();
+    private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>();
+    private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>();
 
     /**
      * true if the back predictability feature is enabled
@@ -284,7 +286,6 @@
             }
 
             if (prepareAnimation) {
-                infoBuilder.setDepartingWCT(toWindowContainerToken(currentTask));
                 prepareAnimationIfNeeded(currentTask, prevTask, prevActivity,
                         removedWindowContainer, backType, adapter);
             }
@@ -303,11 +304,233 @@
         return infoBuilder.build();
     }
 
-    private static WindowContainerToken toWindowContainerToken(WindowContainer<?> windowContainer) {
-        if (windowContainer == null || windowContainer.mRemoteToken == null) {
-            return null;
+    boolean isWaitBackTransition() {
+        return mAnimationTargets.mComposed && mAnimationTargets.mWaitTransition;
+    }
+
+    // For legacy transition.
+    /**
+     *  Once we find the transition targets match back animation targets, remove the target from
+     *  list, so that transition won't count them in since the close animation was finished.
+     *
+     *  @return {@code true} if the participants of this transition was animated by back gesture
+     *  animations, and shouldn't join next transition.
+     */
+    boolean removeIfContainsBackAnimationTargets(ArraySet<ActivityRecord> openApps,
+            ArraySet<ActivityRecord> closeApps) {
+        if (!isWaitBackTransition()) {
+            return false;
         }
-        return windowContainer.mRemoteToken.toWindowContainerToken();
+        mTmpCloseApps.addAll(closeApps);
+        boolean result = false;
+        // Note: TmpOpenApps is empty. Unlike shell transition, the open apps will be removed from
+        // mOpeningApps if there is no visibility change.
+        if (mAnimationTargets.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps)) {
+            // remove close target from close list, open target from open list;
+            // but the open target can be in close list.
+            for (int i = openApps.size() - 1; i >= 0; --i) {
+                final ActivityRecord ar = openApps.valueAt(i);
+                if (mAnimationTargets.isTarget(ar, true /* open */)) {
+                    openApps.removeAt(i);
+                }
+            }
+            for (int i = closeApps.size() - 1; i >= 0; --i) {
+                final ActivityRecord ar = closeApps.valueAt(i);
+                if (mAnimationTargets.isTarget(ar, false /* open */)) {
+                    closeApps.removeAt(i);
+                }
+            }
+            result = true;
+        }
+        mTmpCloseApps.clear();
+        return result;
+    }
+
+    // For shell transition
+    /**
+     *  Check whether the transition targets was animated by back gesture animation.
+     *  Because the opening target could request to do other stuff at onResume, so it could become
+     *  close target for a transition. So the condition here is
+     *  The closing target should only exist in close list, but the opening target can be either in
+     *  open or close list.
+     *  @return {@code true} if the participants of this transition was animated by back gesture
+     *  animations, and shouldn't join next transition.
+     */
+    boolean containsBackAnimationTargets(Transition transition) {
+        if (!mAnimationTargets.mComposed
+                || (transition.mType != TRANSIT_CLOSE && transition.mType != TRANSIT_TO_BACK)) {
+            return false;
+        }
+        final ArraySet<WindowContainer> targets = transition.mParticipants;
+        for (int i = targets.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = targets.valueAt(i);
+            if (wc.asActivityRecord() == null && wc.asTask() == null) {
+                continue;
+            }
+            // WC can be visible due to setLaunchBehind
+            if (wc.isVisibleRequested()) {
+                mTmpOpenApps.add(wc);
+            } else {
+                mTmpCloseApps.add(wc);
+            }
+        }
+        final boolean result = mAnimationTargets.containsBackAnimationTargets(
+                mTmpOpenApps, mTmpCloseApps);
+        mTmpOpenApps.clear();
+        mTmpCloseApps.clear();
+        return result;
+    }
+
+    boolean isMonitorTransitionTarget(WindowContainer wc) {
+        if (!mAnimationTargets.mComposed || !mAnimationTargets.mWaitTransition) {
+            return false;
+        }
+        return mAnimationTargets.isTarget(wc, wc.isVisibleRequested() /* open */);
+    }
+
+    /**
+     * Cleanup animation, this can either happen when transition ready or finish.
+     * @param cleanupTransaction The transaction which the caller want to apply the internal
+     *                           cleanup together.
+     */
+    void clearBackAnimations(SurfaceControl.Transaction cleanupTransaction) {
+        mAnimationTargets.clearBackAnimateTarget(cleanupTransaction);
+    }
+
+    /**
+     * TODO: Animation composer
+     * prepareAnimationIfNeeded will become too complicated in order to support
+     * ActivityRecord/WindowState, using a factory class to create the RemoteAnimationTargets for
+     * different scenario.
+     */
+    private static class AnimationTargets {
+        ActivityRecord mCloseTarget; // Must be activity
+        WindowContainer mOpenTarget; // Can be activity or task if activity was removed
+        private boolean mComposed;
+        private boolean mWaitTransition;
+        private int mSwitchType = UNKNOWN;
+        private SurfaceControl.Transaction mFinishedTransaction;
+
+        private static final int UNKNOWN = 0;
+        private static final int TASK_SWITCH = 1;
+        private static final int ACTIVITY_SWITCH = 2;
+
+        void reset(@NonNull WindowContainer close, @NonNull WindowContainer open) {
+            clearBackAnimateTarget(null);
+            if (close.asActivityRecord() != null && open.asActivityRecord() != null
+                    && (close.asActivityRecord().getTask() == open.asActivityRecord().getTask())) {
+                mSwitchType = ACTIVITY_SWITCH;
+                mCloseTarget = close.asActivityRecord();
+            } else if (close.asTask() != null && open.asTask() != null
+                    && close.asTask() != open.asTask()) {
+                mSwitchType = TASK_SWITCH;
+                mCloseTarget = close.asTask().getTopNonFinishingActivity();
+            } else {
+                mSwitchType = UNKNOWN;
+                return;
+            }
+
+            mOpenTarget = open;
+            mComposed = false;
+            mWaitTransition = false;
+        }
+
+        void composeNewAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) {
+            reset(close, open);
+            if (mSwitchType == UNKNOWN || mComposed || mCloseTarget == mOpenTarget
+                    || mCloseTarget == null || mOpenTarget == null) {
+                return;
+            }
+            mComposed = true;
+            mWaitTransition = false;
+        }
+
+        boolean containTarget(ArrayList<WindowContainer> wcs, boolean open) {
+            for (int i = wcs.size() - 1; i >= 0; --i) {
+                if (isTarget(wcs.get(i), open)) {
+                    return true;
+                }
+            }
+            return wcs.isEmpty();
+        }
+
+        boolean isTarget(WindowContainer wc, boolean open) {
+            if (open) {
+                return wc == mOpenTarget || mOpenTarget.hasChild(wc);
+            }
+            if (mSwitchType == TASK_SWITCH) {
+                return  wc == mCloseTarget
+                        || (wc.asTask() != null && wc.hasChild(mCloseTarget));
+            } else if (mSwitchType == ACTIVITY_SWITCH) {
+                return wc == mCloseTarget;
+            }
+            return false;
+        }
+
+        boolean setFinishTransaction(SurfaceControl.Transaction finishTransaction) {
+            if (!mComposed) {
+                return false;
+            }
+            mFinishedTransaction = finishTransaction;
+            return true;
+        }
+
+        void finishPresentAnimations(SurfaceControl.Transaction t) {
+            if (!mComposed) {
+                return;
+            }
+            final SurfaceControl.Transaction pt = t != null ? t
+                    : mOpenTarget.getPendingTransaction();
+            if (mFinishedTransaction != null) {
+                pt.merge(mFinishedTransaction);
+                mFinishedTransaction = null;
+            }
+        }
+
+        void clearBackAnimateTarget(SurfaceControl.Transaction cleanupTransaction) {
+            finishPresentAnimations(cleanupTransaction);
+            mCloseTarget = null;
+            mOpenTarget = null;
+            mComposed = false;
+            mWaitTransition = false;
+            mSwitchType = UNKNOWN;
+            if (mFinishedTransaction != null) {
+                Slog.w(TAG, "Clear back animation, found un-processed finished transaction");
+                if (cleanupTransaction != null) {
+                    cleanupTransaction.merge(mFinishedTransaction);
+                } else {
+                    mFinishedTransaction.apply();
+                }
+                mFinishedTransaction = null;
+            }
+        }
+
+        // The close target must in close list
+        // The open target can either in close or open list
+        boolean containsBackAnimationTargets(ArrayList<WindowContainer> openApps,
+                ArrayList<WindowContainer> closeApps) {
+            return containTarget(closeApps, false /* open */)
+                    && (containTarget(openApps, true /* open */)
+                    || containTarget(openApps, false /* open */));
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder(128);
+            sb.append("AnimationTargets{");
+            sb.append(" mOpenTarget= ");
+            sb.append(mOpenTarget);
+            sb.append(" mCloseTarget= ");
+            sb.append(mCloseTarget);
+            sb.append(" mSwitchType= ");
+            sb.append(mSwitchType);
+            sb.append(" mComposed= ");
+            sb.append(mComposed);
+            sb.append(" mWaitTransition= ");
+            sb.append(mWaitTransition);
+            sb.append('}');
+            return sb.toString();
+        }
     }
 
     private void prepareAnimationIfNeeded(Task currentTask,
@@ -373,10 +596,6 @@
                 leashes.add(screenshotSurface);
             }
         } else if (prevTask != null) {
-            if (!ENABLE_SHELL_TRANSITIONS) {
-                // Special handling for preventing next transition.
-                currentTask.mBackGestureStarted = true;
-            }
             prevActivity = prevTask.getTopNonFinishingActivity();
             if (prevActivity != null) {
                 // Make previous task show from behind by marking its top activity as visible
@@ -417,35 +636,36 @@
                         for (SurfaceControl sc: leashes) {
                             finishedTransaction.remove(sc);
                         }
-
                         synchronized (mWindowManagerService.mGlobalLock) {
-                            if (ENABLE_SHELL_TRANSITIONS) {
-                                if (!triggerBack) {
-                                    if (!needsScreenshot(backType)) {
-                                        restoreLaunchBehind(finalPrevActivity);
-                                    }
+                            if (triggerBack) {
+                                final SurfaceControl surfaceControl =
+                                        removedWindowContainer.getSurfaceControl();
+                                if (surfaceControl != null && surfaceControl.isValid()) {
+                                    // The animation is finish and start waiting for transition,
+                                    // hide the task surface before it re-parented to avoid flicker.
+                                    finishedTransaction.hide(surfaceControl);
                                 }
+                            } else if (!needsScreenshot(backType)) {
+                                restoreLaunchBehind(finalPrevActivity);
+                            }
+                            if (!mAnimationTargets.setFinishTransaction(finishedTransaction)) {
+                                finishedTransaction.apply();
+                            }
+                            if (!triggerBack) {
+                                mAnimationTargets.clearBackAnimateTarget(null);
                             } else {
-                                if (triggerBack) {
-                                    final SurfaceControl surfaceControl =
-                                            removedWindowContainer.getSurfaceControl();
-                                    if (surfaceControl != null && surfaceControl.isValid()) {
-                                        // When going back to home, hide the task surface before it
-                                        // re-parented to avoid flicker.
-                                        finishedTransaction.hide(surfaceControl);
-                                    }
-                                } else {
-                                    currentTask.mBackGestureStarted = false;
-                                    if (!needsScreenshot(backType)) {
-                                        restoreLaunchBehind(finalPrevActivity);
-                                    }
-                                }
+                                mAnimationTargets.mWaitTransition = true;
                             }
                         }
-                        finishedTransaction.apply();
+                        // TODO Add timeout monitor if transition didn't happen
                     }
                 };
-
+        if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
+            mAnimationTargets.composeNewAnimations(removedWindowContainer, prevActivity);
+        } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+                || backType == BackNavigationInfo.TYPE_CROSS_TASK) {
+            mAnimationTargets.composeNewAnimations(removedWindowContainer, prevTask);
+        }
         scheduleAnimationLocked(backType, targets, adapter, callback);
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d75ab64..cdb3321 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -67,7 +67,6 @@
 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -607,12 +606,6 @@
 
     boolean mLastSurfaceShowing = true;
 
-    /**
-     * Tracks if a back gesture is in progress.
-     * Skips any system transition animations if this is set to {@code true}.
-     */
-    boolean mBackGestureStarted = false;
-
     private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
             Intent _affinityIntent, String _affinity, String _rootAffinity,
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -3333,14 +3326,6 @@
                     }
                 });
             }
-        } else if (mBackGestureStarted) {
-            // Cancel playing transitions if a back navigation animation is in progress.
-            // This bit is set by {@link BackNavigationController} when a back gesture is started.
-            // It is used as a one-off transition overwrite that is cleared when the back gesture
-            // is committed and triggers a transition, or when the gesture is cancelled.
-            mBackGestureStarted = false;
-            mDisplayContent.mSkipAppTransitionAnimation = true;
-            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Skipping app transition animation. task=%s", this);
         } else {
             super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
         }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index a64bd69..ef68590 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -928,10 +928,16 @@
             mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED;
         }
 
+        // Check whether the participants were animated from back navigation.
+        final boolean markBackAnimated = mController.mAtm.mBackNavigationController
+                .containsBackAnimationTargets(this);
         // Resolve the animating targets from the participants
         mTargets = calculateTargets(mParticipants, mChanges);
         final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges,
                 transaction);
+        if (markBackAnimated) {
+            mController.mAtm.mBackNavigationController.clearBackAnimations(mStartTransaction);
+        }
         if (mOverrideOptions != null) {
             info.setAnimationOptions(mOverrideOptions);
             if (mOverrideOptions.getType() == ANIM_OPEN_CROSS_PROFILE_APPS) {
@@ -1935,9 +1941,20 @@
             final Task task = wc.asTask();
             if (task != null) {
                 final ActivityRecord topActivity = task.getTopNonFinishingActivity();
-                if (topActivity != null && topActivity.mStartingData != null
-                        && topActivity.mStartingData.hasImeSurface()) {
-                    flags |= FLAG_WILL_IME_SHOWN;
+                if (topActivity != null) {
+                    if (topActivity.mStartingData != null
+                            && topActivity.mStartingData.hasImeSurface()) {
+                        flags |= FLAG_WILL_IME_SHOWN;
+                    }
+                    if (topActivity.mAtmService.mBackNavigationController
+                            .isMonitorTransitionTarget(topActivity)) {
+                        flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
+                    }
+                } else {
+                    if (task.mAtmService.mBackNavigationController
+                            .isMonitorTransitionTarget(task)) {
+                        flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
+                    }
                 }
                 if (task.voiceSession != null) {
                     flags |= FLAG_IS_VOICE_INTERACTION;
@@ -1951,6 +1968,10 @@
                     flags |= FLAG_IS_VOICE_INTERACTION;
                 }
                 flags |= record.mTransitionChangeFlags;
+                if (record.mAtmService.mBackNavigationController
+                        .isMonitorTransitionTarget(record)) {
+                    flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
+                }
             }
             final TaskFragment taskFragment = wc.asTaskFragment();
             if (taskFragment != null && task == null) {