mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-03 17:36:49 +00:00
Merge "Animate task translation on dismissal." into sc-dev
This commit is contained in:
@@ -39,6 +39,11 @@
|
||||
<dimen name="overview_grid_focus_vertical_margin">90dp</dimen>
|
||||
<dimen name="split_placeholder_size">110dp</dimen>
|
||||
|
||||
<!-- These speeds are in dp/s -->
|
||||
<dimen name="max_task_dismiss_drag_velocity">2.25dp</dimen>
|
||||
<dimen name="default_task_dismiss_drag_velocity">1.75dp</dimen>
|
||||
<dimen name="default_task_dismiss_drag_velocity_grid">0.75dp</dimen>
|
||||
|
||||
<dimen name="recents_page_spacing">16dp</dimen>
|
||||
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.view.animation.Interpolator;
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.LauncherAnimUtils;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
@@ -50,6 +51,10 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
extends AnimatorListenerAdapter implements TouchController,
|
||||
SingleAxisSwipeDetector.Listener {
|
||||
|
||||
private static final float ANIMATION_PROGRESS_FRACTION_MIDPOINT = 0.5f;
|
||||
private static final long MIN_TASK_DISMISS_ANIMATION_DURATION = 300;
|
||||
private static final long MAX_TASK_DISMISS_ANIMATION_DURATION = 600;
|
||||
|
||||
protected final T mActivity;
|
||||
private final SingleAxisSwipeDetector mDetector;
|
||||
private final RecentsView mRecentsView;
|
||||
@@ -277,14 +282,32 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
} else {
|
||||
mFlingBlockCheck.onEvent();
|
||||
}
|
||||
mCurrentAnimation.setPlayFraction(Utilities.boundToRange(
|
||||
totalDisplacement * mProgressMultiplier, 0, 1));
|
||||
|
||||
// Once halfway through task dismissal interpolation, switch from reversible dragging-task
|
||||
// animation to playing the remaining task translation animations
|
||||
if (mCurrentAnimation.getProgressFraction() < ANIMATION_PROGRESS_FRACTION_MIDPOINT) {
|
||||
// Halve the value as we are animating the drag across the full length for only the
|
||||
// first half of the progress
|
||||
mCurrentAnimation.setPlayFraction(
|
||||
Utilities.boundToRange(totalDisplacement * mProgressMultiplier / 2, 0, 1));
|
||||
} else {
|
||||
float dragVelocity = -mTaskBeingDragged.getResources().getDimension(
|
||||
mRecentsView.showAsGrid() ? R.dimen.default_task_dismiss_drag_velocity_grid
|
||||
: R.dimen.default_task_dismiss_drag_velocity);
|
||||
onDragEnd(dragVelocity);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity) {
|
||||
// Limit velocity, as very large scalar values make animations play too quickly
|
||||
float maxTaskDismissDragVelocity = mTaskBeingDragged.getResources().getDimension(
|
||||
R.dimen.max_task_dismiss_drag_velocity);
|
||||
velocity = Utilities.boundToRange(velocity, -maxTaskDismissDragVelocity,
|
||||
maxTaskDismissDragVelocity);
|
||||
boolean fling = mDetector.isFling(velocity);
|
||||
final boolean goingToEnd;
|
||||
boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
|
||||
@@ -305,6 +328,11 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
if (blockedFling && !goingToEnd) {
|
||||
animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity);
|
||||
}
|
||||
// Due to very high or low velocity dismissals, animation durations can be inconsistently
|
||||
// long or short. Bound the duration for animation of task translations for a more
|
||||
// standardized feel.
|
||||
animationDuration = Utilities.boundToRange(animationDuration,
|
||||
MIN_TASK_DISMISS_ANIMATION_DURATION, MAX_TASK_DISMISS_ANIMATION_DURATION);
|
||||
|
||||
mCurrentAnimation.setEndAction(this::clearState);
|
||||
mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
|
||||
|
||||
@@ -32,11 +32,12 @@ import static com.android.launcher3.Utilities.mapToRange;
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_0_5;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
|
||||
@@ -336,6 +337,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// OverScroll constants
|
||||
private static final int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
|
||||
|
||||
private static final int DISMISS_TASK_DURATION = 300;
|
||||
private static final int ADDITION_TASK_DURATION = 200;
|
||||
private static final float INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.55f;
|
||||
private static final float ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.05f;
|
||||
|
||||
protected final RecentsOrientedState mOrientationState;
|
||||
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
|
||||
protected RecentsAnimationController mRecentsAnimationController;
|
||||
@@ -358,10 +364,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private final List<OnScrollChangedListener> mScrollListeners = new ArrayList<>();
|
||||
private float mFullscreenScale;
|
||||
|
||||
private static final int DISMISS_TASK_DURATION = 300;
|
||||
private static final int DISMISS_TASK_TRANSLATION_DURATION = 200;
|
||||
private static final int ADDITIONAL_DISMISS_TASK_TRANSLATION_DURATION = 75;
|
||||
private static final int ADDITION_TASK_DURATION = 200;
|
||||
// The threshold at which we update the SystemUI flags when animating from the task into the app
|
||||
public static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.85f;
|
||||
|
||||
@@ -1886,21 +1888,18 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
* This method is used when no task dismissal has occurred.
|
||||
*/
|
||||
private void updateGridProperties() {
|
||||
updateGridProperties(null, -1);
|
||||
updateGridProperties(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates TaskView and ClearAllButton scaling and translation required to turn into grid
|
||||
* layout.
|
||||
* This method only calculates the potential position and depends on {@link #setGridProgress} to
|
||||
* apply the actual scaling and translation. This adds task translation animations in the case
|
||||
* of task dismissals: e.g. when dismissedTask is not null.
|
||||
* apply the actual scaling and translation.
|
||||
*
|
||||
* @param dismissedTask the TaskView dismissed, possibly null
|
||||
* @param dismissedIndex the index at which the dismissedTask was prior to dismissal, if no
|
||||
* dismissal occurred, this is unused
|
||||
* @param isTaskDismissal indicates if update was called due to task dismissal
|
||||
*/
|
||||
private void updateGridProperties(TaskView dismissedTask, int dismissedIndex) {
|
||||
private void updateGridProperties(boolean isTaskDismissal) {
|
||||
int taskCount = getTaskViewCount();
|
||||
if (taskCount == 0) {
|
||||
return;
|
||||
@@ -1940,10 +1939,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
int snappedPage = getNextPage();
|
||||
TaskView snappedTaskView = getTaskViewAtByAbsoluteIndex(snappedPage);
|
||||
|
||||
boolean isTaskDismissal = dismissedTask != null;
|
||||
float dismissedTaskWidth =
|
||||
isTaskDismissal ? dismissedTask.getLayoutParams().width + mPageSpacing : 0;
|
||||
|
||||
if (!isTaskDismissal) {
|
||||
mTopRowIdSet.clear();
|
||||
}
|
||||
@@ -2039,34 +2034,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
snappedTaskGridTranslationX = gridTranslations[snappedPage - mTaskViewStartIndex];
|
||||
}
|
||||
|
||||
// Animate task dismissTranslationX for tasks with index >= dismissed index and in the
|
||||
// same row as the dismissed index, or if the dismissed task was the focused task. Offset
|
||||
// successive task dismissal durations for a staggered effect.
|
||||
ArrayList<Animator> gridTranslationAnimators = new ArrayList<>();
|
||||
boolean isFocusedTaskDismissed =
|
||||
isTaskDismissal && dismissedTask.getTask().key.id == mFocusedTaskId;
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
TaskView taskView = getTaskViewAt(i);
|
||||
if (isFocusedTaskDismissed || (i >= dismissedIndex && isSameGridRow(dismissedTask,
|
||||
taskView))) {
|
||||
Animator taskDismissAnimator = ObjectAnimator.ofFloat(taskView,
|
||||
taskView.getPrimaryDismissTranslationProperty(),
|
||||
mIsRtl ? -dismissedTaskWidth : dismissedTaskWidth, 0f);
|
||||
int additionalTranslationDuration =
|
||||
i >= dismissedIndex ? (ADDITIONAL_DISMISS_TASK_TRANSLATION_DURATION * (
|
||||
(i - dismissedIndex) / 2)) : 0;
|
||||
taskDismissAnimator.setDuration(
|
||||
DISMISS_TASK_TRANSLATION_DURATION + additionalTranslationDuration);
|
||||
gridTranslationAnimators.add(taskDismissAnimator);
|
||||
}
|
||||
taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX);
|
||||
taskView.getPrimaryNonFullscreenTranslationProperty().set(taskView,
|
||||
snappedTaskFullscreenScrollAdjustment);
|
||||
taskView.getSecondaryNonFullscreenTranslationProperty().set(taskView, 0f);
|
||||
}
|
||||
AnimatorSet gridTranslationAnimatorSet = new AnimatorSet();
|
||||
gridTranslationAnimatorSet.playTogether(gridTranslationAnimators);
|
||||
gridTranslationAnimatorSet.start();
|
||||
|
||||
// Use the accumulated translation of the row containing the last task.
|
||||
float clearAllAccumulatedTranslation = topSet.contains(taskCount - 1)
|
||||
@@ -2210,7 +2184,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
PendingAnimation anim) {
|
||||
// Use setFloat instead of setViewAlpha as we want to keep the view visible even when it's
|
||||
// alpha is set to 0 so that it can be recycled in the view pool properly
|
||||
anim.setFloat(taskView, VIEW_ALPHA, 0, ACCEL_2);
|
||||
anim.setFloat(taskView, VIEW_ALPHA, 0, clampToProgress(ACCEL, 0, 0.5f));
|
||||
SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
|
||||
|
||||
ResourceProvider rp = DynamicResource.provider(mActivity);
|
||||
@@ -2246,8 +2220,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
throw new IllegalStateException("Invalid split task translation: " + dir);
|
||||
}
|
||||
}
|
||||
// Double translation distance so dismissal drag is the full height, as we only animate
|
||||
// the drag for the first half of the progress.
|
||||
anim.add(ObjectAnimator.ofFloat(taskView, dismissingTaskViewTranslate,
|
||||
positiveNegativeFactor * translateDistance).setDuration(duration), LINEAR, sp);
|
||||
positiveNegativeFactor * translateDistance * 2).setDuration(duration), LINEAR, sp);
|
||||
|
||||
if (LIVE_TILE.get() && taskView.isRunningTask()) {
|
||||
anim.addOnFrameCallback(() -> {
|
||||
@@ -2283,6 +2259,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
int draggedIndex = indexOfChild(taskView);
|
||||
|
||||
boolean isFocusedTaskDismissed = taskView.getTask().key.id == mFocusedTaskId;
|
||||
if (isFocusedTaskDismissed && showAsGrid()) {
|
||||
anim.setFloat(mActionsView, VIEW_ALPHA, 0, clampToProgress(ACCEL_0_5, 0, 0.5f));
|
||||
}
|
||||
float dismissedTaskWidth = taskView.getLayoutParams().width + mPageSpacing;
|
||||
boolean needsCurveUpdates = false;
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = getChildAt(i);
|
||||
@@ -2291,7 +2272,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
addDismissedTaskAnimations(taskView, duration, anim);
|
||||
}
|
||||
} else if (!showAsGrid()) {
|
||||
// For grid layout, don't animate other tasks when dismissing in grid for now.
|
||||
// Compute scroll offsets from task dismissal for animation.
|
||||
// If we just take newScroll - oldScroll, everything to the right of dragged task
|
||||
// translates to the left. We need to offset this in some cases:
|
||||
// - In RTL, add page offset to all pages, since we want pages to move to the right
|
||||
@@ -2318,15 +2299,31 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
? ((TaskView) child).getPrimaryDismissTranslationProperty()
|
||||
: mOrientationHandler.getPrimaryViewTranslate();
|
||||
|
||||
ResourceProvider rp = DynamicResource.provider(mActivity);
|
||||
SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_END)
|
||||
.setDampingRatio(
|
||||
rp.getFloat(R.dimen.dismiss_task_trans_x_damping_ratio))
|
||||
.setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_x_stiffness));
|
||||
anim.add(ObjectAnimator.ofFloat(child, translationProperty, scrollDiff)
|
||||
.setDuration(duration), ACCEL, sp);
|
||||
float additionalDismissDuration =
|
||||
ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(
|
||||
i - draggedIndex);
|
||||
anim.setFloat(child, translationProperty, scrollDiff, clampToProgress(LINEAR,
|
||||
Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ additionalDismissDuration, 0f, 1f), 1));
|
||||
needsCurveUpdates = true;
|
||||
}
|
||||
} else if (child instanceof TaskView) {
|
||||
// Animate task with index >= dismissed index and in the same row as the
|
||||
// dismissed index, or if the dismissed task was the focused task. Offset
|
||||
// successive task dismissal durations for a staggered effect.
|
||||
if (isFocusedTaskDismissed || (i >= draggedIndex && isSameGridRow((TaskView) child,
|
||||
taskView))) {
|
||||
FloatProperty translationProperty =
|
||||
((TaskView) child).getPrimaryDismissTranslationProperty();
|
||||
float additionalDismissDuration =
|
||||
ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(
|
||||
i - draggedIndex);
|
||||
anim.setFloat(child, translationProperty,
|
||||
!mIsRtl ? -dismissedTaskWidth : dismissedTaskWidth,
|
||||
clampToProgress(LINEAR, Utilities.boundToRange(
|
||||
INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ additionalDismissDuration, 0f, 1f), 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2364,6 +2361,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
}
|
||||
|
||||
// Reset task translations as they may have updated via animations in
|
||||
// createTaskDismissAnimation
|
||||
resetTaskVisuals();
|
||||
|
||||
int pageToSnapTo = mCurrentPage;
|
||||
// Snap to start if focused task was dismissed, as after quick switch it could
|
||||
// be at any page but the focused task always displays at the start.
|
||||
@@ -2381,7 +2382,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
} else {
|
||||
snapToPageImmediately(pageToSnapTo);
|
||||
// Grid got messed up, reapply.
|
||||
updateGridProperties(taskView, draggedIndex - mTaskViewStartIndex);
|
||||
updateGridProperties(true);
|
||||
if (showAsGrid() && getFocusedTaskView() == null
|
||||
&& mActionsView.getVisibilityAlpha().getValue() == 1) {
|
||||
animateActionsViewOut();
|
||||
@@ -2391,9 +2392,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// immediately available.
|
||||
onLayout(false /* changed */, getLeft(), getTop(), getRight(), getBottom());
|
||||
}
|
||||
if (!showAsGrid()) {
|
||||
resetTaskVisuals();
|
||||
}
|
||||
onDismissAnimationEnds();
|
||||
mPendingAnimation = null;
|
||||
}
|
||||
@@ -3721,7 +3719,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return mColorTint;
|
||||
}
|
||||
|
||||
private boolean showAsGrid() {
|
||||
/** Returns {@code true} if the overview tasks are displayed as a grid. */
|
||||
public boolean showAsGrid() {
|
||||
return mOverviewGridEnabled || (mCurrentGestureEndTarget != null
|
||||
&& mSizeStrategy.stateFromGestureEndTarget(
|
||||
mCurrentGestureEndTarget).displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
|
||||
|
||||
@@ -35,6 +35,7 @@ public class Interpolators {
|
||||
public static final Interpolator LINEAR = new LinearInterpolator();
|
||||
|
||||
public static final Interpolator ACCEL = new AccelerateInterpolator();
|
||||
public static final Interpolator ACCEL_0_5 = new AccelerateInterpolator(0.5f);
|
||||
public static final Interpolator ACCEL_0_75 = new AccelerateInterpolator(0.75f);
|
||||
public static final Interpolator ACCEL_1_5 = new AccelerateInterpolator(1.5f);
|
||||
public static final Interpolator ACCEL_2 = new AccelerateInterpolator(2);
|
||||
@@ -149,11 +150,15 @@ public class Interpolators {
|
||||
*/
|
||||
public static Interpolator clampToProgress(Interpolator interpolator, float lowerBound,
|
||||
float upperBound) {
|
||||
if (upperBound <= lowerBound) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"lowerBound (%f) must be less than upperBound (%f)", lowerBound, upperBound));
|
||||
if (upperBound < lowerBound) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("upperBound (%f) must be greater than lowerBound (%f)",
|
||||
upperBound, lowerBound));
|
||||
}
|
||||
return t -> {
|
||||
if (t == lowerBound && t == upperBound) {
|
||||
return t == 0f ? 0 : 1;
|
||||
}
|
||||
if (t < lowerBound) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user