Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 049434a5 authored by Pat Manning's avatar Pat Manning Committed by Android (Google) Code Review
Browse files

Merge "Animate task translation on dismissal." into sc-dev

parents a79cd201 cc64218e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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>

+30 −2
Original line number Diff line number Diff line
@@ -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,
+51 −52
Original line number Diff line number Diff line
@@ -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()));
+8 −3
Original line number Diff line number Diff line
@@ -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;
            }