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
This commit is contained in:
Sunny Goyal 2018-06-08 13:01:04 -07:00
parent 808e7cae66
commit 0f3af75eb0
5 changed files with 91 additions and 70 deletions

View File

@ -54,4 +54,6 @@
<dimen name="clear_all_container_width">168dp</dimen> <dimen name="clear_all_container_width">168dp</dimen>
<dimen name="shelf_surface_radius">16dp</dimen> <dimen name="shelf_surface_radius">16dp</dimen>
<!-- same as vertical_drag_handle_size -->
<dimen name="shelf_surface_offset">24dp</dimen>
</resources> </resources>

View File

@ -15,11 +15,11 @@
*/ */
package com.android.quickstep.views; package com.android.quickstep.views;
import static android.support.v4.graphics.ColorUtils.compositeColors;
import static android.support.v4.graphics.ColorUtils.setAlphaComponent; import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
import static com.android.launcher3.LauncherState.OVERVIEW; 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.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
@ -32,7 +32,7 @@ import android.util.AttributeSet;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R; 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.util.Themes;
import com.android.launcher3.views.ScrimView; import com.android.launcher3.views.ScrimView;
@ -45,22 +45,30 @@ import com.android.launcher3.views.ScrimView;
*/ */
public class ShelfScrimView extends ScrimView { 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. // In transposed layout, we simply draw a flat color.
private boolean mDrawingFlatColor; private boolean mDrawingFlatColor;
// For shelf mode // For shelf mode
private final int mEndAlpha; private final int mEndAlpha;
private final int mThresholdAlpha;
private final float mRadius; private final float mRadius;
private final float mMaxScrimAlpha; private final float mMaxScrimAlpha;
private final Paint mPaint; private final Paint mPaint;
// Max vertical progress after which the scrim stops moving. // Mid point where the alpha changes
private float mMoveThreshold; private int mMidAlpha;
// Minimum visible size of the scrim. private float mMidProgress;
private int mMinSize;
private float mShiftRange;
private final float mShelfOffset;
private float mTopOffset;
private float mShelfTop;
private float mShelfTopAtThreshold;
private float mScrimMoveFactor = 0;
private int mShelfColor; private int mShelfColor;
private int mRemainingScreenColor; private int mRemainingScreenColor;
@ -73,10 +81,10 @@ public class ShelfScrimView extends ScrimView {
mMaxScrimAlpha = OVERVIEW.getWorkspaceScrimAlpha(mLauncher); mMaxScrimAlpha = OVERVIEW.getWorkspaceScrimAlpha(mLauncher);
mEndAlpha = Color.alpha(mEndScrim); mEndAlpha = Color.alpha(mEndScrim);
mThresholdAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius); mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 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. // Just assume the easiest UI for now, until we have the proper layout information.
mDrawingFlatColor = true; mDrawingFlatColor = true;
} }
@ -93,10 +101,15 @@ public class ShelfScrimView extends ScrimView {
mDrawingFlatColor = dp.isVerticalBarLayout(); mDrawingFlatColor = dp.isVerticalBarLayout();
if (!mDrawingFlatColor) { if (!mDrawingFlatColor) {
float swipeLength = OverviewState.getDefaultSwipeHeight(mLauncher);
mMoveThreshold = 1 - swipeLength / mLauncher.getAllAppsController().getShiftRange();
mMinSize = dp.hotseatBarSizePx + dp.getInsets().bottom;
mRemainingScreenPathValid = false; 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(); updateColors();
} }
updateDragHandleAlpha(); updateDragHandleAlpha();
@ -107,82 +120,79 @@ public class ShelfScrimView extends ScrimView {
public void updateColors() { public void updateColors() {
super.updateColors(); super.updateColors();
if (mDrawingFlatColor) { if (mDrawingFlatColor) {
mDragHandleOffset = 0;
return; return;
} }
if (mProgress >= mMoveThreshold) { mDragHandleOffset = mShelfOffset - mDragHandleSize;
mScrimMoveFactor = 1; if (mProgress >= SCRIM_CATCHUP_THRESHOLD) {
mShelfTop = mShiftRange * mProgress + mTopOffset;
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;
} else { } else {
mScrimMoveFactor = mProgress / mMoveThreshold; mShelfTop = Utilities.mapRange(mProgress / SCRIM_CATCHUP_THRESHOLD, -mRadius,
mRemainingScreenColor = setAlphaComponent(mScrimColor, mShelfTopAtThreshold);
Math.round((1 - mScrimMoveFactor) * mMaxScrimAlpha * 255)); }
// Merge the remainingScreenColor and shelfColor in one to avoid overdraw. if (mProgress >= 1) {
int alpha = mEndAlpha - Math.round((mEndAlpha - mThresholdAlpha) * mScrimMoveFactor); mRemainingScreenColor = 0;
mShelfColor = compositeColors(setAlphaComponent(mEndScrim, alpha), mShelfColor = 0;
mRemainingScreenColor); } 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 @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
float translate = drawBackground(canvas); drawBackground(canvas);
drawDragHandle(canvas);
if (mDragHandle != null) {
canvas.translate(0, -translate);
mDragHandle.draw(canvas);
canvas.translate(0, translate);
}
} }
private float drawBackground(Canvas canvas) { private void drawBackground(Canvas canvas) {
if (mDrawingFlatColor) { if (mDrawingFlatColor) {
if (mCurrentFlatColor != 0) { if (mCurrentFlatColor != 0) {
canvas.drawColor(mCurrentFlatColor); canvas.drawColor(mCurrentFlatColor);
} }
return 0; return;
} }
if (mShelfColor == 0) { if (Color.alpha(mShelfColor) == 0) {
return 0; return;
} else if (mScrimMoveFactor <= 0) { } else if (mProgress <= 0) {
canvas.drawColor(mShelfColor); canvas.drawColor(mShelfColor);
return getHeight(); return;
} }
float minTop = getHeight() - mMinSize; int height = getHeight();
float top = minTop * mScrimMoveFactor - mDragHandleSize; int width = getWidth();
// Draw the scrim over the remaining screen if needed. // Draw the scrim over the remaining screen if needed.
if (mRemainingScreenColor != 0) { if (mRemainingScreenColor != 0) {
if (!mRemainingScreenPathValid) { if (!mRemainingScreenPathValid) {
mTempPath.reset(); mTempPath.reset();
// Using a arbitrary '+10' in the bottom to avoid any left-overs at the // Using a arbitrary '+10' in the bottom to avoid any left-overs at the
// corners due to rounding issues. // 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); mRadius, mRadius, Direction.CW);
mRemainingScreenPath.reset(); mRemainingScreenPath.reset();
mRemainingScreenPath.addRect(0, 0, getWidth(), getHeight(), Direction.CW); mRemainingScreenPath.addRect(0, 0, width, height, Direction.CW);
mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE); mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE);
} }
float offset = minTop - top; float offset = height - mRadius - mShelfTop;
canvas.translate(0, -offset); canvas.translate(0, -offset);
mPaint.setColor(mRemainingScreenColor); mPaint.setColor(mRemainingScreenColor);
canvas.drawPath(mRemainingScreenPath, mPaint); canvas.drawPath(mRemainingScreenPath, mPaint);
@ -190,8 +200,6 @@ public class ShelfScrimView extends ScrimView {
} }
mPaint.setColor(mShelfColor); mPaint.setColor(mShelfColor);
canvas.drawRoundRect(0, top, getWidth(), getHeight() + mRadius, canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint);
mRadius, mRadius, mPaint);
return minTop - mDragHandleSize - top;
} }
} }

View File

@ -48,6 +48,7 @@ import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.View; import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
@ -281,13 +282,14 @@ public final class Utilities {
* @param toMax The upper bound of the range that t is being mapped to. * @param toMax The upper bound of the range that t is being mapped to.
* @return The mapped value of t. * @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) { if (fromMin == fromMax || toMin == toMax) {
Log.e(TAG, "mapToRange: range has 0 length"); Log.e(TAG, "mapToRange: range has 0 length");
return toMin; return toMin;
} }
float progress = Math.abs(t - fromMin) / Math.abs(fromMax - fromMin); 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) { public static float mapRange(float value, float min, float max) {

View File

@ -158,7 +158,6 @@ public class Interpolators {
*/ */
public static Interpolator mapToProgress(Interpolator interpolator, float lowerBound, public static Interpolator mapToProgress(Interpolator interpolator, float lowerBound,
float upperBound) { float upperBound) {
return t -> Utilities.mapToRange(interpolator.getInterpolation(t), 0, 1, return t -> Utilities.mapRange(interpolator.getInterpolation(t), lowerBound, upperBound);
lowerBound, upperBound);
} }
} }

View File

@ -109,6 +109,7 @@ public class ScrimView extends View implements Insettable, OnChangeListener,
protected int mEndFlatColorAlpha; protected int mEndFlatColorAlpha;
protected final int mDragHandleSize; protected final int mDragHandleSize;
protected float mDragHandleOffset;
private final Rect mDragHandleBounds; private final Rect mDragHandleBounds;
private final RectF mHitRect = new RectF(); private final RectF mHitRect = new RectF();
@ -223,8 +224,14 @@ public class ScrimView extends View implements Insettable, OnChangeListener,
if (mCurrentFlatColor != 0) { if (mCurrentFlatColor != 0) {
canvas.drawColor(mCurrentFlatColor); canvas.drawColor(mCurrentFlatColor);
} }
drawDragHandle(canvas);
}
protected void drawDragHandle(Canvas canvas) {
if (mDragHandle != null) { if (mDragHandle != null) {
canvas.translate(0, -mDragHandleOffset);
mDragHandle.draw(canvas); mDragHandle.draw(canvas);
canvas.translate(0, mDragHandleOffset);
} }
} }
@ -237,20 +244,23 @@ public class ScrimView extends View implements Insettable, OnChangeListener,
final Drawable drawable = mDragHandle; final Drawable drawable = mDragHandle;
mDragHandle = null; mDragHandle = null;
drawable.setBounds(mDragHandleBounds);
Rect topBounds = new Rect(mDragHandleBounds); Rect bounds = new Rect(mDragHandleBounds);
topBounds.offset(0, -mDragHandleBounds.height() / 2); 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; invalidateRegion.top = topBounds.top;
Keyframe frameTop = Keyframe.ofObject(0.6f, topBounds); Keyframe frameTop = Keyframe.ofObject(0.6f, topBounds);
frameTop.setInterpolator(DEACCEL); frameTop.setInterpolator(DEACCEL);
Keyframe frameBot = Keyframe.ofObject(1, mDragHandleBounds); Keyframe frameBot = Keyframe.ofObject(1, bounds);
frameBot.setInterpolator(ACCEL); frameBot.setInterpolator(ACCEL);
PropertyValuesHolder holder = PropertyValuesHolder .ofKeyframe("bounds", PropertyValuesHolder holder = PropertyValuesHolder .ofKeyframe("bounds",
Keyframe.ofObject(0, mDragHandleBounds), frameTop, frameBot); Keyframe.ofObject(0, bounds), frameTop, frameBot);
holder.setEvaluator(new RectEvaluator()); holder.setEvaluator(new RectEvaluator());
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, holder); ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, holder);