Merge "Using correct gesture margins in overview" into ub-launcher3-qt-r1-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 72a9da6..e3d622f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -19,12 +19,15 @@
 import static android.os.VibrationEffect.createPredefined;
 
 import static com.android.launcher3.Utilities.postAsyncCallback;
+import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
 import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
 import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
 
+import android.animation.Animator;
 import android.annotation.TargetApi;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
@@ -32,6 +35,7 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
@@ -48,12 +52,19 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.graphics.RotationMode;
+import com.android.launcher3.views.FloatingIconView;
 import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.inputconsumers.InputConsumer;
 import com.android.quickstep.util.ClipAnimationHelper;
 import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
+import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
 import com.android.quickstep.util.SwipeAnimationTargetSet;
 import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
 import com.android.quickstep.views.RecentsView;
@@ -369,9 +380,117 @@
         return TaskView.getCurveScaleForInterpolation(interpolation);
     }
 
+    /**
+     * Creates an animation that transforms the current app window into the home app.
+     * @param startProgress The progress of {@link #mCurrentShift} to start the window from.
+     * @param homeAnimationFactory The home animation factory.
+     */
+    protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
+            HomeAnimationFactory homeAnimationFactory) {
+        final RemoteAnimationTargetSet targetSet = mRecentsAnimationWrapper.targetSet;
+        final RectF startRect = new RectF(mClipAnimationHelper.applyTransform(targetSet,
+                mTransformParams.setProgress(startProgress), false /* launcherOnTop */));
+        final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
+
+        final View floatingView = homeAnimationFactory.getFloatingView();
+        final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
+        RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext.getResources());
+        if (isFloatingIconView) {
+            FloatingIconView fiv = (FloatingIconView) floatingView;
+            anim.addAnimatorListener(fiv);
+            fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
+        }
+
+        AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
+
+        // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
+        // rounding at the end of the animation.
+        float startRadius = mClipAnimationHelper.getCurrentCornerRadius();
+        float endRadius = startRect.width() / 6f;
+        // We want the window alpha to be 0 once this threshold is met, so that the
+        // FolderIconView can be seen morphing into the icon shape.
+        final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
+        anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
+            @Override
+            public void onUpdate(RectF currentRect, float progress) {
+                homeAnim.setPlayFraction(progress);
+
+                float alphaProgress = ACCEL_1_5.getInterpolation(progress);
+                float windowAlpha = Utilities.boundToRange(Utilities.mapToRange(alphaProgress, 0,
+                        windowAlphaThreshold, 1.5f, 0f, Interpolators.LINEAR), 0, 1);
+                mTransformParams.setProgress(progress)
+                        .setCurrentRectAndTargetAlpha(currentRect, windowAlpha);
+                if (isFloatingIconView) {
+                    mTransformParams.setCornerRadius(endRadius * progress + startRadius
+                            * (1f - progress));
+                }
+                mClipAnimationHelper.applyTransform(targetSet, mTransformParams,
+                        false /* launcherOnTop */);
+
+                if (isFloatingIconView) {
+                    ((FloatingIconView) floatingView).update(currentRect, 1f, progress,
+                            windowAlphaThreshold, mClipAnimationHelper.getCurrentCornerRadius(), false);
+                }
+            }
+
+            @Override
+            public void onCancel() {
+                if (isFloatingIconView) {
+                    ((FloatingIconView) floatingView).fastFinish();
+                }
+            }
+        });
+        anim.addAnimatorListener(new AnimationSuccessListener() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                homeAnim.dispatchOnStart();
+            }
+
+            @Override
+            public void onAnimationSuccess(Animator animator) {
+                homeAnim.getAnimationPlayer().end();
+            }
+        });
+        return anim;
+    }
+
     public interface Factory {
 
         BaseSwipeUpHandler newHandler(RunningTaskInfo runningTask,
                 long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask);
     }
+
+    protected interface RunningWindowAnim {
+        void end();
+
+        void cancel();
+
+        static RunningWindowAnim wrap(Animator animator) {
+            return new RunningWindowAnim() {
+                @Override
+                public void end() {
+                    animator.end();
+                }
+
+                @Override
+                public void cancel() {
+                    animator.cancel();
+                }
+            };
+        }
+
+        static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) {
+            return new RunningWindowAnim() {
+                @Override
+                public void end() {
+                    rectFSpringAnim.end();
+                }
+
+                @Override
+                public void cancel() {
+                    rectFSpringAnim.cancel();
+                }
+            };
+        }
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 894edd4..295585e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -151,16 +151,10 @@
             @NonNull
             @Override
             public RectF getWindowTargetRect() {
-                final int halfIconSize = dp.iconSizePx / 2;
-                final float targetCenterX = dp.availableWidthPx / 2f;
-                final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
-
                 if (canUseWorkspaceView) {
                     return iconLocation;
                 } else {
-                    // Fallback to animate to center of screen.
-                    return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
-                            targetCenterX + halfIconSize, targetCenterY + halfIconSize);
+                    return HomeAnimationFactory.getDefaultWindowTargetRect(dp);
                 }
             }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 83e90ed..df37759 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
-import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -27,7 +26,6 @@
 import static com.android.launcher3.util.RaceConditionTracker.ENTER;
 import static com.android.launcher3.util.RaceConditionTracker.EXIT;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
-import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.HIDE;
 import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.PEEK;
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
@@ -52,7 +50,6 @@
 import android.graphics.RectF;
 import android.os.Build;
 import android.os.SystemClock;
-import android.util.Log;
 import android.view.View;
 import android.view.View.OnApplyWindowInsetsListener;
 import android.view.ViewTreeObserver.OnDrawListener;
@@ -68,13 +65,11 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.logging.UserEventDispatcher;
-import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.util.RaceConditionTracker;
 import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.views.FloatingIconView;
 import com.android.quickstep.ActivityControlHelper.AnimationFactory;
 import com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState;
 import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
@@ -83,7 +78,6 @@
 import com.android.quickstep.inputconsumers.OverviewInputConsumer;
 import com.android.quickstep.util.ClipAnimationHelper.TargetAlphaProvider;
 import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.RemoteAnimationTargetSet;
 import com.android.quickstep.util.SwipeAnimationTargetSet;
 import com.android.quickstep.views.LiveTileOverlay;
 import com.android.quickstep.views.RecentsView;
@@ -968,67 +962,15 @@
      * @param startProgress The progress of {@link #mCurrentShift} to start the window from.
      * @param homeAnimationFactory The home animation factory.
      */
-    private RectFSpringAnim createWindowAnimationToHome(float startProgress,
+    @Override
+    protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
             HomeAnimationFactory homeAnimationFactory) {
-        final RemoteAnimationTargetSet targetSet = mRecentsAnimationWrapper.targetSet;
-        final RectF startRect = new RectF(mClipAnimationHelper.applyTransform(targetSet,
-                mTransformParams.setProgress(startProgress), false /* launcherOnTop */));
-        final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
-
-        final View floatingView = homeAnimationFactory.getFloatingView();
-        final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
-        RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mActivity.getResources());
-        if (isFloatingIconView) {
-            FloatingIconView fiv = (FloatingIconView) floatingView;
-            anim.addAnimatorListener(fiv);
-            fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
-        }
-
-        AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
-
-        // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
-        // rounding at the end of the animation.
-        float startRadius = mClipAnimationHelper.getCurrentCornerRadius();
-        float endRadius = startRect.width() / 6f;
-        // We want the window alpha to be 0 once this threshold is met, so that the
-        // FolderIconView can be seen morphing into the icon shape.
-        final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
-        anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
-            @Override
-            public void onUpdate(RectF currentRect, float progress) {
-                homeAnim.setPlayFraction(progress);
-
-                float alphaProgress = ACCEL_1_5.getInterpolation(progress);
-                float windowAlpha = Utilities.boundToRange(Utilities.mapToRange(alphaProgress, 0,
-                        windowAlphaThreshold, 1.5f, 0f, Interpolators.LINEAR), 0, 1);
-                mTransformParams.setProgress(progress)
-                        .setCurrentRectAndTargetAlpha(currentRect, windowAlpha);
-                if (isFloatingIconView) {
-                    mTransformParams.setCornerRadius(endRadius * progress + startRadius
-                            * (1f - progress));
-                }
-                mClipAnimationHelper.applyTransform(targetSet, mTransformParams,
-                        false /* launcherOnTop */);
-
-                if (isFloatingIconView) {
-                    ((FloatingIconView) floatingView).update(currentRect, 1f, progress,
-                            windowAlphaThreshold, mClipAnimationHelper.getCurrentCornerRadius(), false);
-                }
-
-                updateSysUiFlags(Math.max(progress, mCurrentShift.value));
-            }
-
-            @Override
-            public void onCancel() {
-                if (isFloatingIconView) {
-                    ((FloatingIconView) floatingView).fastFinish();
-                }
-            }
-        });
+        RectFSpringAnim anim =
+                super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
+        anim.addOnUpdateListener((r, p) -> updateSysUiFlags(Math.max(p, mCurrentShift.value)));
         anim.addAnimatorListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
-                homeAnim.dispatchOnStart();
                 if (mActivity != null) {
                     mActivity.getRootView().getOverlay().remove(mLiveTileOverlay);
                 }
@@ -1036,7 +978,6 @@
 
             @Override
             public void onAnimationSuccess(Animator animator) {
-                homeAnim.getAnimationPlayer().end();
                 if (mRecentsView != null) {
                     mRecentsView.post(mRecentsView::resetTaskVisuals);
                 }
@@ -1270,38 +1211,4 @@
         return app.isNotInRecents
                 || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
     }
-
-    private interface RunningWindowAnim {
-        void end();
-
-        void cancel();
-
-        static RunningWindowAnim wrap(Animator animator) {
-            return new RunningWindowAnim() {
-                @Override
-                public void end() {
-                    animator.end();
-                }
-
-                @Override
-                public void cancel() {
-                    animator.cancel();
-                }
-            };
-        }
-
-        static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) {
-            return new RunningWindowAnim() {
-                @Override
-                public void end() {
-                    rectFSpringAnim.end();
-                }
-
-                @Override
-                public void cancel() {
-                    rectFSpringAnim.cancel();
-                }
-            };
-        }
-    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java
index 7abf62d..631c34c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java
@@ -18,11 +18,12 @@
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
 import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID;
 import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL;
-import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.NEW_TASK;
 import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
 import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.HOME;
 import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.LAST_TASK;
+import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.NEW_TASK;
 import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.RECENTS;
+import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
@@ -31,10 +32,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.PointF;
+import android.graphics.RectF;
 import android.os.Bundle;
 
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.BaseSwipeUpHandler;
 import com.android.quickstep.MultiStateCallback;
@@ -44,6 +48,7 @@
 import com.android.quickstep.SwipeSharedState;
 import com.android.quickstep.fallback.FallbackRecentsView;
 import com.android.quickstep.util.ObjectWrapper;
+import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.SwipeAnimationTargetSet;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -102,10 +107,10 @@
     private final boolean mRunningOverHome;
     private final boolean mSwipeUpOverHome;
 
-
     private final RunningTaskInfo mRunningTaskInfo;
 
-    private Animator mFinishAnimation;
+    private final PointF mEndVelocityPxPerMs = new PointF(0, 0.5f);
+    private RunningWindowAnim mFinishAnimation;
 
     public FallbackNoButtonInputConsumer(Context context,
             OverviewComponentObserver overviewComponentObserver,
@@ -226,6 +231,8 @@
     @Override
     public void updateFinalShift() {
         mTransformParams.setProgress(mCurrentShift.value);
+        mRecentsAnimationWrapper.setWindowThresholdCrossed(!mInQuickSwitchMode
+                && (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD));
         if (mRecentsAnimationWrapper.targetSet != null) {
             applyTransformUnchecked();
         }
@@ -240,6 +247,7 @@
 
     @Override
     public void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) {
+        mEndVelocityPxPerMs.set(0, velocity.y / 1000);
         if (mInQuickSwitchMode) {
             // For now set it to non-null, it will be reset before starting the animation
             mEndTarget = LAST_TASK;
@@ -288,12 +296,14 @@
         }
     }
 
-
     private void onHandlerInvalidated() {
         mActivityInitListener.unregister();
         if (mGestureEndCallback != null) {
             mGestureEndCallback.run();
         }
+        if (mFinishAnimation != null) {
+            mFinishAnimation.end();
+        }
     }
 
     private void onHandlerInvalidatedWithRecents() {
@@ -364,31 +374,39 @@
         }
 
         float endProgress = mEndTarget.mEndProgress;
-
+        long duration = (long) (mEndTarget.mDurationMultiplier *
+                Math.abs(endProgress - mCurrentShift.value));
+        if (mRecentsView != null) {
+            duration = Math.max(duration, mRecentsView.getScroller().getDuration());
+        }
         if (mCurrentShift.value != endProgress || mInQuickSwitchMode) {
-            AnimatorSet anim = new AnimatorSet();
-            anim.play(mLauncherAlpha.animateToValue(
-                    mLauncherAlpha.value, mEndTarget.mLauncherAlpha));
-            anim.play(mCurrentShift.animateToValue(mCurrentShift.value, endProgress));
-
-
-            long duration = (long) (mEndTarget.mDurationMultiplier *
-                    Math.abs(endProgress - mCurrentShift.value));
-            if (mRecentsView != null) {
-                duration = Math.max(duration, mRecentsView.getScroller().getDuration());
-            }
-
-            anim.setDuration(duration);
-            anim.addListener(new AnimationSuccessListener() {
+            AnimationSuccessListener endListener = new AnimationSuccessListener() {
 
                 @Override
                 public void onAnimationSuccess(Animator animator) {
                     finishAnimationTargetSetAnimationComplete();
                     mFinishAnimation = null;
                 }
-            });
-            anim.start();
-            mFinishAnimation = anim;
+            };
+
+            if (mEndTarget == HOME && !mRunningOverHome) {
+                RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration);
+                anim.addAnimatorListener(endListener);
+                anim.start(mEndVelocityPxPerMs);
+                mFinishAnimation = RunningWindowAnim.wrap(anim);
+            } else {
+
+                AnimatorSet anim = new AnimatorSet();
+                anim.play(mLauncherAlpha.animateToValue(
+                        mLauncherAlpha.value, mEndTarget.mLauncherAlpha));
+                anim.play(mCurrentShift.animateToValue(mCurrentShift.value, endProgress));
+
+                anim.setDuration(duration);
+                anim.addListener(endListener);
+                anim.start();
+                mFinishAnimation = RunningWindowAnim.wrap(anim);
+            }
+
         } else {
             finishAnimationTargetSetAnimationComplete();
         }
@@ -412,4 +430,26 @@
         mRecentsAnimationWrapper.setController(null);
         setStateOnUiThread(STATE_HANDLER_INVALIDATED);
     }
+
+    /**
+     * Creates an animation that transforms the current app window into the home app.
+     * @param startProgress The progress of {@link #mCurrentShift} to start the window from.
+     */
+    private RectFSpringAnim createWindowAnimationToHome(float startProgress, long duration) {
+        HomeAnimationFactory factory = new HomeAnimationFactory() {
+            @Override
+            public RectF getWindowTargetRect() {
+                return HomeAnimationFactory.getDefaultWindowTargetRect(mDp);
+            }
+
+            @Override
+            public AnimatorPlaybackController createActivityAnimationToHome() {
+                AnimatorSet anim = new AnimatorSet();
+                anim.play(mLauncherAlpha.animateToValue(mLauncherAlpha.value, 1));
+                anim.setDuration(duration);
+                return AnimatorPlaybackController.wrap(anim, duration);
+            }
+        };
+        return createWindowAnimationToHome(startProgress, factory);
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index 9c5cf20..c6eafe6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -237,6 +237,6 @@
     public interface OnUpdateListener {
         void onUpdate(RectF currentRect, float progress);
 
-        void onCancel();
+        default void onCancel() { }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index cd2c9cb..5c9c7d4 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -152,5 +152,15 @@
         default void playAtomicAnimation(float velocity) {
             // No-op
         }
+
+        static RectF getDefaultWindowTargetRect(DeviceProfile dp) {
+            final int halfIconSize = dp.iconSizePx / 2;
+            final float targetCenterX = dp.availableWidthPx / 2f;
+            final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
+            // Fallback to animate to center of screen.
+            return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
+                    targetCenterX + halfIconSize, targetCenterY + halfIconSize);
+        }
+
     }
 }