[automerger] Updating the task swipe-down UI am: 7d2e40912e

Change-Id: I4fe2c0ca637b7952c78883a1517656b441badde5
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 5a8ce16..3d64cc8 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.support.annotation.AnyThread;
 import android.util.AttributeSet;
 import android.view.View;
 
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index 9276d238..9dd83d2 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -15,15 +15,23 @@
  */
 package com.android.quickstep.util;
 
+import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Matrix.ScaleToFit;
 import android.graphics.Rect;
 import android.graphics.RectF;
 
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.views.TaskThumbnailView;
 import com.android.systemui.shared.recents.utilities.RectFEvaluator;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.system.TransactionCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 
 /**
  * Utility class to handle window clip animation
@@ -126,4 +134,73 @@
             mTargetRect.offset(offsetX, offsetY);
         }
     }
+
+    public void fromTaskThumbnailView(TaskThumbnailView ttv) {
+        BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext());
+        BaseDragLayer dl = activity.getDragLayer();
+
+        int[] pos = new int[2];
+        dl.getLocationOnScreen(pos);
+        mHomeStackBounds.set(0, 0, dl.getWidth(), dl.getHeight());
+        mHomeStackBounds.offset(pos[0], pos[1]);
+
+        if (activity.isInMultiWindowModeCompat()) {
+            // TODO: Fetch multi-window target bounds from system-ui
+            DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile();
+            // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
+            // account for system insets
+            int taskWidth = fullDp.availableWidthPx;
+            int taskHeight = fullDp.availableHeightPx;
+            int halfDividerSize = activity.getResources()
+                    .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
+
+            Rect insets = new Rect();
+            WindowManagerWrapper.getInstance().getStableInsets(insets);
+            if (fullDp.isLandscape) {
+                taskWidth = taskWidth / 2 - halfDividerSize;
+            } else {
+                taskHeight = taskHeight / 2 - halfDividerSize;
+            }
+
+            mSourceStackBounds.set(0, 0, taskWidth, taskHeight);
+            // Align the task to bottom right (probably not true for seascape).
+            mSourceStackBounds.offset(insets.left + fullDp.availableWidthPx - taskWidth,
+                    insets.top + fullDp.availableHeightPx - taskHeight);
+        } else {
+            mSourceStackBounds.set(mHomeStackBounds);
+            mSourceInsets.set(activity.getDeviceProfile().getInsets());
+        }
+
+        Rect targetRect = new Rect();
+        dl.getDescendantRectRelativeToSelf(ttv, targetRect);
+        updateTargetRect(targetRect);
+
+        // Transform the clip relative to the target rect.
+        float scale = mTargetRect.width() / mSourceRect.width();
+        mSourceWindowClipInsets.left = mSourceWindowClipInsets.left * scale;
+        mSourceWindowClipInsets.top = mSourceWindowClipInsets.top * scale;
+        mSourceWindowClipInsets.right = mSourceWindowClipInsets.right * scale;
+        mSourceWindowClipInsets.bottom = mSourceWindowClipInsets.bottom * scale;
+    }
+
+    public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) {
+        RectF currentRect;
+        synchronized (mTargetRect) {
+            currentRect =  mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
+        }
+
+        canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left,
+                mSourceStackBounds.top - mHomeStackBounds.top);
+        mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL);
+        canvas.concat(mTmpMatrix);
+        canvas.translate(mTargetRect.left, mTargetRect.top);
+
+        float insetProgress = (1 - progress);
+        ttv.drawOnCanvas(canvas,
+                -mSourceWindowClipInsets.left * insetProgress,
+                -mSourceWindowClipInsets.top * insetProgress,
+                ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress,
+                ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress,
+                ttv.getCornerRadius() * progress);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java b/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java
new file mode 100644
index 0000000..0fa0023
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.animation.TimeInterpolator;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.util.FloatProperty;
+import android.widget.ImageView;
+
+import com.android.launcher3.Utilities;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskView;
+
+public class TaskViewDrawable extends Drawable {
+
+    public static FloatProperty<TaskViewDrawable> PROGRESS =
+            new FloatProperty<TaskViewDrawable>("progress") {
+                @Override
+                public void setValue(TaskViewDrawable taskViewDrawable, float v) {
+                    taskViewDrawable.setProgress(v);
+                }
+
+                @Override
+                public Float get(TaskViewDrawable taskViewDrawable) {
+                    return taskViewDrawable.mProgress;
+                }
+            };
+
+    private static final TimeInterpolator ICON_SIZE_INTERPOLATOR =
+            (t) -> (Math.max(t, 0.3f) - 0.3f) / 0.7f;
+
+    private final RecentsView mParent;
+    private final ImageView mIconView;
+    private final int[] mIconPos;
+
+    private final TaskThumbnailView mThumbnailView;
+
+    private final ClipAnimationHelper mClipAnimationHelper;
+
+    private float mProgress = 1;
+
+    public TaskViewDrawable(TaskView tv, RecentsView parent) {
+        mParent = parent;
+        mIconView = tv.getIconView();
+        mIconPos = new int[2];
+        Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
+
+        mThumbnailView = tv.getThumbnail();
+        mClipAnimationHelper = new ClipAnimationHelper();
+        mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView);
+    }
+
+    public void setProgress(float progress) {
+        mProgress = progress;
+        mParent.invalidate();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        canvas.save();
+        canvas.translate(mParent.getScrollX(), mParent.getScrollY());
+        mClipAnimationHelper.drawForProgress(mThumbnailView, canvas, mProgress);
+        canvas.restore();
+
+        canvas.save();
+        canvas.translate(mIconPos[0], mIconPos[1]);
+        float scale = ICON_SIZE_INTERPOLATOR.getInterpolation(mProgress);
+        canvas.scale(scale, scale, mIconView.getWidth() / 2, mIconView.getHeight() / 2);
+        mIconView.draw(canvas);
+        canvas.restore();
+    }
+
+    @Override
+    public void setAlpha(int i) { }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) { }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 280fd46..90b4bd2 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -130,4 +130,12 @@
     protected void getTaskSize(DeviceProfile dp, Rect outRect) {
         LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
     }
+
+    @Override
+    protected void onTaskLaunched(boolean success) {
+        if (success) {
+            mActivity.getStateManager().goToState(NORMAL, false /* animate */);
+        }
+        super.onTaskLaunched(success);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5e55590..6a2df0b 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -66,10 +66,10 @@
 import com.android.launcher3.util.Themes;
 import com.android.quickstep.OverviewCallbacks;
 import com.android.quickstep.QuickScrubController;
-import com.android.quickstep.RecentsAnimationInterpolator;
 import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskUtils;
+import com.android.quickstep.util.TaskViewDrawable;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.shared.recents.model.RecentsTaskLoader;
 import com.android.systemui.shared.recents.model.Task;
@@ -79,6 +79,7 @@
 import com.android.systemui.shared.system.TaskStackChangeListener;
 
 import java.util.ArrayList;
+import java.util.function.Consumer;
 
 /**
  * A list of recent tasks.
@@ -522,7 +523,6 @@
         mHasVisibleTaskData.clear();
     }
 
-
     protected abstract void onAllTasksRemoved();
 
     public void reset() {
@@ -1060,23 +1060,27 @@
             return new PendingAnimation(anim);
         }
 
-        final RecentsAnimationInterpolator recentsInterpolator = tv.getRecentsInterpolator();
-        ValueAnimator targetViewAnim = ValueAnimator.ofFloat(0, 1);
-        targetViewAnim.addUpdateListener((animation) -> {
-            float percent = animation.getAnimatedFraction();
-            TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
-            tv.setScaleX(tw.taskScale);
-            tv.setScaleY(tw.taskScale);
-            tv.setTranslationX(tw.taskX);
-            tv.setTranslationY(tw.taskY);
-        });
-        anim.play(targetViewAnim);
+        tv.setVisibility(INVISIBLE);
+        TaskViewDrawable drawable = new TaskViewDrawable(tv, this);
+        getOverlay().add(drawable);
+
+        ObjectAnimator drawableAnim =
+                ObjectAnimator.ofFloat(drawable, TaskViewDrawable.PROGRESS, 1, 0);
+        drawableAnim.setInterpolator(LINEAR);
+
+        anim.play(drawableAnim);
         anim.setDuration(duration);
 
+        Consumer<Boolean> onTaskLaunchFinish = (r) -> {
+            onTaskLaunched(r);
+            tv.setVisibility(VISIBLE);
+            getOverlay().remove(drawable);
+        };
+
         mPendingAnimation = new PendingAnimation(anim);
         mPendingAnimation.addEndListener((onEndListener) -> {
             if (onEndListener.isSuccess) {
-                tv.launchTask(false);
+                tv.launchTask(false, onTaskLaunchFinish, getHandler());
                 Task task = tv.getTask();
                 if (task != null) {
                     mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
@@ -1084,13 +1088,17 @@
                             TaskUtils.getComponentKeyForTask(task.key));
                 }
             } else {
-                resetTaskVisuals();
+                onTaskLaunchFinish.accept(false);
             }
             mPendingAnimation = null;
         });
         return mPendingAnimation;
     }
 
+    protected void onTaskLaunched(boolean success) {
+        resetTaskVisuals();
+    }
+
     @Override
     protected void notifyPageSwitchListener(int prevPage) {
         super.notifyPageSwitchListener(prevPage);
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 2f7199b..592166d 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -143,22 +143,28 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
+        drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
+    }
+
+    public float getCornerRadius() {
+        return mCornerRadius;
+    }
+
+    public void drawOnCanvas(Canvas canvas, float x, float y, float width, float height,
+            float cornerRadius) {
+        // Always draw the background since the snapshots may be translucent
+        canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mBackgroundPaint);
         if (mTask == null) {
             return;
         }
-        int width = getMeasuredWidth();
-        int height = getMeasuredHeight();
-
-        // Always draw the background since the snapshots may be translucent
-        canvas.drawRoundRect(0, 0, width, height, mCornerRadius, mCornerRadius, mBackgroundPaint);
         if (!mTask.isLocked) {
             if (mClipBottom > 0) {
                 canvas.save();
-                canvas.clipRect(0, 0, width, mClipBottom);
-                canvas.drawRoundRect(0, 0, width, height, mCornerRadius, mCornerRadius, mPaint);
+                canvas.clipRect(x, y, width, mClipBottom);
+                canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
                 canvas.restore();
             } else {
-                canvas.drawRoundRect(0, 0, width, height, mCornerRadius, mCornerRadius, mPaint);
+                canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 2c1318c..b32d8dd 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -131,6 +131,10 @@
         return mSnapshotView;
     }
 
+    public ImageView getIconView() {
+        return mIconView;
+    }
+
     public void launchTask(boolean animate) {
         launchTask(animate, null, null);
     }