Moving some recents controller methods into wrapper class and better tracking
the controller states

Change-Id: I561cd74dde0a49f5734cbc7fe6930703b7e998dd
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index d8c45c5..63d2531 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -292,8 +292,6 @@
         mMotionPauseDetector.setOnMotionPauseListener(handler::onMotionPauseChanged);
         handler.initWhenReady();
 
-        TraceHelper.beginSection("RecentsController");
-
         if (listenerSet != null) {
             listenerSet.addListener(handler);
             mSwipeSharedState.applyActiveRecentsAnimationState(handler);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index c2d4d80..5e7c1a1 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -21,17 +21,11 @@
 
 import android.view.MotionEvent;
 
-import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.util.UiThreadHelper;
-import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet;
 import com.android.systemui.shared.system.InputConsumerController;
-import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 
 import java.util.ArrayList;
-import java.util.concurrent.ExecutorService;
 import java.util.function.Supplier;
 
 import androidx.annotation.UiThread;
@@ -45,17 +39,10 @@
     // than the state callbacks as these run on the current worker thread.
     private final ArrayList<Runnable> mCallbacks = new ArrayList<>();
 
-    public RemoteAnimationTargetSet targetSet;
+    public SwipeAnimationTargetSet targetSet;
 
-    private RecentsAnimationControllerCompat mController;
-    private boolean mInputConsumerEnabled = false;
-    private boolean mBehindSystemBars = true;
-    private boolean mSplitScreenMinimized = false;
+    private boolean mWindowThresholdCrossed = false;
 
-    private final ExecutorService mExecutorService =
-            new LooperExecutor(UiThreadHelper.getBackgroundLooper());
-
-    private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
     private final InputConsumerController mInputConsumer;
     private final Supplier<TouchConsumer> mTouchProxySupplier;
 
@@ -71,19 +58,14 @@
     }
 
     @UiThread
-    public synchronized void setController(
-            RecentsAnimationControllerCompat controller, RemoteAnimationTargetSet targetSet) {
+    public synchronized void setController(SwipeAnimationTargetSet targetSet) {
         Preconditions.assertUIThread();
-        TraceHelper.partitionSection("RecentsController", "Set controller " + controller);
-        this.mController = controller;
         this.targetSet = targetSet;
 
-        if (controller == null) {
+        if (targetSet == null) {
             return;
         }
-        if (mInputConsumerEnabled) {
-            enableInputConsumer();
-        }
+        targetSet.setWindowThresholdCrossed(mWindowThresholdCrossed);
 
         if (!mCallbacks.isEmpty()) {
             for (Runnable action : new ArrayList<>(mCallbacks)) {
@@ -105,13 +87,12 @@
      * @param onFinishComplete A callback that runs on the main thread after the animation
      *                         controller has finished on the background thread.
      */
+    @UiThread
     public void finish(boolean toRecents, Runnable onFinishComplete) {
+        Preconditions.assertUIThread();
         if (!toRecents) {
-            mExecutorService.submit(() -> finishBg(false, onFinishComplete));
-            return;
-        }
-
-        mMainThreadExecutor.execute(() -> {
+            finishAndClear(false, onFinishComplete);
+        } else {
             if (mTouchInProgress) {
                 mFinishPending = true;
                 // Execute the callback
@@ -119,45 +100,39 @@
                     onFinishComplete.run();
                 }
             } else {
-                mExecutorService.submit(() -> finishBg(true, onFinishComplete));
+                finishAndClear(true, onFinishComplete);
             }
-        });
+        }
     }
 
-    protected void finishBg(boolean toRecents, Runnable onFinishComplete) {
-        RecentsAnimationControllerCompat controller = mController;
-        mController = null;
-        TraceHelper.endSection("RecentsController", "Finish " + controller
-                + ", toRecents=" + toRecents);
+    private void finishAndClear(boolean toRecents, Runnable onFinishComplete) {
+        SwipeAnimationTargetSet controller = targetSet;
+        targetSet = null;
         if (controller != null) {
-            controller.setInputConsumerEnabled(false);
-            controller.finish(toRecents);
-
-            if (onFinishComplete != null) {
-                mMainThreadExecutor.execute(onFinishComplete);
-            }
+            controller.finishController(toRecents, onFinishComplete);
         }
     }
 
     public void enableInputConsumer() {
-        mInputConsumerEnabled = true;
-        if (mInputConsumerEnabled) {
-            mExecutorService.submit(() -> {
-                RecentsAnimationControllerCompat controller = mController;
-                TraceHelper.partitionSection("RecentsController",
-                        "Enabling consumer on " + controller);
-                if (controller != null) {
-                    controller.setInputConsumerEnabled(true);
-                }
-            });
+        if (targetSet != null) {
+            targetSet.enableInputConsumer();
+        }
+    }
+
+    /**
+     * Indicates that the gesture has crossed the window boundary threshold and system UI can be
+     * update the represent the window behind
+     */
+    public void setWindowThresholdCrossed(boolean windowThresholdCrossed) {
+        if (mWindowThresholdCrossed != windowThresholdCrossed) {
+            mWindowThresholdCrossed = windowThresholdCrossed;
+            if (targetSet != null) {
+                targetSet.setWindowThresholdCrossed(windowThresholdCrossed);
+            }
         }
     }
 
     public void enableTouchProxy() {
-        mMainThreadExecutor.execute(this::enableTouchProxyUi);
-    }
-
-    private void enableTouchProxyUi() {
         mInputConsumer.setTouchListener(this::onInputConsumerTouch);
     }
 
@@ -171,7 +146,7 @@
             mTouchInProgress = false;
             if (mFinishPending) {
                 mFinishPending = false;
-                mExecutorService.submit(() -> finishBg(true, null));
+                finishAndClear(true /* toRecents */, null);
             }
         }
         if (mTouchConsumer != null) {
@@ -181,54 +156,7 @@
         return true;
     }
 
-    public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) {
-        if (mBehindSystemBars == behindSystemBars) {
-            return;
-        }
-        mBehindSystemBars = behindSystemBars;
-        mExecutorService.submit(() -> {
-            RecentsAnimationControllerCompat controller = mController;
-            TraceHelper.partitionSection("RecentsController",
-                    "Setting behind system bars on " + controller);
-            if (controller != null) {
-                controller.setAnimationTargetsBehindSystemBars(behindSystemBars);
-            }
-        });
-    }
-
-    /**
-     * NOTE: As a workaround for conflicting animations (Launcher animating the task leash, and
-     * SystemUI resizing the docked stack, which resizes the task), we currently only set the
-     * minimized mode, and not the inverse.
-     * TODO: Synchronize the minimize animation with the launcher animation
-     */
-    public void setSplitScreenMinimizedForTransaction(boolean minimized) {
-        if (mSplitScreenMinimized || !minimized) {
-            return;
-        }
-        mSplitScreenMinimized = minimized;
-        mExecutorService.submit(() -> {
-            RecentsAnimationControllerCompat controller = mController;
-            TraceHelper.partitionSection("RecentsController",
-                    "Setting minimize dock on " + controller);
-            if (controller != null) {
-                controller.setSplitScreenMinimized(minimized);
-            }
-        });
-    }
-
-    public void hideCurrentInputMethod() {
-        mExecutorService.submit(() -> {
-            RecentsAnimationControllerCompat controller = mController;
-            TraceHelper.partitionSection("RecentsController",
-                    "Hiding currentinput method on " + controller);
-            if (controller != null) {
-                controller.hideCurrentInputMethod();
-            }
-        });
-    }
-
-    public RecentsAnimationControllerCompat getController() {
-        return mController;
+    public SwipeAnimationTargetSet getController() {
+        return targetSet;
     }
 }
diff --git a/quickstep/src/com/android/quickstep/SwipeSharedState.java b/quickstep/src/com/android/quickstep/SwipeSharedState.java
index 15914ba..7c6638a 100644
--- a/quickstep/src/com/android/quickstep/SwipeSharedState.java
+++ b/quickstep/src/com/android/quickstep/SwipeSharedState.java
@@ -15,6 +15,9 @@
  */
 package com.android.quickstep;
 
+import android.util.Log;
+
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.Preconditions;
 import com.android.quickstep.util.RecentsAnimationListenerSet;
 import com.android.quickstep.util.SwipeAnimationTargetSet;
@@ -25,23 +28,35 @@
  */
 public class SwipeSharedState implements SwipeAnimationListener {
 
+    private final OverviewComponentObserver mOverviewComponentObserver;
+
     private RecentsAnimationListenerSet mRecentsAnimationListener;
     private SwipeAnimationTargetSet mLastAnimationTarget;
+
     private boolean mLastAnimationCancelled = false;
+    private boolean mLastAnimationRunning = false;
 
     public boolean canGestureBeContinued;
     public boolean goingToLauncher;
 
+    public SwipeSharedState(OverviewComponentObserver overviewComponentObserver) {
+        mOverviewComponentObserver = overviewComponentObserver;
+    }
+
     @Override
     public final void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) {
         mLastAnimationTarget = targetSet;
+
         mLastAnimationCancelled = false;
+        mLastAnimationRunning = true;
     }
 
     @Override
     public final void onRecentsAnimationCanceled() {
         mLastAnimationTarget = null;
+
         mLastAnimationCancelled = true;
+        mLastAnimationRunning = false;
     }
 
     private void clearListenerState() {
@@ -51,12 +66,31 @@
         mRecentsAnimationListener = null;
         mLastAnimationTarget = null;
         mLastAnimationCancelled = false;
+        mLastAnimationRunning = false;
+    }
+
+    private void onSwipeAnimationFinished(SwipeAnimationTargetSet targetSet) {
+        if (mLastAnimationTarget == targetSet) {
+            mLastAnimationRunning = false;
+        }
     }
 
     public RecentsAnimationListenerSet newRecentsAnimationListenerSet() {
         Preconditions.assertUIThread();
+
+        if (mLastAnimationRunning) {
+            String msg = "New animation started before completing old animation";
+            if (FeatureFlags.IS_DOGFOOD_BUILD) {
+                throw new IllegalArgumentException(msg);
+            } else {
+                Log.e("SwipeSharedState", msg, new Exception());
+            }
+        }
+
         clearListenerState();
-        mRecentsAnimationListener = new RecentsAnimationListenerSet();
+        mRecentsAnimationListener = new RecentsAnimationListenerSet(mOverviewComponentObserver
+                .getActivityControlHelper().shouldMinimizeSplitScreen(),
+                this::onSwipeAnimationFinished);
         mRecentsAnimationListener.addListener(this);
         return mRecentsAnimationListener;
     }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 74ac1c6..0ccd141 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -37,6 +37,8 @@
 import android.view.MotionEvent;
 
 import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.util.LooperExecutor;
+import com.android.launcher3.util.UiThreadHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -55,6 +57,9 @@
 public class TouchInteractionService extends Service {
 
     public static final MainThreadExecutor MAIN_THREAD_EXECUTOR = new MainThreadExecutor();
+    public static final LooperExecutor BACKGROUND_EXECUTOR =
+            new LooperExecutor(UiThreadHelper.getBackgroundLooper());
+
     public static final TouchInteractionLog TOUCH_INTERACTION_LOG = new TouchInteractionLog();
 
     public static final int EDGE_NAV_BAR = 1 << 8;
@@ -174,7 +179,7 @@
         mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this);
         mOverviewCallbacks = OverviewCallbacks.get(this);
         mTaskOverlayFactory = TaskOverlayFactory.INSTANCE.get(this);
-        mSwipeSharedState = new SwipeSharedState();
+        mSwipeSharedState = new SwipeSharedState(mOverviewComponentObserver);
         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
         mInputConsumer.registerInputConsumer();
 
@@ -249,10 +254,8 @@
                     mOverviewComponentObserver.getActivityControlHelper();
             boolean shouldDefer = activityControl.deferStartingActivity(mActiveNavBarRegion, event);
             return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
-                    mOverviewComponentObserver.getOverviewIntent(),
-                    mOverviewComponentObserver.getActivityControlHelper(),
-                    shouldDefer, mOverviewCallbacks,
-                    mTaskOverlayFactory, mInputConsumer,
+                    mOverviewComponentObserver.getOverviewIntent(), activityControl,
+                    shouldDefer, mOverviewCallbacks, mTaskOverlayFactory, mInputConsumer,
                     this::onConsumerInactive, mSwipeSharedState);
         }
     }
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 67dcc78..890bf18 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -99,7 +99,6 @@
 import com.android.systemui.shared.recents.utilities.RectFEvaluator;
 import com.android.systemui.shared.system.InputConsumerController;
 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.SyncRtSurfaceTransactionApplierCompat;
 import com.android.systemui.shared.system.WindowCallbacksCompat;
@@ -115,7 +114,7 @@
         implements SwipeAnimationListener, OnApplyWindowInsetsListener {
     private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
 
-    private static final String[] STATE_NAMES = DEBUG_STATES ? new String[20] : null;
+    private static final String[] STATE_NAMES = DEBUG_STATES ? new String[19] : null;
 
     private static int getFlagForIndex(int index, String name) {
         if (DEBUG_STATES) {
@@ -347,6 +346,9 @@
                 | STATE_SCALED_CONTROLLER_LAST_TASK,
                 this::notifyTransitionCancelled);
 
+        mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
+                mRecentsAnimationWrapper::enableInputConsumer);
+
         if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             mStateCallback.addChangeHandler(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
                             | STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
@@ -595,7 +597,7 @@
     private void updateFinalShift() {
         float shift = mCurrentShift.value;
 
-        RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
+        SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController();
         if (controller != null) {
             float offsetX = 0;
             if (mRecentsView != null) {
@@ -610,12 +612,8 @@
                     .setSyncTransactionApplier(mSyncTransactionApplier);
             mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet,
                     mTransformParams);
-
-            boolean passedThreshold = shift > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
-            mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold);
-            if (mActivityControlHelper.shouldMinimizeSplitScreen()) {
-                mRecentsAnimationWrapper.setSplitScreenMinimizedForTransaction(passedThreshold);
-            }
+            mRecentsAnimationWrapper.setWindowThresholdCrossed(
+                    shift > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD);
         }
 
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
@@ -694,7 +692,7 @@
         mClipAnimationHelper.prepareAnimation(false /* isOpening */);
         initTransitionEndpoints(dp);
 
-        mRecentsAnimationWrapper.setController(targetSet.controller, targetSet);
+        mRecentsAnimationWrapper.setController(targetSet);
         TOUCH_INTERACTION_LOG.startRecentsAnimationCallback(targetSet.apps.length);
         setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
 
@@ -703,7 +701,7 @@
 
     @Override
     public void onRecentsAnimationCanceled() {
-        mRecentsAnimationWrapper.setController(null, null);
+        mRecentsAnimationWrapper.setController(null);
         mActivityInitListener.unregister();
         setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
         TOUCH_INTERACTION_LOG.cancelRecentsAnimation();
@@ -715,8 +713,6 @@
         mShiftAtGestureStart = mCurrentShift.value;
         setStateOnUiThread(STATE_GESTURE_STARTED);
         mGestureStarted = true;
-        mRecentsAnimationWrapper.hideCurrentInputMethod();
-        mRecentsAnimationWrapper.enableInputConsumer();
     }
 
     /**
@@ -1107,7 +1103,7 @@
             setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
         } else {
             boolean finishTransitionPosted = false;
-            RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
+            SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController();
             if (controller != null) {
                 // Update the screenshot of the task
                 if (mTaskSnapshot == null) {
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAnimationListenerSet.java b/quickstep/src/com/android/quickstep/util/RecentsAnimationListenerSet.java
index 686e74d..62f2183 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsAnimationListenerSet.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsAnimationListenerSet.java
@@ -28,6 +28,7 @@
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
 import java.util.Set;
+import java.util.function.Consumer;
 
 import androidx.annotation.UiThread;
 
@@ -38,6 +39,14 @@
 public class RecentsAnimationListenerSet implements RecentsAnimationListener {
 
     private final Set<SwipeAnimationListener> mListeners = new ArraySet<>();
+    private final boolean mShouldMinimizeSplitScreen;
+    private final Consumer<SwipeAnimationTargetSet> mOnFinishListener;
+
+    public RecentsAnimationListenerSet(boolean shouldMinimizeSplitScreen,
+            Consumer<SwipeAnimationTargetSet> onFinishListener) {
+        mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen;
+        mOnFinishListener = onFinishListener;
+    }
 
     @UiThread
     public void addListener(SwipeAnimationListener listener) {
@@ -56,7 +65,8 @@
             RemoteAnimationTargetCompat[] targets, Rect homeContentInsets,
             Rect minimizedHomeBounds) {
         SwipeAnimationTargetSet targetSet = new SwipeAnimationTargetSet(controller, targets,
-                homeContentInsets, minimizedHomeBounds);
+                homeContentInsets, minimizedHomeBounds, mShouldMinimizeSplitScreen,
+                mOnFinishListener);
         Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), () -> {
             for (SwipeAnimationListener listener : getListeners()) {
                 listener.onRecentsAnimationStart(targetSet);
diff --git a/quickstep/src/com/android/quickstep/util/SwipeAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
index 4f02acf..b682481 100644
--- a/quickstep/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
+++ b/quickstep/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
@@ -15,32 +15,79 @@
  */
 package com.android.quickstep.util;
 
+import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
+import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 
 import android.graphics.Rect;
 
+import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
+import java.util.function.Consumer;
+
 /**
  * Extension of {@link RemoteAnimationTargetSet} with additional information about swipe
  * up animation
  */
 public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet {
 
+    private final boolean mShouldMinimizeSplitScreen;
+    private final Consumer<SwipeAnimationTargetSet> mOnFinishListener;
+
+
     public final RecentsAnimationControllerCompat controller;
     public final Rect homeContentInsets;
     public final Rect minimizedHomeBounds;
 
     public SwipeAnimationTargetSet(RecentsAnimationControllerCompat controller,
             RemoteAnimationTargetCompat[] targets, Rect homeContentInsets,
-            Rect minimizedHomeBounds) {
+            Rect minimizedHomeBounds, boolean shouldMinimizeSplitScreen,
+            Consumer<SwipeAnimationTargetSet> onFinishListener) {
         super(targets, MODE_CLOSING);
         this.controller = controller;
         this.homeContentInsets = homeContentInsets;
         this.minimizedHomeBounds = minimizedHomeBounds;
+        this.mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen;
+        this.mOnFinishListener = onFinishListener;
     }
 
+    public void finishController(boolean toRecents, Runnable callback) {
+        mOnFinishListener.accept(this);
+        BACKGROUND_EXECUTOR.execute(() -> {
+            controller.setInputConsumerEnabled(false);
+            controller.finish(toRecents);
+
+            if (callback != null) {
+                MAIN_THREAD_EXECUTOR.execute(callback);
+            }
+        });
+    }
+
+    public void enableInputConsumer() {
+        BACKGROUND_EXECUTOR.submit(() -> {
+            controller.hideCurrentInputMethod();
+            controller.setInputConsumerEnabled(true);
+        });
+    }
+
+    public void setWindowThresholdCrossed(boolean thresholdCrossed) {
+        BACKGROUND_EXECUTOR.execute(() -> {
+            controller.setAnimationTargetsBehindSystemBars(!thresholdCrossed);
+            if (mShouldMinimizeSplitScreen && thresholdCrossed) {
+                // NOTE: As a workaround for conflicting animations (Launcher animating the task
+                // leash, and SystemUI resizing the docked stack, which resizes the task), we
+                // currently only set the minimized mode, and not the inverse.
+                // TODO: Synchronize the minimize animation with the launcher animation
+                controller.setSplitScreenMinimized(thresholdCrossed);
+            }
+        });
+    }
+
+    public ThumbnailData screenshotTask(int taskId) {
+        return controller != null ? controller.screenshotTask(taskId) : null;
+    }
 
     public interface SwipeAnimationListener {
 
@@ -48,4 +95,9 @@
 
         void onRecentsAnimationCanceled();
     }
+
+    public interface SwipeAnimationFinishListener {
+
+        void onSwipeAnimationFinished(SwipeAnimationTargetSet targetSet);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 0c1867d..5465a0c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -93,13 +93,13 @@
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.SwipeAnimationTargetSet;
 import com.android.quickstep.util.TaskViewDrawable;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.BackgroundExecutor;
 import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowCallbacksCompat;
@@ -1590,7 +1590,7 @@
             return;
         }
 
-        RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
+        SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController();
         if (controller != null) {
             // Update the screenshot of the task
             ThumbnailData taskSnapshot = controller.screenshotTask(mRunningTaskId);