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

Commit a57000c3 authored by Tony Wickham's avatar Tony Wickham
Browse files

Restart running task if another task was started but not appeared

If we just finish the controller to resume the running task like
we normally would, the delayed task will appear on top when it's
ready. Instead, we need to start the original task in this case.

- Move mLastStartedTaskId to GestureState, shared between swipe
  handlers when continuing the gesture.
- Update logic to change LAST_TASK to NEW_TASK if a task was
  started (but not appeared) during the same gesture; likewise,
  only change NEW_TASK to LAST_TASK if no task was started.
- Finish the controller when successfully starting the task
  that already appeared, since we won't get onTaskAppeared().

Bug: 156132424
Change-Id: I1e9af297840745ab3d5e90214425f10a2616d90a
parent ed31f24d
Loading
Loading
Loading
Loading
+29 −3
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.util.Pair;
import android.view.MotionEvent;
import android.view.animation.Interpolator;

import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -128,7 +129,6 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
    protected MultiStateCallback mStateCallback;

    protected boolean mCanceled;
    protected int mLastStartedTaskId = -1;

    private boolean mRecentsViewScrollLinked = false;

@@ -218,11 +218,16 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
            if (!mCanceled) {
                TaskView nextTask = mRecentsView.getTaskView(taskId);
                if (nextTask != null) {
                    mLastStartedTaskId = taskId;
                    mGestureState.updateLastStartedTaskId(taskId);
                    nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
                            success -> {
                                resultCallback.accept(success);
                                if (!success) {
                                if (success) {
                                    if (mRecentsView.indexOfChild(nextTask)
                                            == getLastAppearedTaskIndex()) {
                                        onRestartLastAppearedTask();
                                    }
                                } else {
                                    mActivityInterface.onLaunchTaskFailed();
                                    nextTask.notifyTaskLaunchFailed(TAG);
                                    mRecentsAnimationController.finish(true /* toRecents */, null);
@@ -235,6 +240,19 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
        ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
    }

    /**
     * Called when we successfully startNewTask() on the task that was previously running. Normally
     * we call resumeLastTask() when returning to the previously running task, but this handles a
     * specific edge case: if we switch from A to B, and back to A before B appears, we need to
     * start A again to ensure it stays on top.
     */
    @CallSuper
    protected void onRestartLastAppearedTask() {
        // Finish the controller here, since we won't get onTaskAppeared() for a task that already
        // appeared.
        mRecentsAnimationController.finish(false, null);
    }

    /**
     * Runs the given {@param action} if the recents animation has already started, or queues it to
     * be run when it is next started.
@@ -331,6 +349,14 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
                : mRecentsView.getRunningTaskIndex();
    }

    /**
     * @return Whether we are continuing a gesture that already landed on a new task,
     * but before that task appeared.
     */
    protected boolean hasStartedNewTask() {
        return mGestureState.getLastStartedTaskId() != -1;
    }

    protected void initTransitionEndpoints(DeviceProfile dp) {
        mDp = dp;

+15 −6
Original line number Diff line number Diff line
@@ -725,7 +725,8 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
        if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
            return false;
        }
        if (appearedTaskTarget.taskId == mLastStartedTaskId) {
        if (mGestureState.getEndTarget() == NEW_TASK
                && appearedTaskTarget.taskId == mGestureState.getLastStartedTaskId()) {
            reset();
            return true;
        }
@@ -1016,17 +1017,19 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
                    if (mRecentsView != null) {
                        int taskToLaunch = mRecentsView.getNextPage();
                        int runningTask = getLastAppearedTaskIndex();
                        if (target == NEW_TASK && taskToLaunch == runningTask) {
                        boolean hasStartedNewTask = hasStartedNewTask();
                        if (target == NEW_TASK && taskToLaunch == runningTask
                                && !hasStartedNewTask) {
                            // We are about to launch the current running task, so use LAST_TASK
                            // state instead of NEW_TASK. This could happen, for example, if our
                            // scroll is aborted after we determined the target to be NEW_TASK.
                            mGestureState.setEndTarget(LAST_TASK);
                        } else if (target == LAST_TASK && taskToLaunch != runningTask) {
                        } else if (target == LAST_TASK && hasStartedNewTask) {
                            // We are about to re-launch the previously running task, but we can't
                            // just finish the controller like we normally would because that would
                            // instead resume the last task that appeared. As a workaround, launch
                            // the task as if it were a new task.
                            // TODO: is this expected?
                            // instead resume the last task that appeared, and not ensure that this
                            // task is restored to the top. To address this, re-launch the task as
                            // if it were a new task.
                            mGestureState.setEndTarget(NEW_TASK);
                        }
                    }
@@ -1164,6 +1167,12 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
        });
    }

    @Override
    protected void onRestartLastAppearedTask() {
        super.onRestartLastAppearedTask();
        reset();
    }

    private void reset() {
        mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
    }
+1 −0
Original line number Diff line number Diff line
@@ -518,6 +518,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
                ActiveGestureLog.INSTANCE.generateAndSetLogId());
        if (mTaskAnimationManager.isRecentsAnimationRunning()) {
            gestureState.updateRunningTask(mGestureState.getRunningTask());
            gestureState.updateLastStartedTaskId(mGestureState.getLastStartedTaskId());
        } else {
            gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
                    () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
+18 −1
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
 */
package com.android.quickstep;

import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;

import android.app.ActivityManager;
@@ -121,6 +120,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
    private ActivityManager.RunningTaskInfo mRunningTask;
    private GestureEndTarget mEndTarget;
    private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
    private int mLastStartedTaskId = -1;

    public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
        mHomeIntent = componentObserver.getHomeIntent();
@@ -139,6 +139,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
        mRunningTask = other.mRunningTask;
        mEndTarget = other.mEndTarget;
        mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
        mLastStartedTaskId = other.mLastStartedTaskId;
    }

    public GestureState() {
@@ -234,6 +235,21 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
        return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1;
    }

    /**
     * Updates the last task that we started via startActivityFromRecents() during this gesture.
     */
    public void updateLastStartedTaskId(int lastStartedTaskId) {
        mLastStartedTaskId = lastStartedTaskId;
    }

    /**
     * @return The id of the task that was most recently started during this gesture, or -1 if
     * no task has been started yet (i.e. we haven't settled on a new task).
     */
    public int getLastStartedTaskId() {
        return mLastStartedTaskId;
    }

    /**
     * @return the end target for this gesture (if known).
     */
@@ -300,6 +316,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
        pw.println("  runningTask=" + mRunningTask);
        pw.println("  endTarget=" + mEndTarget);
        pw.println("  lastAppearedTaskTarget=" + mLastAppearedTaskTarget);
        pw.println("  lastStartedTaskId=" + mLastStartedTaskId);
        pw.println("  isRecentsAnimationRunning=" + isRecentsAnimationRunning());
    }
}