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

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

Launch multiple tasks at once

Bug: 195675206

Change-Id: I31c76e8dfec617092f73e989ce94bf0ab693d0d1
parent 95cb6a9a
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -366,8 +366,8 @@ public final class TaskViewUtils {
     * device is considered in multiWindowMode and things like insets and stuff change
     * and calculations have to be adjusted in the animations for that
     */
    public static void composeRecentsSplitLaunchAnimator(@NonNull TaskView initialView,
            @NonNull TaskView v, @NonNull TransitionInfo transitionInfo,
    public static void composeRecentsSplitLaunchAnimator(@NonNull Task initalTask,
            @NonNull Task secondTask, @NonNull TransitionInfo transitionInfo,
            SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {

        final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2];
@@ -377,7 +377,7 @@ public final class TaskViewUtils {
            final int mode = change.getMode();
            // Find the target tasks' root tasks since those are the split stages that need to
            // be animated (the tasks themselves are children and thus inherit animation).
            if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
            if (taskId == initalTask.key.id || taskId == secondTask.key.id) {
                if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
                    throw new IllegalStateException(
                            "Expected task to be showing, but it is " + mode);
@@ -386,7 +386,7 @@ public final class TaskViewUtils {
                    throw new IllegalStateException("Initiating multi-split launch but the split"
                            + "root of " + taskId + " is already visible or has broken hierarchy.");
                }
                splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] =
                splitRoots[taskId == initalTask.key.id ? 0 : 1] =
                        transitionInfo.getChange(change.getParent());
            }
        }
@@ -406,8 +406,8 @@ public final class TaskViewUtils {
    }

    /** Legacy version (until shell transitions are enabled) */
    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull TaskView initialView,
            @NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull Task initialTask,
            @NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets,
            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
            @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
            @NonNull Runnable finishCallback) {
@@ -416,12 +416,12 @@ public final class TaskViewUtils {
        for (int i = 0; i < appTargets.length; ++i) {
            final int taskId = appTargets[i].taskInfo != null ? appTargets[i].taskInfo.taskId : -1;
            final int mode = appTargets[i].mode;
            if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
            if (taskId == initialTask.key.id || taskId == secondTask.key.id) {
                if (mode != MODE_OPENING) {
                    throw new IllegalStateException(
                            "Expected task to be opening, but it is " + mode);
                }
                splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] = i;
                splitRoots[taskId == initialTask.key.id ? 0 : 1] = i;
            }
        }

+36 −31
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -47,23 +47,21 @@ import com.android.systemui.shared.system.RemoteTransitionRunner;
public class SplitSelectStateController {

    private final SystemUiProxy mSystemUiProxy;
    private TaskView mInitialTaskView;
    private TaskView mSecondTaskView;
    private @StagePosition int mStagePosition;
    private Task mInitialTask;
    private Task mSecondTask;
    private Rect mInitialBounds;
    private final Handler mHandler;

    public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
        mSystemUiProxy = systemUiProxy;
        mHandler = handler;
    }

    /**
     * To be called after first task selected
     */
    public void setInitialTaskSelect(TaskView taskView, @StagePosition int stagePosition,
    public void setInitialTaskSelect(Task taskView, @StagePosition int stagePosition,
            Rect initialBounds) {
        mInitialTaskView = taskView;
        mInitialTask = taskView;
        mStagePosition = stagePosition;
        mInitialBounds = initialBounds;
    }
@@ -71,21 +69,28 @@ public class SplitSelectStateController {
    /**
     * To be called after second task selected
     */
    public void setSecondTaskId(TaskView taskView) {
        mSecondTaskView = taskView;
    public void setSecondTaskId(Task taskView) {
        mSecondTask = taskView;
        launchTasks(mInitialTask, mSecondTask, mStagePosition);
    }

    /**
     * @param stagePosition representing location of task1
     */
    public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition) {
        // Assume initial task is for top/left part of screen
        final int[] taskIds = mStagePosition == STAGE_POSITION_TOP_OR_LEFT
                ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
                : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
        final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
                ? new int[]{task1.key.id, task2.key.id}
                : new int[]{task2.key.id, task1.key.id};
        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
            RemoteSplitLaunchTransitionRunner animationRunner =
                    new RemoteSplitLaunchTransitionRunner(mInitialTaskView, taskView);
                    new RemoteSplitLaunchTransitionRunner(task1, task2);
            mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
                    null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
                    new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
        } else {
            RemoteSplitLaunchAnimationRunner animationRunner =
                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
                    new RemoteSplitLaunchAnimationRunner(task1, task2);
            final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
                    RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
                    300, 150,
@@ -105,19 +110,19 @@ public class SplitSelectStateController {
     */
    private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner {

        private final TaskView mInitialTaskView;
        private final TaskView mTaskView;
        private final Task mInitialTask;
        private final Task mSecondTask;

        RemoteSplitLaunchTransitionRunner(TaskView initialTaskView, TaskView taskView) {
            mInitialTaskView = initialTaskView;
            mTaskView = taskView;
        RemoteSplitLaunchTransitionRunner(Task initialTask, Task secondTask) {
            mInitialTask = initialTask;
            mSecondTask = secondTask;
        }

        @Override
        public void startAnimation(IBinder transition, TransitionInfo info,
                SurfaceControl.Transaction t, Runnable finishCallback) {
            TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskView, mTaskView,
                    info, t, finishCallback);
            TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTask,
                    mSecondTask, info, t, finishCallback);
            // After successful launch, call resetState
            resetState();
        }
@@ -129,20 +134,20 @@ public class SplitSelectStateController {
     */
    private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat {

        private final TaskView mInitialTaskView;
        private final TaskView mTaskView;
        private final Task mInitialTask;
        private final Task mSecondTask;

        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
            mInitialTaskView = initialTaskView;
            mTaskView = taskView;
        RemoteSplitLaunchAnimationRunner(Task initialTask, Task secondTask) {
            mInitialTask = initialTask;
            mSecondTask = secondTask;
        }

        @Override
        public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps,
                RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
                Runnable finishedCallback) {
            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTaskView, mTaskView, apps,
                    wallpapers, nonApps, finishedCallback);
            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask,
                    mSecondTask, apps, wallpapers, nonApps, finishedCallback);
            // After successful launch, call resetState
            resetState();
        }
@@ -157,8 +162,8 @@ public class SplitSelectStateController {
     * To be called if split select was cancelled
     */
    public void resetState() {
        mInitialTaskView = null;
        mSecondTaskView = null;
        mInitialTask = null;
        mSecondTask = null;
        mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
        mInitialBounds = null;
    }
@@ -168,7 +173,7 @@ public class SplitSelectStateController {
     *         chosen
     */
    public boolean isSplitSelectActive() {
        return mInitialTaskView != null && mSecondTaskView == null;
        return mInitialTask != null && mSecondTask == null;
    }

    public Rect getInitialBounds() {
+8 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import android.content.Context;
import android.util.AttributeSet;

import com.android.launcher3.R;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.TaskThumbnailCache;
@@ -94,6 +95,13 @@ public class GroupedTaskView extends TaskView {
        }
    }

    @Override
    public RunnableList launchTaskAnimated() {
        getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
                SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT);
        return null;
    }

    @Override
    public void onRecycle() {
        super.onRecycle();
+3 −2
Original line number Diff line number Diff line
@@ -3568,7 +3568,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        mSplitHiddenTaskView = taskView;
        Rect initialBounds = new Rect(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
                taskView.getBottom());
        mSplitSelectStateController.setInitialTaskSelect(taskView, stagePosition, initialBounds);
        mSplitSelectStateController.setInitialTaskSelect(taskView.getTask(),
                stagePosition, initialBounds);
        mSplitHiddenTaskViewIndex = indexOfChild(taskView);
        if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
            finishRecentsAnimation(true, null);
@@ -3609,7 +3610,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
                secondTaskEndingBounds, taskView.getThumbnail(),
                true /*fadeWithThumbnail*/);
        pendingAnimation.addEndListener(aBoolean -> {
            mSplitSelectStateController.setSecondTaskId(taskView);
            mSplitSelectStateController.setSecondTaskId(taskView.getTask());
            resetFromSplitSelectionState();
        });
        mSecondSplitHiddenTaskView = taskView;