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

Commit e7e7a6e5 authored by Vinit Nayak's avatar Vinit Nayak
Browse files

Keep track of multiple TasksIDs and Targets in GestureState

* Quickswitching between fullscreen and split tasks breaks split,
need that to be fixed to further test these code changes

Bug: 236226779
Change-Id: I332ad6e2d98760ec1d691dae76e8e3ab8b839c75
parent 3396b5c3
Loading
Loading
Loading
Loading
+55 −29
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -150,6 +151,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.function.Consumer;

/**
@@ -656,11 +658,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,

    protected void notifyGestureAnimationStartToRecents() {
        Task[] runningTasks;
        TopTaskTracker.CachedTaskInfo cachedTaskInfo = mGestureState.getRunningTask();
        if (mIsSwipeForSplit) {
            int[] splitTaskIds = TopTaskTracker.INSTANCE.get(mContext).getRunningSplitTaskIds();
            runningTasks = mGestureState.getRunningTask().getPlaceholderTasks(splitTaskIds);
            runningTasks = cachedTaskInfo.getPlaceholderTasks(splitTaskIds);
        } else {
            runningTasks = mGestureState.getRunningTask().getPlaceholderTasks();
            runningTasks = cachedTaskInfo.getPlaceholderTasks();
        }

        // Safeguard against any null tasks being sent to recents view, happens when quickswitching
@@ -733,8 +736,11 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
                || mRecentsView == null) {
            return;
        }
        // looking at single target is fine here since either app of a split pair would
        // have their "isInRecents" field set? (that's what this is used for below)
        RemoteAnimationTarget runningTaskTarget = mRecentsAnimationTargets != null
                ? mRecentsAnimationTargets.findTask(mGestureState.getRunningTaskId())
                ? mRecentsAnimationTargets
                .findTask(mGestureState.getTopRunningTaskId())
                : null;
        final boolean recentsAttachedToAppWindow;
        if (mIsInAllAppsRegion) {
@@ -1190,7 +1196,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
            return false;
        }
        boolean hasStartedTaskBefore = Arrays.stream(appearedTaskTarget).anyMatch(
                targetCompat -> targetCompat.taskId == mGestureState.getLastStartedTaskId());
                mGestureState.mLastStartedTaskIdPredicate);
        if (mStateCallback.hasStates(STATE_START_NEW_TASK) && hasStartedTaskBefore) {
            reset();
            return true;
@@ -1456,9 +1462,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
        @Override
        public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
                boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
            if (task.taskId == mGestureState.getRunningTaskId()
            boolean taskRunningAndNotHome = Arrays.stream(mGestureState
                            .getRunningTaskIds(true /*getMultipleTasks*/))
                    .anyMatch(taskId -> task.taskId == taskId
                            && task.configuration.windowConfiguration.getActivityType()
                    != ACTIVITY_TYPE_HOME) {
                            != ACTIVITY_TYPE_HOME);
            if (taskRunningAndNotHome) {
                // Since this is an edge case, just cancel and relaunch with default activity
                // options (since we don't know if there's an associated app icon to launch from)
                endRunningWindowAnim(true /* cancel */);
@@ -1500,8 +1509,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,

        if (mGestureState.getEndTarget() == HOME) {
            getOrientationHandler().adjustFloatingIconStartVelocity(velocityPxPerMs);
            // Take first task ID, if there are multiple we don't have any special home
            // animation so doesn't matter for splitscreen.. though the "allowEnterPip" might change
            // depending on which task it is..
            final RemoteAnimationTarget runningTaskTarget = mRecentsAnimationTargets != null
                    ? mRecentsAnimationTargets.findTask(mGestureState.getRunningTaskId())
                    ? mRecentsAnimationTargets
                    .findTask(mGestureState.getTopRunningTaskId())
                    : null;
            final ArrayList<IBinder> cookies = runningTaskTarget != null
                    ? runningTaskTarget.taskInfo.launchCookies
@@ -1530,7 +1543,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,

                // grab a screenshot before the PipContentOverlay gets parented on top of the task
                UI_HELPER_EXECUTOR.execute(() -> {
                    final int taskId = mGestureState.getRunningTaskId();
                    // Directly use top task, split to pip handled on shell side
                    final int taskId = mGestureState.getTopRunningTaskId();
                    mTaskSnapshotCache.put(taskId,
                            mRecentsAnimationController.screenshotTask(taskId));
                });
@@ -1994,13 +2008,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
            // If there are no targets, then we don't need to capture anything
            mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
        } else {
            final int runningTaskId = mGestureState.getRunningTaskId();
            boolean finishTransitionPosted = false;
            // If we already have cached screenshot(s) from running tasks, skip update
            boolean shouldUpdate = false;
            int[] runningTaskIds = mIsSwipeForSplit
                    ? TopTaskTracker.INSTANCE.get(mContext).getRunningSplitTaskIds()
                    : new int[]{runningTaskId};
            int[] runningTaskIds = mGestureState.getRunningTaskIds(mIsSwipeForSplit);
            for (int id : runningTaskIds) {
                if (!mTaskSnapshotCache.containsKey(id)) {
                    shouldUpdate = true;
@@ -2205,16 +2216,27 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
        if (!mCanceled) {
            TaskView nextTask = mRecentsView == null ? null : mRecentsView.getNextPageTaskView();
            if (nextTask != null) {
                Task.TaskKey nextTaskKey = nextTask.getTask().key;
                int taskId = nextTaskKey.id;
                mGestureState.updateLastStartedTaskId(taskId);
                boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
                        .contains(taskId);
                int[] taskIds = nextTask.getTaskIds();
                StringBuilder nextTaskLog = new StringBuilder();
                for (TaskIdAttributeContainer c : nextTask.getTaskIdAttributeContainers()) {
                    if (c == null) {
                        continue;
                    }
                    nextTaskLog
                            .append("[id: ")
                            .append(c.getTask().key.id)
                            .append(", pkg: ")
                            .append(c.getTask().key.getPackageName())
                            .append("] | ");
                }
                mGestureState.updateLastStartedTaskIds(taskIds);
                boolean hasTaskPreviouslyAppeared = Arrays.stream(taskIds).anyMatch(
                                taskId -> mGestureState.getPreviouslyAppearedTaskIds()
                                        .contains(taskId));
                if (!hasTaskPreviouslyAppeared) {
                    ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED);
                }
                ActiveGestureLog.INSTANCE.addLog("Launching task: id=" + taskId
                        + " pkg=" + nextTaskKey.getPackageName());
                ActiveGestureLog.INSTANCE.addLog("Launching task: " + nextTaskLog);
                nextTask.launchTask(success -> {
                    resultCallback.accept(success);
                    if (success) {
@@ -2284,7 +2306,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
    public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) {
        if (mRecentsAnimationController != null) {
            boolean hasStartedTaskBefore = Arrays.stream(appearedTaskTargets).anyMatch(
                    targetCompat -> targetCompat.taskId == mGestureState.getLastStartedTaskId());
                    mGestureState.mLastStartedTaskIdPredicate);
            if (!mStateCallback.hasStates(STATE_GESTURE_COMPLETED) && !hasStartedTaskBefore) {
                // This is a special case, if a task is started mid-gesture that wasn't a part of a
                // previous quickswitch task launch, then cancel the animation back to the app
@@ -2297,8 +2319,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
            } else if (handleTaskAppeared(appearedTaskTargets)) {
                Optional<RemoteAnimationTarget> taskTargetOptional =
                        Arrays.stream(appearedTaskTargets)
                                .filter(targetCompat ->
                                        targetCompat.taskId == mGestureState.getLastStartedTaskId())
                                .filter(mGestureState.mLastStartedTaskIdPredicate)
                                .findFirst();
                if (!taskTargetOptional.isPresent()) {
                    ActiveGestureLog.INSTANCE.addLog("No appeared task matching started task id");
@@ -2367,10 +2388,15 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
     * resume if we finish the controller.
     */
    protected int getLastAppearedTaskIndex() {
        return mRecentsView == null
                ? -1
                : mGestureState.getLastAppearedTaskId() != -1
                        ? mRecentsView.getTaskIndexForId(mGestureState.getLastAppearedTaskId())
        if (mRecentsView == null) {
            return -1;
        }

        OptionalInt firstValidTaskId = Arrays.stream(mGestureState.getLastAppearedTaskIds())
                .filter(i -> i != -1)
                .findFirst();
        return firstValidTaskId.isPresent()
                ? mRecentsView.getTaskIndexForId(firstValidTaskId.getAsInt())
                : mRecentsView.getRunningTaskIndex();
    }

@@ -2379,7 +2405,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
     * but before that task appeared.
     */
    protected boolean hasStartedNewTask() {
        return mGestureState.getLastStartedTaskId() != -1;
        return mGestureState.getLastStartedTaskIds()[0] != -1;
    }

    /**
+59 −17
Original line number Diff line number Diff line
@@ -15,8 +15,9 @@
 */
package com.android.quickstep;

import static android.app.ActivityTaskManager.INVALID_TASK_ID;

import static com.android.launcher3.MotionEventsUtils.isTrackpadFourFingerSwipe;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.launcher3.MotionEventsUtils.isTrackpadThreeFingerSwipe;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -44,10 +45,12 @@ import com.android.systemui.shared.recents.model.ThumbnailData;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

/**
 * Manages the state for an active system gesture, listens for events from the system and Launcher,
@@ -56,6 +59,18 @@ import java.util.Set;
@TargetApi(Build.VERSION_CODES.R)
public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationListener {

    final Predicate<RemoteAnimationTarget> mLastStartedTaskIdPredicate = new Predicate<>() {
        @Override
        public boolean test(RemoteAnimationTarget targetCompat) {
            for (int taskId : mLastStartedTaskId) {
                if (targetCompat.taskId == taskId) {
                    return true;
                }
            }
            return false;
        }
    };

    /**
     * Defines the end targets of a gesture and the associated state.
     */
@@ -161,9 +176,9 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
    private TrackpadGestureType mTrackpadGestureType = TrackpadGestureType.NONE;
    private CachedTaskInfo mRunningTask;
    private GestureEndTarget mEndTarget;
    private RemoteAnimationTarget mLastAppearedTaskTarget;
    private RemoteAnimationTarget[] mLastAppearedTaskTargets;
    private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>();
    private int mLastStartedTaskId = -1;
    private int[] mLastStartedTaskId = new int[]{INVALID_TASK_ID, INVALID_TASK_ID};
    private RecentsAnimationController mRecentsAnimationController;
    private HashMap<Integer, ThumbnailData> mRecentsAnimationCanceledSnapshots;

@@ -189,7 +204,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
        mGestureId = other.mGestureId;
        mRunningTask = other.mRunningTask;
        mEndTarget = other.mEndTarget;
        mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
        mLastAppearedTaskTargets = other.mLastAppearedTaskTargets;
        mPreviouslyAppearedTaskIds = other.mPreviouslyAppearedTaskIds;
        mLastStartedTaskId = other.mLastStartedTaskId;
    }
@@ -293,10 +308,29 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
    }

    /**
     * @return the running task id for this gesture.
     * @param getMultipleTasks Whether multiple tasks or not are to be returned (for split)
     * @return the running task ids for this gesture.
     */
    public int[] getRunningTaskIds(boolean getMultipleTasks) {
        if (mRunningTask == null) {
            return new int[]{INVALID_TASK_ID, INVALID_TASK_ID};
        } else {
            int cachedTasksSize = mRunningTask.mAllCachedTasks.size();
            int count = Math.min(cachedTasksSize, getMultipleTasks ? 2 : 1);
            int[] runningTaskIds = new int[count];
            for (int i = 0; i < count; i++) {
                runningTaskIds[i] = mRunningTask.mAllCachedTasks.get(i).taskId;
            }
            return runningTaskIds;
        }
    }

    /**
     * @see #getRunningTaskIds(boolean)
     * @return the single top-most running taskId for this gesture
     */
    public int getRunningTaskId() {
        return mRunningTask != null ? mRunningTask.getTaskId() : -1;
    public int getTopRunningTaskId() {
        return getRunningTaskIds(false /*getMultipleTasks*/)[0];
    }

    /**
@@ -309,18 +343,26 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
    /**
     * Updates the last task that appeared during this gesture.
     */
    public void updateLastAppearedTaskTarget(RemoteAnimationTarget lastAppearedTaskTarget) {
        mLastAppearedTaskTarget = lastAppearedTaskTarget;
        if (lastAppearedTaskTarget != null) {
            mPreviouslyAppearedTaskIds.add(lastAppearedTaskTarget.taskId);
    public void updateLastAppearedTaskTargets(RemoteAnimationTarget[] lastAppearedTaskTargets) {
        mLastAppearedTaskTargets = lastAppearedTaskTargets;
        for (RemoteAnimationTarget target : lastAppearedTaskTargets) {
            if (target == null) {
                continue;
            }
            mPreviouslyAppearedTaskIds.add(target.taskId);
        }
    }

    /**
     * @return The id of the task that appeared during this gesture.
     */
    public int getLastAppearedTaskId() {
        return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1;
    public int[] getLastAppearedTaskIds() {
        if (mLastAppearedTaskTargets == null) {
            return new int[]{INVALID_TASK_ID, INVALID_TASK_ID};
        } else {
            return Arrays.stream(mLastAppearedTaskTargets)
                    .mapToInt(target -> target != null ? target.taskId : INVALID_TASK_ID).toArray();
        }
    }

    public void updatePreviouslyAppearedTaskIds(Set<Integer> previouslyAppearedTaskIds) {
@@ -334,7 +376,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
    /**
     * Updates the last task that we started via startActivityFromRecents() during this gesture.
     */
    public void updateLastStartedTaskId(int lastStartedTaskId) {
    public void updateLastStartedTaskIds(int[] lastStartedTaskId) {
        mLastStartedTaskId = lastStartedTaskId;
    }

@@ -342,7 +384,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
     * @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() {
    public int[] getLastStartedTaskIds() {
        return mLastStartedTaskId;
    }

@@ -478,8 +520,8 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
        pw.println("  gestureID=" + mGestureId);
        pw.println("  runningTask=" + mRunningTask);
        pw.println("  endTarget=" + mEndTarget);
        pw.println("  lastAppearedTaskTargetId=" + getLastAppearedTaskId());
        pw.println("  lastStartedTaskId=" + mLastStartedTaskId);
        pw.println("  lastAppearedTaskTargetId=" + Arrays.toString(mLastAppearedTaskTargets));
        pw.println("  lastStartedTaskId=" + Arrays.toString(mLastStartedTaskId));
        pw.println("  isRecentsAnimationRunning=" + isRecentsAnimationRunning());
    }
}
+2 −3
Original line number Diff line number Diff line
@@ -115,8 +115,8 @@ public class RecentsAnimationController {
     * {@link RecentsAnimationCallbacks#onTasksAppeared}}.
     */
    @UiThread
    public void removeTaskTarget(@NonNull RemoteAnimationTarget target) {
        UI_HELPER_EXECUTOR.execute(() -> mController.removeTask(target.taskId));
    public void removeTaskTarget(int targetTaskId) {
        UI_HELPER_EXECUTOR.execute(() -> mController.removeTask(targetTaskId));
    }

    @UiThread
@@ -167,7 +167,6 @@ public class RecentsAnimationController {
                /* event= */ "finishRecentsAnimation",
                /* extras= */ toRecents,
                /* gestureEvent= */ FINISH_RECENTS_ANIMATION);

        // Finish not yet requested
        mFinishRequested = true;
        mFinishTargetIsLauncher = toRecents;
+21 −11
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
    private RecentsAnimationTargets mTargets;
    // Temporary until we can hook into gesture state events
    private GestureState mLastGestureState;
    private RemoteAnimationTarget mLastAppearedTaskTarget;
    private RemoteAnimationTarget[] mLastAppearedTaskTargets;
    private Runnable mLiveTileCleanUpHandler;
    private Context mCtx;

@@ -141,8 +141,15 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
                }
                mController = controller;
                mTargets = targets;
                mLastAppearedTaskTarget = mTargets.findTask(mLastGestureState.getRunningTaskId());
                mLastGestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
                // TODO(b/236226779): We can probably get away w/ setting mLastAppearedTaskTargets
                //  to all appeared targets directly vs just looking at running ones
                int[] runningTaskIds = mLastGestureState.getRunningTaskIds(targets.apps.length > 1);
                mLastAppearedTaskTargets = new RemoteAnimationTarget[runningTaskIds.length];
                for (int i = 0; i < runningTaskIds.length; i++) {
                    RemoteAnimationTarget task = mTargets.findTask(runningTaskIds[i]);
                    mLastAppearedTaskTargets[i] = task;
                }
                mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets);
            }

            @Override
@@ -196,14 +203,17 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
                            true /*shown*/, null /* animatorHandler */);
                }
                if (mController != null) {
                    if (mLastAppearedTaskTarget == null
                            || appearedTaskTarget.taskId != mLastAppearedTaskTarget.taskId) {
                        if (mLastAppearedTaskTarget != null) {
                            mController.removeTaskTarget(mLastAppearedTaskTarget);
                    if (mLastAppearedTaskTargets != null) {
                        for (RemoteAnimationTarget lastTarget : mLastAppearedTaskTargets) {
                            for (RemoteAnimationTarget appearedTarget : appearedTaskTargets) {
                                if (appearedTarget.taskId != lastTarget.taskId) {
                                    mController.removeTaskTarget(lastTarget.taskId);
                                }
                            }
                        }
                        mLastAppearedTaskTarget = appearedTaskTarget;
                        mLastGestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
                    }
                    mLastAppearedTaskTargets = appearedTaskTargets;
                    mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets);
                }
            }

@@ -268,7 +278,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
        mCallbacks.addListener(gestureState);
        gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED
                | STATE_RECENTS_ANIMATION_STARTED);
        gestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
        gestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets);
        return mCallbacks;
    }

@@ -369,7 +379,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
        mCallbacks = null;
        mTargets = null;
        mLastGestureState = null;
        mLastAppearedTaskTarget = null;
        mLastAppearedTaskTargets = null;
    }

    @Nullable
+1 −1
Original line number Diff line number Diff line
@@ -210,7 +210,7 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta

        @Nullable
        private final RunningTaskInfo mTopTask;
        private final List<RunningTaskInfo> mAllCachedTasks;
        public final List<RunningTaskInfo> mAllCachedTasks;

        CachedTaskInfo(List<RunningTaskInfo> allCachedTasks) {
            mAllCachedTasks = allCachedTasks;
Loading