Changes to use new startTasks API

When shell transitions is enabled, this will use the
newer multi-task-launch api and control the animation.

There is no actual animation yet, this just adds the
infrastructure.

Bug: 182002789
Test: enable developer option and enter split via recents
Change-Id: If5be104a86e7b5f743f85efed20b0d2bf1b8bfd1
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index e9ded8a..4415b51 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -219,7 +219,7 @@
         mSplitPlaceholderView = findViewById(R.id.split_placeholder);
         RecentsView overviewPanel = (RecentsView) getOverviewPanel();
         mSplitPlaceholderView.init(
-                new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this))
+                new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this))
         );
         overviewPanel.init(mActionsView, mSplitPlaceholderView);
         mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 06137f2..7c453e7 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -108,8 +108,7 @@
 
         SplitPlaceholderView splitPlaceholderView = findViewById(R.id.split_placeholder);
         splitPlaceholderView.init(
-                new SplitSelectStateController(
-                        SystemUiProxy.INSTANCE.get(this))
+                new SplitSelectStateController(mUiHandler, SystemUiProxy.INSTANCE.get(this))
         );
 
         mDragLayer.recreateControllers();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 1f332c4..0ee28bc 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -35,6 +35,7 @@
 import android.view.MotionEvent;
 
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.RemoteTransitionCompat;
@@ -491,6 +492,20 @@
         }
     }
 
+    /** Start multiple tasks in split-screen simultaneously. */
+    public void startTasks(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions,
+            @SplitConfigurationOptions.StagePosition int sidePosition,
+            RemoteTransitionCompat remoteTransition) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSplitScreen.startTasks(mainTaskId, mainOptions, sideTaskId, sideOptions,
+                        sidePosition, remoteTransition.getTransition());
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startTask");
+            }
+        }
+    }
+
     public void startShortcut(String packageName, String shortcutId, int stage, int position,
             Bundle options, UserHandle user) {
         if (mSplitScreen != null) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index bea1250..cbb2a66 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -15,6 +15,9 @@
  */
 package com.android.quickstep;
 
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -47,7 +50,9 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Build;
+import android.view.SurfaceControl;
 import android.view.View;
+import android.window.TransitionInfo;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -352,7 +357,47 @@
      * 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 AnimatorSet anim,
+    public static void composeRecentsSplitLaunchAnimator(@NonNull TaskView initialView,
+            @NonNull TaskView v, @NonNull TransitionInfo transitionInfo,
+            SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
+
+        final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2];
+        for (int i = 0; i < transitionInfo.getChanges().size(); ++i) {
+            final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
+            final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;
+            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 (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
+                    throw new IllegalStateException(
+                            "Expected task to be showing, but it is " + mode);
+                }
+                if (change.getParent() == null) {
+                    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] =
+                        transitionInfo.getChange(change.getParent());
+            }
+        }
+
+        // This is where we should animate the split roots. For now, though, just make them visible.
+        for (int i = 0; i < 2; ++i) {
+            t.show(splitRoots[i].getLeash());
+            t.setAlpha(splitRoots[i].getLeash(), 1.f);
+        }
+
+        // This contains the initial state (before animation), so apply this at the beginning of
+        // the animation.
+        t.apply();
+
+        // Once there is an animation, this should be called AFTER the animation completes.
+        finishCallback.run();
+    }
+
+    /** Legacy version (until shell transitions are enabled) */
+    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull AnimatorSet anim,
             @NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
             @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
             @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index e3f2925..9576eac 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -16,11 +16,17 @@
 
 package com.android.quickstep.util;
 
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+
 import android.animation.AnimatorSet;
 import android.app.ActivityOptions;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Pair;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
 
 import androidx.annotation.Nullable;
 
@@ -31,12 +37,15 @@
 import com.android.launcher3.WrappedLauncherAnimationRunner;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 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.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.RemoteTransitionCompat;
+import com.android.systemui.shared.system.RemoteTransitionRunner;
 
 /**
  * Represent data needed for the transient state when user has selected one app for split screen
@@ -47,9 +56,11 @@
     private final SystemUiProxy mSystemUiProxy;
     private TaskView mInitialTaskView;
     private SplitPositionOption mInitialPosition;
+    private final Handler mHandler;
 
-    public SplitSelectStateController(SystemUiProxy systemUiProxy) {
+    public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
         mSystemUiProxy = systemUiProxy;
+        mHandler = handler;
     }
 
     /**
@@ -64,6 +75,19 @@
      * To be called after second task selected
      */
     public void setSecondTaskId(TaskView taskView) {
+        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+            // Assume initial task is for top/left part of screen
+            final int[] taskIds = mInitialPosition.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};
+
+            RemoteSplitLaunchAnimationRunner animationRunner =
+                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+            mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
+                    null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
+                    new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
+            return;
+        }
         // Assume initial mInitialTaskId is for top/left part of screen
         WrappedAnimationRunnerImpl initialSplitRunnerWrapped =  new SplitLaunchAnimationRunner(
                 mInitialTaskView, 0);
@@ -96,6 +120,30 @@
     }
 
     /**
+     * Requires Shell Transitions
+     */
+    private class RemoteSplitLaunchAnimationRunner implements RemoteTransitionRunner {
+
+        private final TaskView mInitialTaskView;
+        private final TaskView mTaskView;
+
+        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+            mInitialTaskView = initialTaskView;
+            mTaskView = taskView;
+        }
+
+        @Override
+        public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
+                Runnable finishCallback) {
+            TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskView, mTaskView,
+                    info, t, finishCallback);
+            // After successful launch, call resetState
+            resetState();
+        }
+    }
+
+    /**
+     * LEGACY
      * @return the opposite stage and position from the {@param position} provided as first and
      *         second object, respectively
      * Ex. If position is has stage = Main and position = Top/Left, this will return
@@ -109,6 +157,7 @@
     }
 
     /**
+     * LEGACY
      * Remote animation runner for animation to launch an app.
      */
     private class SplitLaunchAnimationRunner implements WrappedAnimationRunnerImpl {
@@ -129,7 +178,7 @@
                 LauncherAnimationRunner.AnimationResult result) {
             AnimatorSet anim = new AnimatorSet();
             BaseQuickstepLauncher activity = BaseActivity.fromContext(mV.getContext());
-            TaskViewUtils.composeRecentsSplitLaunchAnimator(anim, mV,
+            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(anim, mV,
                     appTargets, wallpaperTargets, nonAppTargets, true, activity.getStateManager(),
                     activity.getDepthController(), mTargetState);
             result.setAnimation(anim, activity);