Use SyncRtSurfaceTransactionApplier for recents enter/exit

To ensure proper synchronization, fixing jank.

Furthermore, we need to move the background choreographer to
vsync-sf pulse in order to allow for a smooth transition
background -> foreground when handling the touch.

Test: Swipe up, disable swipe, press recents to enter/exit
Bug: 80292740
Change-Id: Ie58616edf6432a0154d6dbf8497218721154d2b8
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 41bf729..308e92f 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 7b29323..8082d30 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -65,6 +65,7 @@
 import com.android.systemui.shared.system.LatencyTrackerCompat;
 import com.android.systemui.shared.system.PackageManagerWrapper;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
 import com.android.systemui.shared.system.TransactionCompat;
 
 import java.util.ArrayList;
@@ -348,11 +349,14 @@
             clipHelper.updateTargetRect(targetRect);
             clipHelper.prepareAnimation(false /* isOpening */);
 
+            SyncRtSurfaceTransactionApplier syncTransactionApplier =
+                    new SyncRtSurfaceTransactionApplier(rootView);
             ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
             valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
             valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
             valueAnimator.addUpdateListener((v) ->
-                    clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue()));
+                    clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue(),
+                            syncTransactionApplier));
 
             if (targetSet.isAnimatingHome()) {
                 // If we are animating home, fade in the opening targets
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 2b0c98f..ec2c318 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -46,6 +46,7 @@
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
 
 import java.util.List;
 
@@ -144,6 +145,8 @@
      */
     public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
             RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) {
+        SyncRtSurfaceTransactionApplier syncTransactionApplier =
+                new SyncRtSurfaceTransactionApplier(v);
         final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
         appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
         appAnimator.addUpdateListener(new MultiValueUpdateListener() {
@@ -155,18 +158,10 @@
             final RemoteAnimationTargetSet mTargetSet;
 
             final RectF mThumbnailRect;
-            private Surface mSurface;
-            private long mFrameNumber;
 
             {
                 mTargetSet = new RemoteAnimationTargetSet(targets, MODE_OPENING);
-                inOutHelper.setTaskTransformCallback((t, app) -> {
-                    t.setAlpha(app.leash, mTaskAlpha.value);
-
-                    if (!skipViewChanges) {
-                        t.deferTransactionUntil(app.leash, mSurface, mFrameNumber);
-                    }
-                });
+                inOutHelper.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
 
                 inOutHelper.prepareAnimation(true /* isOpening */);
                 inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
@@ -179,15 +174,8 @@
 
             @Override
             public void onUpdate(float percent) {
-                mSurface = getSurface(v);
-                mFrameNumber = mSurface != null ? getNextFrameNumber(mSurface) : -1;
-                if (mFrameNumber == -1) {
-                    // Booo, not cool! Our surface got destroyed, so no reason to animate anything.
-                    Log.w(TAG, "Failed to animate, surface got destroyed.");
-                    return;
-                }
-
-                RectF taskBounds = inOutHelper.applyTransform(mTargetSet, 1 - percent);
+                RectF taskBounds = inOutHelper.applyTransform(mTargetSet, 1 - percent,
+                        syncTransactionApplier);
                 if (!skipViewChanges) {
                     float scale = taskBounds.width() / mThumbnailRect.width();
                     v.setScaleX(scale);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index aecb66c..49a4ac8 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -49,6 +49,7 @@
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ChoreographerCompat;
 import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
 
 /**
@@ -406,6 +407,6 @@
             sRemoteUiThread.start();
         }
         new Handler(sRemoteUiThread.getLooper()).post(() ->
-                mBackgroundThreadChoreographer = Choreographer.getInstance());
+                mBackgroundThreadChoreographer = ChoreographerCompat.getSfInstance());
     }
 }
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 84b2176..a1d0584 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -73,6 +73,7 @@
 import com.android.systemui.shared.system.LatencyTrackerCompat;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
 import com.android.systemui.shared.system.WindowCallbacksCompat;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
@@ -180,6 +181,7 @@
     private T mActivity;
     private LayoutListener mLayoutListener;
     private RecentsView mRecentsView;
+    private SyncRtSurfaceTransactionApplier mSyncTransactionApplier;
     private QuickScrubController mQuickScrubController;
     private AnimationFactory mAnimationFactory = (t) -> { };
 
@@ -346,6 +348,7 @@
         }
 
         mRecentsView = activity.getOverviewPanel();
+        mSyncTransactionApplier = new SyncRtSurfaceTransactionApplier(mRecentsView);
         mQuickScrubController = mRecentsView.getQuickScrubController();
         mLayoutListener = mActivityControlHelper.createLayoutListener(mActivity);
 
@@ -503,7 +506,11 @@
 
         RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
         if (controller != null) {
-            mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, shift);
+
+            mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, shift,
+                    Looper.myLooper() == mMainThreadHandler.getLooper()
+                            ? mSyncTransactionApplier
+                            : null);
 
             // TODO: This logic is spartanic!
             boolean passedThreshold = shift > 0.12f;
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index 8c7f104..62a169c 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -30,6 +30,7 @@
 import android.os.Build;
 import android.os.RemoteException;
 import android.support.annotation.Nullable;
+import android.view.Surface;
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.BaseDraggingActivity;
@@ -44,10 +45,13 @@
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.utilities.RectFEvaluator;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import com.android.systemui.shared.system.TransactionCompat;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
 import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
 
 /**
  * Utility class to handle window clip animation
@@ -89,8 +93,8 @@
     // Wether or not applyTransform has been called yet since prepareAnimation()
     private boolean mIsFirstFrame = true;
 
-    private BiConsumer<TransactionCompat, RemoteAnimationTargetCompat> mTaskTransformCallback =
-            (t, a) -> { };
+    private BiFunction<RemoteAnimationTargetCompat, Float, Float> mTaskAlphaCallback =
+            (t, a1) -> a1;
 
     private void updateSourceStack(RemoteAnimationTargetCompat target) {
         mSourceInsets.set(target.contentInsets);
@@ -131,11 +135,11 @@
     }
 
     public void prepareAnimation(boolean isOpening) {
-        mIsFirstFrame = true;
         mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
     }
 
-    public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress) {
+    public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress,
+            @Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier) {
         RectF currentRect;
         mTmpRectF.set(mTargetRect);
         Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale);
@@ -155,35 +159,51 @@
         mClipRect.bottom = (int)
                 (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress));
 
-        TransactionCompat transaction = new TransactionCompat();
-        if (mIsFirstFrame) {
-            RemoteAnimationProvider.prepareTargetsForFirstFrame(targetSet.unfilteredApps,
-                    transaction, mBoostModeTargetLayers);
-            mIsFirstFrame = false;
-        }
-        for (RemoteAnimationTargetCompat app : targetSet.apps) {
-            if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
-                mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
-                mTmpMatrix.postTranslate(app.position.x, app.position.y);
-                transaction.setMatrix(app.leash, mTmpMatrix)
-                        .setWindowCrop(app.leash, mClipRect);
+        SurfaceParams[] params = new SurfaceParams[targetSet.unfilteredApps.length];
+        for (int i = 0; i < targetSet.unfilteredApps.length; i++) {
+            RemoteAnimationTargetCompat app = targetSet.unfilteredApps[i];
+            mTmpMatrix.setTranslate(app.position.x, app.position.y);
+            Rect crop = app.sourceContainerBounds;
+            float alpha = 1f;
+            if (app.mode == targetSet.targetMode) {
+                if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+                    mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
+                    mTmpMatrix.postTranslate(app.position.x, app.position.y);
+                    crop = mClipRect;
+                }
+
+                if (app.isNotInRecents
+                        || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+                    alpha = 1 - progress;
+                }
+
+                alpha = mTaskAlphaCallback.apply(app, alpha);
             }
 
-            if (app.isNotInRecents
-                    || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
-                transaction.setAlpha(app.leash, 1 - progress);
-            }
-
-            mTaskTransformCallback.accept(transaction, app);
+            params[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop,
+                    RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers));
         }
-        transaction.setEarlyWakeup();
-        transaction.apply();
+        applyParams(syncTransactionApplier, params);
         return currentRect;
     }
 
-    public void setTaskTransformCallback
-            (BiConsumer<TransactionCompat, RemoteAnimationTargetCompat> callback) {
-        mTaskTransformCallback = callback;
+    private void applyParams(@Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier,
+            SurfaceParams[] params) {
+        if (syncTransactionApplier != null) {
+            syncTransactionApplier.scheduleApply(params);
+        } else {
+            TransactionCompat t = new TransactionCompat();
+            for (SurfaceParams param : params) {
+                SyncRtSurfaceTransactionApplier.applyParams(t, param);
+            }
+            t.setEarlyWakeup();
+            t.apply();
+        }
+    }
+
+    public void setTaskAlphaCallback(
+            BiFunction<RemoteAnimationTargetCompat, Float, Float> callback) {
+        mTaskAlphaCallback = callback;
     }
 
     public void offsetTarget(float scale, float offsetX, float offsetY, Interpolator interpolator) {
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
index 04b8be5..c372485 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
@@ -26,6 +26,7 @@
 
     public final RemoteAnimationTargetCompat[] unfilteredApps;
     public final RemoteAnimationTargetCompat[] apps;
+    public final int targetMode;
 
     public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, int targetMode) {
         ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
@@ -39,6 +40,7 @@
 
         this.unfilteredApps = apps;
         this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]);
+        this.targetMode = targetMode;
     }
 
     public RemoteAnimationTargetCompat findTask(int taskId) {