Making the self always follow the vertical progress without any min height limit.
After a certain height, the self fades out, but keeps following the vertical progress.

Eventually the fade-out can be decoupled from vertical progress and tied to the state

Bug: 109829614
Change-Id: I9808ed3fa1730b938196bc6d3518a6d096a13f4c
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index acfc180..ea7d21b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -54,4 +54,6 @@
     <dimen name="clear_all_container_width">168dp</dimen>
 
     <dimen name="shelf_surface_radius">16dp</dimen>
+    <!-- same as vertical_drag_handle_size -->
+    <dimen name="shelf_surface_offset">24dp</dimen>
 </resources>
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index c780b62..d7e527c 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -15,11 +15,11 @@
  */
 package com.android.quickstep.views;
 
-import static android.support.v4.graphics.ColorUtils.compositeColors;
 import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
 
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
 
 import android.content.Context;
 import android.graphics.Canvas;
@@ -32,7 +32,7 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.OverviewState;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ScrimView;
 
@@ -45,22 +45,30 @@
  */
 public class ShelfScrimView extends ScrimView {
 
+    // If the progress is more than this, shelf follows the finger, otherwise it moves faster to
+    // cover the whole screen
+    private static final float SCRIM_CATCHUP_THRESHOLD = 0.2f;
+
     // In transposed layout, we simply draw a flat color.
     private boolean mDrawingFlatColor;
 
     // For shelf mode
     private final int mEndAlpha;
-    private final int mThresholdAlpha;
     private final float mRadius;
     private final float mMaxScrimAlpha;
     private final Paint mPaint;
 
-    // Max vertical progress after which the scrim stops moving.
-    private float mMoveThreshold;
-    // Minimum visible size of the scrim.
-    private int mMinSize;
+    // Mid point where the alpha changes
+    private int mMidAlpha;
+    private float mMidProgress;
 
-    private float mScrimMoveFactor = 0;
+    private float mShiftRange;
+
+    private final float mShelfOffset;
+    private float mTopOffset;
+    private float mShelfTop;
+    private float mShelfTopAtThreshold;
+
     private int mShelfColor;
     private int mRemainingScreenColor;
 
@@ -73,10 +81,10 @@
         mMaxScrimAlpha = OVERVIEW.getWorkspaceScrimAlpha(mLauncher);
 
         mEndAlpha = Color.alpha(mEndScrim);
-        mThresholdAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
         mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius);
         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
+        mShelfOffset = context.getResources().getDimension(R.dimen.shelf_surface_offset);
         // Just assume the easiest UI for now, until we have the proper layout information.
         mDrawingFlatColor = true;
     }
@@ -93,10 +101,15 @@
         mDrawingFlatColor = dp.isVerticalBarLayout();
 
         if (!mDrawingFlatColor) {
-            float swipeLength = OverviewState.getDefaultSwipeHeight(mLauncher);
-            mMoveThreshold = 1 - swipeLength / mLauncher.getAllAppsController().getShiftRange();
-            mMinSize = dp.hotseatBarSizePx + dp.getInsets().bottom;
             mRemainingScreenPathValid = false;
+            mShiftRange = mLauncher.getAllAppsController().getShiftRange();
+
+            mMidProgress = OVERVIEW.getVerticalProgress(mLauncher);
+            mMidAlpha = mMidProgress >= 1 ? 0
+                    : Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha);
+
+            mTopOffset = dp.getInsets().top - mShelfOffset;
+            mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
             updateColors();
         }
         updateDragHandleAlpha();
@@ -107,82 +120,79 @@
     public void updateColors() {
         super.updateColors();
         if (mDrawingFlatColor) {
+            mDragHandleOffset = 0;
             return;
         }
 
-        if (mProgress >= mMoveThreshold) {
-            mScrimMoveFactor = 1;
-
-            if (mProgress >= 1) {
-                mShelfColor = 0;
-            } else {
-                int alpha = Math.round(mThresholdAlpha * ACCEL_2.getInterpolation(
-                        (1 - mProgress) / (1 - mMoveThreshold)));
-                mShelfColor = setAlphaComponent(mEndScrim, alpha);
-            }
-
-            mRemainingScreenColor = 0;
-        } else if (mProgress <= 0) {
-            mScrimMoveFactor = 0;
-            mShelfColor = mCurrentFlatColor;
-            mRemainingScreenColor = 0;
-
+        mDragHandleOffset = mShelfOffset - mDragHandleSize;
+        if (mProgress >= SCRIM_CATCHUP_THRESHOLD) {
+            mShelfTop = mShiftRange * mProgress + mTopOffset;
         } else {
-            mScrimMoveFactor = mProgress / mMoveThreshold;
-            mRemainingScreenColor = setAlphaComponent(mScrimColor,
-                    Math.round((1 - mScrimMoveFactor) * mMaxScrimAlpha * 255));
+            mShelfTop = Utilities.mapRange(mProgress / SCRIM_CATCHUP_THRESHOLD, -mRadius,
+                    mShelfTopAtThreshold);
+        }
 
-            // Merge the remainingScreenColor and shelfColor in one to avoid overdraw.
-            int alpha = mEndAlpha - Math.round((mEndAlpha - mThresholdAlpha) * mScrimMoveFactor);
-            mShelfColor = compositeColors(setAlphaComponent(mEndScrim, alpha),
-                    mRemainingScreenColor);
+        if (mProgress >= 1) {
+            mRemainingScreenColor = 0;
+            mShelfColor = 0;
+        } else if (mProgress >= mMidProgress) {
+            mRemainingScreenColor = 0;
+
+            int alpha = Math.round(Utilities.mapToRange(
+                    mProgress, mMidProgress, 1, mMidAlpha, 0, ACCEL));
+            mShelfColor = setAlphaComponent(mEndScrim, alpha);
+        } else {
+            mDragHandleOffset += mShiftRange * (mMidProgress - mProgress);
+
+            int alpha = Math.round(
+                    Utilities.mapToRange(mProgress, (float) 0, mMidProgress, (float) mEndAlpha,
+                            (float) mMidAlpha, LINEAR));
+            mShelfColor = setAlphaComponent(mEndScrim, alpha);
+
+            int remainingScrimAlpha = Math.round(
+                    Utilities.mapToRange(mProgress, (float) 0, mMidProgress, mMaxScrimAlpha,
+                            (float) 0, LINEAR));
+            mRemainingScreenColor = setAlphaComponent(mScrimColor, remainingScrimAlpha);
         }
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
-        float translate = drawBackground(canvas);
-
-        if (mDragHandle != null) {
-            canvas.translate(0, -translate);
-            mDragHandle.draw(canvas);
-            canvas.translate(0, translate);
-        }
+        drawBackground(canvas);
+        drawDragHandle(canvas);
     }
 
-    private float drawBackground(Canvas canvas) {
+    private void drawBackground(Canvas canvas) {
         if (mDrawingFlatColor) {
             if (mCurrentFlatColor != 0) {
                 canvas.drawColor(mCurrentFlatColor);
             }
-            return 0;
+            return;
         }
 
-        if (mShelfColor == 0) {
-            return 0;
-        } else if (mScrimMoveFactor <= 0) {
+        if (Color.alpha(mShelfColor) == 0) {
+            return;
+        } else if (mProgress <= 0) {
             canvas.drawColor(mShelfColor);
-            return getHeight();
+            return;
         }
 
-        float minTop = getHeight() - mMinSize;
-        float top = minTop * mScrimMoveFactor - mDragHandleSize;
-
+        int height = getHeight();
+        int width = getWidth();
         // Draw the scrim over the remaining screen if needed.
         if (mRemainingScreenColor != 0) {
             if (!mRemainingScreenPathValid) {
                 mTempPath.reset();
                 // Using a arbitrary '+10' in the bottom to avoid any left-overs at the
                 // corners due to rounding issues.
-                mTempPath.addRoundRect(0, minTop, getWidth(), getHeight() + mRadius + 10,
+                mTempPath.addRoundRect(0, height - mRadius, width, height + mRadius + 10,
                         mRadius, mRadius, Direction.CW);
-
                 mRemainingScreenPath.reset();
-                mRemainingScreenPath.addRect(0, 0, getWidth(), getHeight(), Direction.CW);
+                mRemainingScreenPath.addRect(0, 0, width, height, Direction.CW);
                 mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE);
             }
 
-            float offset = minTop - top;
+            float offset = height - mRadius - mShelfTop;
             canvas.translate(0, -offset);
             mPaint.setColor(mRemainingScreenColor);
             canvas.drawPath(mRemainingScreenPath, mPaint);
@@ -190,8 +200,6 @@
         }
 
         mPaint.setColor(mShelfColor);
-        canvas.drawRoundRect(0, top, getWidth(), getHeight() + mRadius,
-                mRadius, mRadius, mPaint);
-        return minTop - mDragHandleSize - top;
+        canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint);
     }
 }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 5355c5e..7fe8d35 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -48,6 +48,7 @@
 import android.util.Pair;
 import android.util.TypedValue;
 import android.view.View;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.config.FeatureFlags;
 
@@ -281,13 +282,14 @@
      * @param toMax The upper bound of the range that t is being mapped to.
      * @return The mapped value of t.
      */
-    public static float mapToRange(float t, float fromMin, float fromMax, float toMin, float toMax) {
+    public static float mapToRange(float t, float fromMin, float fromMax, float toMin, float toMax,
+            Interpolator interpolator) {
         if (fromMin == fromMax || toMin == toMax) {
             Log.e(TAG, "mapToRange: range has 0 length");
             return toMin;
         }
         float progress = Math.abs(t - fromMin) / Math.abs(fromMax - fromMin);
-        return mapRange(progress, toMin, toMax);
+        return mapRange(interpolator.getInterpolation(progress), toMin, toMax);
     }
 
     public static float mapRange(float value, float min, float max) {
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index d17572e..a4cba4f 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -158,7 +158,6 @@
      */
     public static Interpolator mapToProgress(Interpolator interpolator, float lowerBound,
             float upperBound) {
-        return t -> Utilities.mapToRange(interpolator.getInterpolation(t), 0, 1,
-                lowerBound, upperBound);
+        return t -> Utilities.mapRange(interpolator.getInterpolation(t), lowerBound, upperBound);
     }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 6e3ef07..7066980 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -109,6 +109,7 @@
     protected int mEndFlatColorAlpha;
 
     protected final int mDragHandleSize;
+    protected float mDragHandleOffset;
     private final Rect mDragHandleBounds;
     private final RectF mHitRect = new RectF();
 
@@ -223,8 +224,14 @@
         if (mCurrentFlatColor != 0) {
             canvas.drawColor(mCurrentFlatColor);
         }
+        drawDragHandle(canvas);
+    }
+
+    protected void drawDragHandle(Canvas canvas) {
         if (mDragHandle != null) {
+            canvas.translate(0, -mDragHandleOffset);
             mDragHandle.draw(canvas);
+            canvas.translate(0, mDragHandleOffset);
         }
     }
 
@@ -237,20 +244,23 @@
 
             final Drawable drawable = mDragHandle;
             mDragHandle = null;
-            drawable.setBounds(mDragHandleBounds);
 
-            Rect topBounds = new Rect(mDragHandleBounds);
-            topBounds.offset(0, -mDragHandleBounds.height() / 2);
+            Rect bounds = new Rect(mDragHandleBounds);
+            bounds.offset(0, -(int) mDragHandleOffset);
+            drawable.setBounds(bounds);
 
-            Rect invalidateRegion = new Rect(mDragHandleBounds);
+            Rect topBounds = new Rect(bounds);
+            topBounds.offset(0, -bounds.height() / 2);
+
+            Rect invalidateRegion = new Rect(bounds);
             invalidateRegion.top = topBounds.top;
 
             Keyframe frameTop = Keyframe.ofObject(0.6f, topBounds);
             frameTop.setInterpolator(DEACCEL);
-            Keyframe frameBot = Keyframe.ofObject(1, mDragHandleBounds);
+            Keyframe frameBot = Keyframe.ofObject(1, bounds);
             frameBot.setInterpolator(ACCEL);
             PropertyValuesHolder holder = PropertyValuesHolder .ofKeyframe("bounds",
-                    Keyframe.ofObject(0, mDragHandleBounds), frameTop, frameBot);
+                    Keyframe.ofObject(0, bounds), frameTop, frameBot);
             holder.setEvaluator(new RectEvaluator());
 
             ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, holder);