Handle transition from multi-window

- Make use of app/home insets and minimized home size to calculate the
  proper clipping and target bounds for the task view in home.

Test: Swipe up when in multiwindow

Change-Id: Ibef7a6dc319ded7867ee559dd31c5e87fd76cadb
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index d230de6..74d3cba 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
index 2a7e5c4..fbdbe7a 100644
--- a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
@@ -42,12 +42,6 @@
 
     @Override
     public void setInsets(Rect insets) {
-        requestLayout();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
         if (mHandler != null) {
             mHandler.onLauncherLayoutChanged();
         }
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 86e28f2..61d4790 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -279,10 +279,11 @@
                 new RecentsAnimationListener() {
                     public void onAnimationStart(
                             RecentsAnimationControllerCompat controller,
-                            RemoteAnimationTargetCompat[] apps) {
+                            RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
+                            Rect minimizedHomeBounds) {
                         if (mInteractionHandler == handler) {
-                            handler.setRecentsAnimation(controller, apps);
-
+                            handler.setRecentsAnimation(controller, apps, homeContentInsets,
+                                    minimizedHomeBounds);
                         } else {
                             controller.finish(false /* toHome */);
                         }
@@ -290,7 +291,7 @@
 
                     public void onAnimationCanceled() {
                         if (mInteractionHandler == handler) {
-                            handler.setRecentsAnimation(null, null);
+                            handler.setRecentsAnimation(null, null, null, null);
                         }
                     }
                 }, null, null);
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 028af9a..ea6003e 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -34,6 +34,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Handler;
@@ -91,10 +92,23 @@
 
     private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
 
-    private final Rect mStableInsets = new Rect();
+    // The bounds of the source app in device coordinates
+    private final Rect mSourceStackBounds = new Rect();
+    // The insets of the source app
+    private final Rect mSourceInsets = new Rect();
+    // The source app bounds with the source insets applied, in the source app window coordinates
     private final Rect mSourceRect = new Rect();
+    // The insets to be used for clipping the app window, which can be larger than mSourceInsets
+    // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
+    // app window coordinates.
+    private final Rect mSourceWindowClipInsets = new Rect();
+    // The bounds of launcher (not including insets) in device coordinates
+    private final Rect mHomeStackBounds = new Rect();
+    // The bounds of the task view in launcher window coordinates
     private final Rect mTargetRect = new Rect();
+    // The interpolated rect from the source app rect to the target rect
     private final Rect mCurrentRect = new Rect();
+    // The clip rect in source app window coordinates
     private final Rect mClipRect = new Rect();
     private final RectEvaluator mRectEvaluator = new RectEvaluator(mCurrentRect);
     private DeviceProfile mDp;
@@ -135,16 +149,6 @@
     WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) {
         mContext = context;
         mRunningTaskId = runningTaskInfo.id;
-
-        WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
-
-        DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
-        // TODO: If in multi window mode, dp = dp.getMultiWindowProfile()
-        dp = dp.copy(mContext);
-        // TODO: Use different insets for multi-window mode
-        dp.updateInsets(mStableInsets);
-
-        initTransitionEndpoints(dp);
         initStateCallbacks();
     }
 
@@ -187,13 +191,33 @@
 
     private void initTransitionEndpoints(DeviceProfile dp) {
         mDp = dp;
-        RecentsView.getPageRect(dp, mContext, mTargetRect);
-        mSourceRect.set(0, 0, dp.widthPx - mStableInsets.left - mStableInsets.right,
-                dp.heightPx - mStableInsets.top - mStableInsets.bottom);
 
-        mTransitionDragLength = dp.hotseatBarSizePx + (dp.isVerticalBarLayout()
-                ? (dp.hotseatBarSidePaddingPx + (dp.isSeascape() ? mStableInsets.left : mStableInsets.right))
-                : mStableInsets.bottom);
+        mSourceRect.set(0, 0, dp.widthPx - mSourceInsets.left - mSourceInsets.right,
+                dp.heightPx - mSourceInsets.top - mSourceInsets.bottom);
+        RecentsView.getPageRect(dp, mContext, mTargetRect);
+        mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
+                mHomeStackBounds.top - mSourceStackBounds.top);
+
+        // Calculate the clip based on the target rect (since the content insets and the
+        // launcher insets may differ, so the aspect ratio of the target rect can differ
+        // from the source rect. The difference between the target rect (scaled to the
+        // source rect) is the amount to clip on each edge.
+        Rect scaledTargetRect = new Rect(mTargetRect);
+        Utilities.scaleRectAboutCenter(scaledTargetRect,
+                (float) mSourceRect.width() / mTargetRect.width());
+        scaledTargetRect.offsetTo(mSourceInsets.left, mSourceInsets.top);
+        mSourceWindowClipInsets.set(scaledTargetRect.left, scaledTargetRect.top,
+                mDp.widthPx - scaledTargetRect.right,
+                mDp.heightPx - scaledTargetRect.bottom);
+
+        Rect targetInsets = dp.getInsets();
+        mTransitionDragLength = dp.hotseatBarSizePx;
+        if (dp.isVerticalBarLayout()) {
+            int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
+            mTransitionDragLength += dp.hotseatBarSidePaddingPx + hotseatInset;
+        } else {
+            mTransitionDragLength += targetInsets.bottom;
+        }
     }
 
     private long getFadeInDuration() {
@@ -268,18 +292,14 @@
                 }
             });
             state = STATE_LAUNCHER_PRESENT;
+
+            // Optimization, hide the all apps view to prevent layout while initializing
+            mLauncher.getAppsView().setVisibility(View.GONE);
         }
 
         mRecentsView.showTask(mRunningTaskId);
         mLauncherLayoutListener.open();
 
-        // Optimization
-        // We are using the internal device profile as launcher may not have got the insets yet.
-        if (!mDp.isVerticalBarLayout()) {
-            // All-apps search box is visible in vertical bar layout.
-            mLauncher.getAppsView().setVisibility(View.GONE);
-        }
-
         mStateCallback.setState(state);
         return true;
     }
@@ -351,7 +371,6 @@
      * Called by {@link #mLauncherLayoutListener} when launcher layout changes
      */
     public void onLauncherLayoutChanged() {
-        WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
         initTransitionEndpoints(mLauncher.getDeviceProfile());
 
         if (!mWasLauncherAlreadyVisible) {
@@ -392,14 +411,14 @@
                 mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
                 float scale = (float) mCurrentRect.width() / mSourceRect.width();
 
-                mClipRect.left = mSourceRect.left;
-                mClipRect.top = (int) (mStableInsets.top * shift);
-                mClipRect.bottom = (int) (mDp.heightPx - (mStableInsets.bottom * shift));
-                mClipRect.right = mSourceRect.right;
+                mClipRect.left = (int) (mSourceWindowClipInsets.left * shift);
+                mClipRect.top = (int) (mSourceWindowClipInsets.top * shift);
+                mClipRect.right = (int) (mDp.widthPx - (mSourceWindowClipInsets.right * shift));
+                mClipRect.bottom = (int) (mDp.heightPx - (mSourceWindowClipInsets.bottom * shift));
 
                 mTmpMatrix.setScale(scale, scale, 0, 0);
-                mTmpMatrix.postTranslate(mCurrentRect.left - mStableInsets.left * scale * shift,
-                        mCurrentRect.top - mStableInsets.top * scale * shift);
+                mTmpMatrix.postTranslate(mCurrentRect.left - mSourceInsets.left * scale * shift,
+                        mCurrentRect.top - mSourceInsets.top * scale * shift);
                 TransactionCompat transaction = new TransactionCompat();
                 for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
                     if (app.mode == MODE_CLOSING) {
@@ -423,7 +442,42 @@
     }
 
     public void setRecentsAnimation(RecentsAnimationControllerCompat controller,
-            RemoteAnimationTargetCompat[] apps) {
+            RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, Rect minimizedHomeBounds) {
+        if (apps != null) {
+            // Use the top closing app to determine the insets for the animation
+            for (RemoteAnimationTargetCompat target : apps) {
+                if (target.mode == MODE_CLOSING) {
+                    DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
+                    if (minimizedHomeBounds != null) {
+                        mHomeStackBounds.set(minimizedHomeBounds);
+                        dp = dp.getMultiWindowProfile(mContext,
+                                new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
+                        dp.updateInsets(homeContentInsets);
+                    } else {
+                        mHomeStackBounds.set(new Rect(0, 0, dp.widthPx, dp.heightPx));
+                        // TODO: Workaround for an existing issue where the home content insets are
+                        // not valid immediately after rotation, just use the stable insets for now
+                        Rect insets = new Rect();
+                        WindowManagerWrapper.getInstance().getStableInsets(insets);
+                        dp.updateInsets(insets);
+                    }
+
+                    // Initialize the start and end animation bounds
+                    // TODO: Remove once platform is updated
+                    try {
+                        mSourceInsets.set(target.getContentInsets());
+                    } catch (Error e) {
+                        // TODO: Remove once platform is updated, use stable insets as fallback
+                        WindowManagerWrapper.getInstance().getStableInsets(mSourceInsets);
+                    }
+                    mSourceStackBounds.set(target.sourceContainerBounds);
+
+                    initTransitionEndpoints(dp);
+                    break;
+                }
+            }
+        }
+
         mRecentsAnimationWrapper.setController(controller, apps);
         setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
     }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2227bfd..950c7f7 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -217,7 +217,7 @@
         return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape);
     }
 
-    DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
+    public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
         // We take the minimum sizes of this profile and it's multi-window variant to ensure that
         // the system decor is always excluded.
         mwSize.set(Math.min(availableWidthPx, mwSize.x), Math.min(availableHeightPx, mwSize.y));