Responsive caret drawable

Change-Id: I9d40052d001c80d99db511af6134227f8e4e4239
This commit is contained in:
Hyunyoung Song 2016-07-27 12:48:09 -07:00 committed by Peter Schiller
parent 64035e9ee6
commit 7ccc4625e3
5 changed files with 99 additions and 37 deletions

View File

@ -66,6 +66,11 @@
public void setAnimationProgress(float); public void setAnimationProgress(float);
} }
-keep class com.android.launcher3.pageindicators.CaretDrawable {
public float getCaretProgress();
public void setCaretProgress(float);
}
-keep class com.android.launcher3.Workspace { -keep class com.android.launcher3.Workspace {
public float getBackgroundAlpha(); public float getBackgroundAlpha();
public void setBackgroundAlpha(float); public void setBackgroundAlpha(float);

View File

@ -705,7 +705,7 @@ public class LauncherStateTransitionAnimation {
if (!animated || !initialized) { if (!animated || !initialized) {
if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
fromWorkspaceState == Workspace.State.NORMAL_HIDDEN) { fromWorkspaceState == Workspace.State.NORMAL_HIDDEN) {
mAllAppsController.finishPullDown(false); mAllAppsController.finishPullDown();
} }
fromView.setVisibility(View.GONE); fromView.setVisibility(View.GONE);
dispatchOnLauncherTransitionPrepare(fromView, animated, multiplePagesVisible); dispatchOnLauncherTransitionPrepare(fromView, animated, multiplePagesVisible);

View File

@ -59,6 +59,8 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
private ObjectAnimator mCaretAnimator; private ObjectAnimator mCaretAnimator;
private final long mCaretAnimationDuration; private final long mCaretAnimationDuration;
private final Interpolator mCaretInterpolator; private final Interpolator mCaretInterpolator;
private CaretDrawable mCaretDrawable;
private float mLastCaretProgress;
private float mStatusBarHeight; private float mStatusBarHeight;
@ -76,6 +78,8 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
private float mShiftRange; // changes depending on the orientation private float mShiftRange; // changes depending on the orientation
private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent
private float mVelocityForCaret;
private static final float DEFAULT_SHIFT_RANGE = 10; private static final float DEFAULT_SHIFT_RANGE = 10;
private static final float RECATCH_REJECTION_FRACTION = .0875f; private static final float RECATCH_REJECTION_FRACTION = .0875f;
@ -203,8 +207,12 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
if (mAppsView == null) { if (mAppsView == null) {
return false; // early termination. return false; // early termination.
} }
mVelocityForCaret = velocity;
float shift = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange); float shift = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange);
setProgress(shift / mShiftRange); setProgress(shift / mShiftRange);
return true; return true;
} }
@ -329,6 +337,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
mWorkspace.setWorkspaceYTranslationAndAlpha( mWorkspace.setWorkspaceYTranslationAndAlpha(
PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent), PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent),
interpolation); interpolation);
updateCaret(progress);
updateLightStatusBar(shiftCurrent); updateLightStatusBar(shiftCurrent);
} }
@ -352,6 +361,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
return; return;
} }
if (mDetector.isIdleState()) { if (mDetector.isIdleState()) {
mVelocityForCaret = -VerticalPullDetector.RELEASE_VELOCITY_PX_MS;
preparePull(true); preparePull(true);
mAnimationDuration = duration; mAnimationDuration = duration;
mShiftStart = mAppsView.getTranslationY(); mShiftStart = mAppsView.getTranslationY();
@ -404,7 +414,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
@Override @Override
public void onAnimationEnd(Animator animator) { public void onAnimationEnd(Animator animator) {
finishPullDown(false); finishPullDown();
mDiscoBounceAnimation = null; mDiscoBounceAnimation = null;
mIsTranslateWithoutWorkspace = false; mIsTranslateWithoutWorkspace = false;
} }
@ -424,6 +434,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
} }
Interpolator interpolator; Interpolator interpolator;
if (mDetector.isIdleState()) { if (mDetector.isIdleState()) {
mVelocityForCaret = VerticalPullDetector.RELEASE_VELOCITY_PX_MS;
preparePull(true); preparePull(true);
mAnimationDuration = duration; mAnimationDuration = duration;
mShiftStart = mAppsView.getTranslationY(); mShiftStart = mAppsView.getTranslationY();
@ -452,7 +463,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
if (canceled) { if (canceled) {
return; return;
} else { } else {
finishPullDown(true); finishPullDown();
cleanUpAnimation(); cleanUpAnimation();
mDetector.finishedScrolling(); mDetector.finishedScrolling();
} }
@ -464,21 +475,14 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
public void finishPullUp() { public void finishPullUp() {
mHotseat.setVisibility(View.INVISIBLE); mHotseat.setVisibility(View.INVISIBLE);
setProgress(0f); setProgress(0f);
animateCaret();
} }
public void finishPullDown(boolean animated) { public void finishPullDown() {
mAppsView.setVisibility(View.INVISIBLE); mAppsView.setVisibility(View.INVISIBLE);
mHotseat.setBackgroundTransparent(false /* transparent */); mHotseat.setBackgroundTransparent(false /* transparent */);
mHotseat.setVisibility(View.VISIBLE); mHotseat.setVisibility(View.VISIBLE);
mAppsView.reset(); mAppsView.reset();
setProgress(1f); setProgress(1f);
if (animated) {
animateCaret();
} else {
mWorkspace.getPageIndicator().getCaretDrawable()
.setLevel(CaretDrawable.LEVEL_CARET_POINTING_UP);
}
} }
private void cancelAnimation() { private void cancelAnimation() {
@ -501,17 +505,41 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
mCurrentAnimation = null; mCurrentAnimation = null;
} }
private void animateCaret() { private void updateCaret(float shift) {
// Animate to a neutral state by default
float newCaretProgress = CaretDrawable.PROGRESS_CARET_NEUTRAL;
// If we're in portrait and the shift is not 0 or 1, adjust the caret based on velocity
if (0f < shift && shift < 1f && !mLauncher.useVerticalBarLayout()) {
// How fast are we moving as a percentage of the minimum fling velocity?
final float pctOfFlingVelocity = Math.max(-1, Math.min(
mVelocityForCaret / VerticalPullDetector.RELEASE_VELOCITY_PX_MS, 1));
mCaretDrawable.setCaretProgress(pctOfFlingVelocity);
// Set the last caret progress to this progress to prevent animator cancellation
mLastCaretProgress = pctOfFlingVelocity;
} else if (!mDetector.isDraggingState()) {
// Otherwise, if we're not dragging, match the caret to the appropriate state
if (Float.compare(shift, 0f) == 0) { // All Apps is up
newCaretProgress = CaretDrawable.PROGRESS_CARET_POINTING_DOWN;
} else if (Float.compare(shift, 1f) == 0) { // All Apps is down
newCaretProgress = CaretDrawable.PROGRESS_CARET_POINTING_UP;
}
}
// If the new progress is the same as the last progress we animated to, terminate early
if (Float.compare(mLastCaretProgress, newCaretProgress) == 0) {
return;
}
if (mCaretAnimator.isRunning()) { if (mCaretAnimator.isRunning()) {
mCaretAnimator.cancel(); // stop the animator in its tracks mCaretAnimator.cancel(); // Stop the animator in its tracks
}
if (mLauncher.isAllAppsVisible()) {
mCaretAnimator.setIntValues(CaretDrawable.LEVEL_CARET_POINTING_DOWN);
} else {
mCaretAnimator.setIntValues(CaretDrawable.LEVEL_CARET_POINTING_UP);
} }
// Update the progress and start the animation
mLastCaretProgress = newCaretProgress;
mCaretAnimator.setFloatValues(newCaretProgress);
mCaretAnimator.start(); mCaretAnimator.start();
} }
@ -519,12 +547,14 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
mAppsView = appsView; mAppsView = appsView;
mHotseat = hotseat; mHotseat = hotseat;
mWorkspace = workspace; mWorkspace = workspace;
mCaretAnimator = ObjectAnimator.ofInt(mWorkspace.getPageIndicator().getCaretDrawable(), mCaretDrawable = mWorkspace.getPageIndicator().getCaretDrawable();
"level", CaretDrawable.LEVEL_CARET_POINTING_UP); // we will set values later
mCaretAnimator.setDuration(mCaretAnimationDuration);
mCaretAnimator.setInterpolator(mCaretInterpolator);
mHotseat.addOnLayoutChangeListener(this); mHotseat.addOnLayoutChangeListener(this);
mHotseat.bringToFront(); mHotseat.bringToFront();
// we will set values later
mCaretAnimator = ObjectAnimator.ofFloat(mCaretDrawable, "caretProgress", 0);
mCaretAnimator.setDuration(mCaretAnimationDuration);
mCaretAnimator.setInterpolator(mCaretInterpolator);
} }
@Override @Override
@ -537,6 +567,4 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
} }
setProgress(mProgress); setProgress(mProgress);
} }
} }

View File

@ -26,7 +26,7 @@ public class VerticalPullDetector {
/** /**
* The minimum release velocity in pixels per millisecond that triggers fling.. * The minimum release velocity in pixels per millisecond that triggers fling..
*/ */
private static final float RELEASE_VELOCITY_PX_MS = 1.0f; public static final float RELEASE_VELOCITY_PX_MS = 1.0f;
/** /**
* The time constant used to calculate dampening in the low-pass filter of scroll velocity. * The time constant used to calculate dampening in the low-pass filter of scroll velocity.
@ -87,6 +87,10 @@ public class VerticalPullDetector {
return mState == ScrollState.SETTLING; return mState == ScrollState.SETTLING;
} }
public boolean isDraggingState() {
return mState == ScrollState.DRAGGING;
}
private float mDownX; private float mDownX;
private float mDownY; private float mDownY;
private float mDownMillis; private float mDownMillis;

View File

@ -28,11 +28,11 @@ import com.android.launcher3.R;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
public class CaretDrawable extends Drawable { public class CaretDrawable extends Drawable {
public static final int LEVEL_CARET_POINTING_UP = 0; // minimum possible level value public static final float PROGRESS_CARET_POINTING_UP = -1f;
public static final int LEVEL_CARET_POINTING_DOWN = 10000; // maximum possible level value public static final float PROGRESS_CARET_POINTING_DOWN = 1f;
public static final int LEVEL_CARET_NEUTRAL = LEVEL_CARET_POINTING_DOWN / 2; public static final float PROGRESS_CARET_NEUTRAL = 0;
private float mCaretProgress; private float mCaretProgress = PROGRESS_CARET_NEUTRAL;
private Paint mShadowPaint = new Paint(); private Paint mShadowPaint = new Paint();
private Paint mCaretPaint = new Paint(); private Paint mCaretPaint = new Paint();
@ -72,23 +72,48 @@ public class CaretDrawable extends Drawable {
final float left = getBounds().left + (mShadowPaint.getStrokeWidth() / 2); final float left = getBounds().left + (mShadowPaint.getStrokeWidth() / 2);
final float top = getBounds().top + (mShadowPaint.getStrokeWidth() / 2); final float top = getBounds().top + (mShadowPaint.getStrokeWidth() / 2);
// When the bounds are square, this will result in a caret with a right angle
final float verticalInset = (height / 4); final float verticalInset = (height / 4);
final float caretHeight = (height - (verticalInset * 2)); final float caretHeight = (height - (verticalInset * 2));
mPath.reset(); mPath.reset();
mPath.moveTo(left, top + caretHeight * (1 - mCaretProgress)); mPath.moveTo(left, top + caretHeight * (1 - getNormalizedCaretProgress()));
mPath.lineTo(left + (width / 2), top + caretHeight * mCaretProgress); mPath.lineTo(left + (width / 2), top + caretHeight * getNormalizedCaretProgress());
mPath.lineTo(left + width, top + caretHeight * (1 - mCaretProgress)); mPath.lineTo(left + width, top + caretHeight * (1 - getNormalizedCaretProgress()));
canvas.drawPath(mPath, mShadowPaint); canvas.drawPath(mPath, mShadowPaint);
canvas.drawPath(mPath, mCaretPaint); canvas.drawPath(mPath, mCaretPaint);
} }
@Override /**
protected boolean onLevelChange(int level) { * Sets the caret progress
mCaretProgress = (float) level / (float) LEVEL_CARET_POINTING_DOWN; *
* @param progress The progress ({@value #PROGRESS_CARET_POINTING_UP} for pointing up,
* {@value #PROGRESS_CARET_POINTING_DOWN} for pointing down, {@value #PROGRESS_CARET_NEUTRAL}
* for neutral)
*/
public void setCaretProgress(float progress) {
mCaretProgress = progress;
invalidateSelf(); invalidateSelf();
return true; }
/**
* Returns the caret progress
*
* @return The progress
*/
public float getCaretProgress() {
return mCaretProgress;
}
/**
* Returns the caret progress normalized to [0..1]
*
* @return The normalized progress
*/
public float getNormalizedCaretProgress() {
return (mCaretProgress - PROGRESS_CARET_POINTING_UP) /
(PROGRESS_CARET_POINTING_DOWN - PROGRESS_CARET_POINTING_UP);
} }
@Override @Override