mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 11:18:21 +00:00
[automerger] Overshoot when flinging up from an app am: b45444b250
Change-Id: I25d7621d3b60b307d4eb7c466eafc893e78b7ea0
This commit is contained in:
@@ -25,7 +25,6 @@ import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
@@ -192,7 +191,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
|
||||
// Update all apps interpolator to add a bit of overshoot starting from currFraction
|
||||
final float currFraction = mCurrentAnimation.getProgressFraction();
|
||||
mAllAppsInterpolatorWrapper.baseInterpolator = Interpolators.clampToProgress(
|
||||
new OvershootInterpolator(Math.min(Math.abs(velocity), 3f)), currFraction, 1);
|
||||
Interpolators.overshootInterpolatorForVelocity(velocity), currFraction, 1);
|
||||
animator.setDuration(Math.min(expectedDuration, ATOMIC_DURATION))
|
||||
.setInterpolator(LINEAR);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.view.View.TRANSLATION_Y;
|
||||
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
|
||||
@@ -25,6 +27,7 @@ import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
|
||||
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
|
||||
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
@@ -55,14 +58,15 @@ import com.android.launcher3.uioverrides.FastOverviewState;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||
import com.android.quickstep.TouchConsumer.InteractionType;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.TransformedRect;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.util.RemoteAnimationTargetSet;
|
||||
import com.android.quickstep.util.TransformedRect;
|
||||
import com.android.quickstep.views.LauncherLayoutListener;
|
||||
import com.android.quickstep.views.LauncherRecentsView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.RecentsViewContainer;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -248,28 +252,52 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activity.getDeviceProfile().isVerticalBarLayout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AllAppsTransitionController controller = activity.getAllAppsController();
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
|
||||
float scrollRange = Math.max(controller.getShiftRange(), 1);
|
||||
float progressDelta = (transitionLength / scrollRange);
|
||||
if (!activity.getDeviceProfile().isVerticalBarLayout()) {
|
||||
AllAppsTransitionController controller = activity.getAllAppsController();
|
||||
float scrollRange = Math.max(controller.getShiftRange(), 1);
|
||||
float progressDelta = (transitionLength / scrollRange);
|
||||
|
||||
float endProgress = endState.getVerticalProgress(activity);
|
||||
float startProgress = endProgress + progressDelta;
|
||||
ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(
|
||||
controller, ALL_APPS_PROGRESS, startProgress, endProgress);
|
||||
shiftAnim.setInterpolator(LINEAR);
|
||||
anim.play(shiftAnim);
|
||||
float endProgress = endState.getVerticalProgress(activity);
|
||||
float startProgress = endProgress + progressDelta;
|
||||
ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(
|
||||
controller, ALL_APPS_PROGRESS, startProgress, endProgress);
|
||||
shiftAnim.setInterpolator(LINEAR);
|
||||
anim.play(shiftAnim);
|
||||
}
|
||||
|
||||
if (interactionType == INTERACTION_NORMAL) {
|
||||
playScaleDownAnim(anim, activity);
|
||||
}
|
||||
|
||||
anim.setDuration(transitionLength * 2);
|
||||
activity.getStateManager().setCurrentAnimation(anim);
|
||||
callback.accept(AnimatorPlaybackController.wrap(anim, transitionLength * 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale down recents from the center task being full screen to being in overview.
|
||||
*/
|
||||
private void playScaleDownAnim(AnimatorSet anim, Launcher launcher) {
|
||||
RecentsView recentsView = launcher.getOverviewPanel();
|
||||
TaskView v = recentsView.getPageAt(recentsView.getCurrentPage());
|
||||
ClipAnimationHelper clipHelper = new ClipAnimationHelper();
|
||||
clipHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), null);
|
||||
if (!clipHelper.getSourceRect().isEmpty() && !clipHelper.getTargetRect().isEmpty()) {
|
||||
float fromScale = clipHelper.getSourceRect().width()
|
||||
/ clipHelper.getTargetRect().width();
|
||||
float fromTranslationY = clipHelper.getSourceRect().centerY()
|
||||
- clipHelper.getTargetRect().centerY();
|
||||
Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, fromScale, 1);
|
||||
Animator translateY = ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y,
|
||||
fromTranslationY, 0);
|
||||
scale.setInterpolator(LINEAR);
|
||||
translateY.setInterpolator(LINEAR);
|
||||
anim.playTogether(scale, translateY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityInitListener createActivityInitListener(
|
||||
BiPredicate<Launcher, Boolean> onInitListener) {
|
||||
|
||||
@@ -58,6 +58,7 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
@@ -569,7 +570,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
}
|
||||
|
||||
private void updateFinalShiftUi() {
|
||||
if (mLauncherTransitionController == null) {
|
||||
if (mLauncherTransitionController == null || mLauncherTransitionController
|
||||
.getAnimationPlayer().isStarted()) {
|
||||
return;
|
||||
}
|
||||
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
|
||||
@@ -663,17 +665,23 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
}
|
||||
|
||||
private void handleNormalGestureEnd(float endVelocity, boolean isFling) {
|
||||
float velocityPxPerMs = endVelocity / 1000;
|
||||
long duration = MAX_SWIPE_DURATION;
|
||||
final float endShift;
|
||||
final float startShift;
|
||||
final Interpolator interpolator;
|
||||
if (!isFling) {
|
||||
endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW && mGestureStarted ? 1 : 0;
|
||||
long expectedDuration = Math.abs(Math.round((endShift - mCurrentShift.value)
|
||||
* MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
|
||||
duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
|
||||
startShift = mCurrentShift.value;
|
||||
interpolator = DEACCEL;
|
||||
} else {
|
||||
endShift = endVelocity < 0 ? 1 : 0;
|
||||
interpolator = endVelocity < 0
|
||||
? Interpolators.overshootInterpolatorForVelocity(velocityPxPerMs, 2f)
|
||||
: DEACCEL;
|
||||
float minFlingVelocity = mContext.getResources()
|
||||
.getDimension(R.dimen.quickstep_fling_min_velocity);
|
||||
if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
|
||||
@@ -682,14 +690,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
// we want the page's snap velocity to approximately match the velocity at
|
||||
// which the user flings, so we scale the duration by a value near to the
|
||||
// derivative of the scroll interpolator at zero, ie. 2.
|
||||
long baseDuration = Math.round(1000 * Math.abs(distanceToTravel / endVelocity));
|
||||
long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs));
|
||||
duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
|
||||
}
|
||||
startShift = Utilities.boundToRange(mCurrentShift.value - endVelocity * SINGLE_FRAME_MS
|
||||
/ (mTransitionDragLength * 1000), 0, 1);
|
||||
startShift = Utilities.boundToRange(mCurrentShift.value - velocityPxPerMs
|
||||
* SINGLE_FRAME_MS / (mTransitionDragLength), 0, 1);
|
||||
}
|
||||
|
||||
animateToProgress(startShift, endShift, duration, DEACCEL);
|
||||
animateToProgress(startShift, endShift, duration, interpolator);
|
||||
}
|
||||
|
||||
private void doLogGesture(boolean toLauncher) {
|
||||
@@ -716,6 +723,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
|
||||
private void animateToProgress(float start, float end, long duration,
|
||||
Interpolator interpolator) {
|
||||
mRecentsAnimationWrapper.runOnInit(() -> animateToProgressInternal(start, end, duration,
|
||||
interpolator));
|
||||
}
|
||||
|
||||
private void animateToProgressInternal(float start, float end, long duration,
|
||||
Interpolator interpolator) {
|
||||
mIsGoingToHome = Float.compare(end, 1) == 0;
|
||||
ObjectAnimator anim = mCurrentShift.animateToValue(start, end).setDuration(duration);
|
||||
anim.setInterpolator(interpolator);
|
||||
@@ -727,7 +740,26 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
: STATE_SCALED_CONTROLLER_APP);
|
||||
}
|
||||
});
|
||||
mRecentsAnimationWrapper.runOnInit(anim::start);
|
||||
anim.start();
|
||||
long startMillis = SystemClock.uptimeMillis();
|
||||
executeOnUiThread(() -> {
|
||||
// Animate the launcher components at the same time as the window, always on UI thread.
|
||||
if (mLauncherTransitionController != null && !mWasLauncherAlreadyVisible
|
||||
&& start != end && duration > 0) {
|
||||
// Adjust start progress and duration in case we are on a different thread.
|
||||
long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
|
||||
elapsedMillis = Utilities.boundToRange(elapsedMillis, 0, duration);
|
||||
float elapsedProgress = (float) elapsedMillis / duration;
|
||||
float adjustedStart = Utilities.mapRange(elapsedProgress, start, end);
|
||||
long adjustedDuration = duration - elapsedMillis;
|
||||
// We want to use the same interpolator as the window, but need to adjust it to
|
||||
// interpolate over the remaining progress (end - start).
|
||||
mLauncherTransitionController.dispatchSetInterpolator(Interpolators.mapToProgress(
|
||||
interpolator, adjustedStart, end));
|
||||
mLauncherTransitionController.getAnimationPlayer().setDuration(adjustedDuration);
|
||||
mLauncherTransitionController.getAnimationPlayer().start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@UiThread
|
||||
|
||||
@@ -272,6 +272,24 @@ public final class Utilities {
|
||||
return scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps t from one range to another range.
|
||||
* @param t The value to map.
|
||||
* @param fromMin The lower bound of the range that t is being mapped from.
|
||||
* @param fromMax The upper bound of the range that t is being mapped from.
|
||||
* @param toMin The lower 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.
|
||||
*/
|
||||
public static float mapToRange(float t, float fromMin, float fromMax, float toMin, float toMax) {
|
||||
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);
|
||||
}
|
||||
|
||||
public static float mapRange(float value, float min, float max) {
|
||||
return min + (value * (max - min));
|
||||
}
|
||||
@@ -462,6 +480,13 @@ public final class Utilities {
|
||||
return Math.max(lowerBound, Math.min(value, upperBound));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #boundToRange(int, int, int).
|
||||
*/
|
||||
public static long boundToRange(long value, long lowerBound, long upperBound) {
|
||||
return Math.max(lowerBound, Math.min(value, upperBound));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a message with a TTS span, so that a different message is spoken than
|
||||
* what is getting displayed.
|
||||
|
||||
@@ -202,6 +202,19 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchSetInterpolator(TimeInterpolator interpolator) {
|
||||
dispatchSetInterpolatorRecursively(mAnim, interpolator);
|
||||
}
|
||||
|
||||
private void dispatchSetInterpolatorRecursively(Animator anim, TimeInterpolator interpolator) {
|
||||
anim.setInterpolator(interpolator);
|
||||
if (anim instanceof AnimatorSet) {
|
||||
for (Animator child : nonNullList(((AnimatorSet) anim).getChildAnimations())) {
|
||||
dispatchSetInterpolatorRecursively(child, interpolator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnCancelRunnable(Runnable runnable) {
|
||||
mOnCancelRunnable = runnable;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import android.view.animation.LinearInterpolator;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.view.animation.PathInterpolator;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
|
||||
/**
|
||||
* Common interpolators used in Launcher
|
||||
@@ -116,6 +118,19 @@ public class Interpolators {
|
||||
return Math.abs(velocity) > FAST_FLING_PX_MS ? SCROLL : SCROLL_CUBIC;
|
||||
}
|
||||
|
||||
public static Interpolator overshootInterpolatorForVelocity(float velocity) {
|
||||
return overshootInterpolatorForVelocity(velocity, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an OvershootInterpolator with tension directly related to the velocity (in px/ms).
|
||||
* @param velocity The start velocity of the animation we want to overshoot.
|
||||
* @param dampFactor An optional factor to reduce the amount of tension (how far we overshoot).
|
||||
*/
|
||||
public static Interpolator overshootInterpolatorForVelocity(float velocity, float dampFactor) {
|
||||
return new OvershootInterpolator(Math.min(Math.abs(velocity), 3f) / dampFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given interpolator such that the entire progress is set between the given bounds.
|
||||
* That is, we set the interpolation to 0 until lowerBound and reach 1 by upperBound.
|
||||
@@ -135,4 +150,15 @@ public class Interpolators {
|
||||
return interpolator.getInterpolation((t - lowerBound) / (upperBound - lowerBound));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given interpolator such that the interpolated value is mapped to the given range.
|
||||
* This is useful, for example, if we only use this interpolator for part of the animation,
|
||||
* such as to take over a user-controlled animation when they let go.
|
||||
*/
|
||||
public static Interpolator mapToProgress(Interpolator interpolator, float lowerBound,
|
||||
float upperBound) {
|
||||
return t -> Utilities.mapToRange(interpolator.getInterpolation(t), 0, 1,
|
||||
lowerBound, upperBound);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user