Use SysUI/Shell's transaction apply token in Launcher

Launcher and SysUI/Shell have a lot of interactions
that require careful synchronization and ordering (at-least
with shell-transitions). As a result, they need to share
the same apply token or else some operations can end up
out-of-order despite being applied in-order.

Bug: 242193885
Test: Open an app, quickswitch repeatedly.
Change-Id: I4cbe8b5db28516db7a08b4022f1199f3f6b89591
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index d348cc3..92dd22c 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -46,6 +46,7 @@
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
+import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
 import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
 import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
@@ -1119,6 +1120,9 @@
      * Registers remote animations used when closing apps to home screen.
      */
     public void registerRemoteTransitions() {
+        if (ENABLE_SHELL_TRANSITIONS) {
+            SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
+        }
         if (SEPARATE_RECENTS_ACTIVITY.get()) {
             return;
         }
@@ -1158,6 +1162,9 @@
     }
 
     private void unregisterRemoteTransitions() {
+        if (ENABLE_SHELL_TRANSITIONS) {
+            SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
+        }
         if (SEPARATE_RECENTS_ACTIVITY.get()) {
             return;
         }
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 0ec7e62..c2b8c8b 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -28,7 +28,6 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -101,6 +100,7 @@
     private ILauncherUnlockAnimationController mLauncherUnlockAnimationController;
     private IRecentTasksListener mRecentTasksListener;
     private final ArrayList<RemoteTransitionCompat> mRemoteTransitions = new ArrayList<>();
+    private IBinder mOriginalTransactionToken = null;
     private IOnBackInvokedCallback mBackToLauncherCallback;
 
     // Used to dedupe calls to SystemUI
@@ -199,6 +199,7 @@
         for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
             registerRemoteTransition(mRemoteTransitions.get(i));
         }
+        setupTransactionQueue();
         if (mRecentTasksListener != null && mRecentTasks != null) {
             registerRecentTasksListener(mRecentTasksListener);
         }
@@ -721,6 +722,50 @@
         mRemoteTransitions.remove(remoteTransition);
     }
 
+    /**
+     * Use SystemUI's transaction-queue instead of Launcher's independent one. This is necessary
+     * if Launcher and SystemUI need to coordinate transactions (eg. for shell transitions).
+     */
+    public void shareTransactionQueue() {
+        if (mOriginalTransactionToken == null) {
+            mOriginalTransactionToken = SurfaceControl.Transaction.getDefaultApplyToken();
+        }
+        setupTransactionQueue();
+    }
+
+    /**
+     * Switch back to using Launcher's independent transaction queue.
+     */
+    public void unshareTransactionQueue() {
+        if (mOriginalTransactionToken == null) {
+            return;
+        }
+        SurfaceControl.Transaction.setDefaultApplyToken(mOriginalTransactionToken);
+        mOriginalTransactionToken = null;
+    }
+
+    private void setupTransactionQueue() {
+        if (mOriginalTransactionToken == null) {
+            return;
+        }
+        if (mShellTransitions == null) {
+            SurfaceControl.Transaction.setDefaultApplyToken(mOriginalTransactionToken);
+            return;
+        }
+        final IBinder shellApplyToken;
+        try {
+            shellApplyToken = mShellTransitions.getShellApplyToken();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error getting Shell's apply token", e);
+            return;
+        }
+        if (shellApplyToken == null) {
+            Log.e(TAG, "Didn't receive apply token from Shell");
+            return;
+        }
+        SurfaceControl.Transaction.setDefaultApplyToken(shellApplyToken);
+    }
+
     //
     // Starting window
     //