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

Commit 61560f06 authored by Winson's avatar Winson
Browse files

Fixes several animation issues related to a dismissing task.

- Previously we did not properly cancel the animations when the user 
  interacted with the stack while a task was being dismissed.  Now, on 
  touch down, we only cancel the non-dismissing tasks, and in doing so,
  set their task override if there is a dismissing task (so that the 
  stack can scroll correctly), and update the surrounding task views
  if the dismiss update comes from the currently dismissing task.  
  (or in other words, the surrounding task animations will only be a 
  function of the current task being dismissed)

Bug: 28448670
Change-Id: If7b8ed3f1fe342114ae0f6dd9dbff0d48204f31e
parent aa0dea7a
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.recents.events.ui;

import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.AnimationProps;
import com.android.systemui.recents.views.TaskView;

/**
@@ -27,9 +28,11 @@ public class TaskViewDismissedEvent extends EventBus.Event {

    public final Task task;
    public final TaskView taskView;
    public final AnimationProps animation;

    public TaskViewDismissedEvent(Task task, TaskView taskView) {
    public TaskViewDismissedEvent(Task task, TaskView taskView, AnimationProps animation) {
        this.task = task;
        this.taskView = taskView;
        this.animation = animation;
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -310,6 +310,11 @@ public class TaskStackAnimationHelper {
        for (int i = 0; i < taskViewCount; i++) {
            int taskIndexFromFront = taskViewCount - i - 1;
            TaskView tv = taskViews.get(i);
            Task task = tv.getTask();

            if (mStackView.isIgnoredTask(task)) {
                continue;
            }

            // Animate the tasks down
            AnimationProps taskAnimation;
@@ -386,7 +391,7 @@ public class TaskStackAnimationHelper {
    public void startDeleteTaskAnimation(final TaskView deleteTaskView,
            final ReferenceCountedTrigger postAnimationTrigger) {
        TaskStackViewTouchHandler touchHandler = mStackView.getTouchHandler();
        touchHandler.onBeginDrag(deleteTaskView);
        touchHandler.onBeginManualDrag(deleteTaskView);

        postAnimationTrigger.increment();
        postAnimationTrigger.addLastDecrementRunnable(() -> {
+18 −0
Original line number Diff line number Diff line
@@ -623,6 +623,24 @@ public class TaskStackLayoutAlgorithm {
        }
    }

    /**
     * Adds and override task progress for the given task when transitioning from focused to
     * unfocused state.
     */
    public void addUnfocusedTaskOverride(TaskView taskView, float stackScroll) {
        mFocusedRange.offset(stackScroll);
        mUnfocusedRange.offset(stackScroll);

        Task task = taskView.getTask();
        int top = taskView.getTop() - mTaskRect.top;
        float focusedRangeX = getNormalizedXFromFocusedY(top, FROM_TOP);
        float unfocusedRangeX = getNormalizedXFromUnfocusedY(top, FROM_TOP);
        float unfocusedTaskProgress = stackScroll + mUnfocusedRange.getAbsoluteX(unfocusedRangeX);
        if (Float.compare(focusedRangeX, unfocusedRangeX) != 0) {
            mTaskIndexOverrideMap.put(task.key.id, unfocusedTaskProgress);
        }
    }

    public void clearUnfocusedTaskOverrides() {
        mTaskIndexOverrideMap.clear();
    }
+2 −3
Original line number Diff line number Diff line
@@ -1671,7 +1671,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal

    public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
        // Stop any scrolling
        mTouchHandler.finishAnimations();
        mTouchHandler.cancelNonDismissTaskAnimations();
        mStackScroller.stopScroller();
        mStackScroller.stopBoundScrollAnimation();
        cancelDeferredTaskViewLayoutAnimation();
@@ -1729,8 +1729,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                R.string.accessibility_recents_item_dismissed, event.task.title));

        // Remove the task from the stack
        mStack.removeTask(event.task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
                Interpolators.FAST_OUT_SLOW_IN), false /* fromDockGesture */);
        mStack.removeTask(event.task, event.animation, false /* fromDockGesture */);
        EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));

        MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS,
+64 −26
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewParent;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -189,16 +188,31 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
    }

    /**
     * Finishes all scroll-fling and swipe animations currently running.
     * Finishes all scroll-fling and non-dismissing animations currently running.
     */
    public void finishAnimations() {
    public void cancelNonDismissTaskAnimations() {
        Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator);
        ArrayMap<View, Animator> existingAnimators = new ArrayMap<>(mSwipeHelperAnimations);
        for (int i = 0; i < existingAnimators.size(); i++) {
            existingAnimators.get(existingAnimators.keyAt(i)).end();
        if (!mSwipeHelperAnimations.isEmpty()) {
            // For the non-dismissing tasks, freeze the position into the task overrides
            List<TaskView> taskViews = mSv.getTaskViews();
            for (int i = taskViews.size() - 1; i >= 0; i--) {
                TaskView tv = taskViews.get(i);

                if (mSv.isIgnoredTask(tv.getTask())) {
                    continue;
                }

                tv.cancelTransformAnimation();
                mSv.getStackAlgorithm().addUnfocusedTaskOverride(tv, mTargetStackScroll);
            }
            mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
            // Update the scroll to the final scroll position from onBeginDrag()
            mSv.getScroller().setStackScroll(mTargetStackScroll, null);

            mSwipeHelperAnimations.clear();
        }
        mActiveTaskView = null;
    }

    private boolean handleTouchEvent(MotionEvent ev) {
        // Short circuit if we have no children
@@ -210,6 +224,13 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
        int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                // Stop the current scroll if it is still flinging
                mScroller.stopScroller();
                mScroller.stopBoundScrollAnimation();
                mScroller.resetDeltaScroll();
                cancelNonDismissTaskAnimations();
                mSv.cancelDeferredTaskViewLayoutAnimation();

                // Save the touch down info
                mDownX = (int) ev.getX();
                mDownY = (int) ev.getY();
@@ -218,13 +239,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
                mActivePointerId = ev.getPointerId(0);
                mActiveTaskView = findViewAtPoint(mDownX, mDownY);

                // Stop the current scroll if it is still flinging
                mSv.cancelDeferredTaskViewLayoutAnimation();
                mScroller.stopScroller();
                mScroller.stopBoundScrollAnimation();
                mScroller.resetDeltaScroll();
                finishAnimations();

                // Initialize the velocity tracker
                initOrResetVelocityTracker();
                mVelocityTracker.addMovement(ev);
@@ -431,8 +445,18 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
    public boolean canChildBeDismissed(View v) {
        // Disallow dismissing an already dismissed task
        TaskView tv = (TaskView) v;
        Task task = tv.getTask();
        return !mSwipeHelperAnimations.containsKey(v) &&
                (mSv.getStack().indexOfStackTask(tv.getTask()) != -1);
                (mSv.getStack().indexOfStackTask(task) != -1);
    }

    /**
     * Starts a manual drag that goes through the same swipe helper path.
     */
    public void onBeginManualDrag(TaskView v) {
        mActiveTaskView = v;
        mSwipeHelperAnimations.put(v, null);
        onBeginDrag(v);
    }

    @Override
@@ -453,7 +477,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
        mSv.addIgnoreTask(tv.getTask());

        // Determine if we are animating the other tasks while dismissing this task
        mCurrentTasks = mSv.getStack().getStackTasks();
        mCurrentTasks = new ArrayList<Task>(mSv.getStack().getStackTasks());
        MutableBoolean isFrontMostTask = new MutableBoolean(false);
        Task anchorTask = mSv.findAnchorTask(mCurrentTasks, isFrontMostTask);
        TaskStackLayoutAlgorithm layoutAlgorithm = mSv.getStackAlgorithm();
@@ -513,7 +537,12 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {

    @Override
    public boolean updateSwipeProgress(View v, boolean dismissable, float swipeProgress) {
        updateTaskViewTransforms(Interpolators.FAST_OUT_SLOW_IN.getInterpolation(swipeProgress));
        // Only update the swipe progress for the surrounding tasks if the dismiss animation was not
        // preempted from a call to cancelNonDismissTaskAnimations
        if (mActiveTaskView == v || mSwipeHelperAnimations.containsKey(v)) {
            updateTaskViewTransforms(
                    Interpolators.FAST_OUT_SLOW_IN.getInterpolation(swipeProgress));
        }
        return true;
    }

@@ -528,15 +557,24 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
        tv.setClipViewInStack(true);
        // Re-enable touch events from this task view
        tv.setTouchEnabled(true);
        // Remove the task view from the stack
        EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
        // Update the scroll to the final scroll position from onBeginDrag()
        // Remove the task view from the stack, ignoring the animation if we've started dragging
        // again
        EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv,
                mSwipeHelperAnimations.containsKey(v)
                    ? new AnimationProps(TaskStackView.DEFAULT_SYNC_STACK_DURATION,
                        Interpolators.FAST_OUT_SLOW_IN)
                    : null));
        // Only update the final scroll and layout state (set in onBeginDrag()) if the dismiss
        // animation was not preempted from a call to cancelNonDismissTaskAnimations
        if (mSwipeHelperAnimations.containsKey(v)) {
            // Update the scroll to the final scroll position
            mSv.getScroller().setStackScroll(mTargetStackScroll, null);
            // Update the focus state to the final focus state
            mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
            mSv.getStackAlgorithm().clearUnfocusedTaskOverrides();
            // Stop tracking this deletion animation
            mSwipeHelperAnimations.remove(v);
        }
        // Keep track of deletions by keyboard
        MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source",
                Constants.Metrics.DismissSourceSwipeGesture);
Loading