Implement split from workspace to workspace

Fixes: 239824922
Test: https://recall.googleplex.com/projects/f46cfe9c-8076-4efe-bf8a-b1cc4f1f5e1b/sessions/b745433d-cba7-4f7a-a28d-4223d9950c0b
Change-Id: I9bfd5844bb9ccb6e65e77fedb7fbccb37692f812
diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
index 7c3281a..7cf8201 100644
--- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
+++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
@@ -15,20 +15,29 @@
  */
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
 import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
+import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
 
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
 import android.view.View;
 
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.quickstep.util.SplitSelectStateController;
+import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.RecentsView;
 
 public interface QuickstepSystemShortcut {
@@ -44,6 +53,10 @@
 
     class SplitSelectSystemShortcut extends SystemShortcut<QuickstepLauncher> {
 
+        private final int mSplitPlaceholderSize;
+        private final int mSplitPlaceholderInset;
+
+        private final Rect mTempRect = new Rect();
         private final SplitPositionOption mPosition;
 
         public SplitSelectSystemShortcut(QuickstepLauncher launcher, ItemInfo itemInfo,
@@ -51,6 +64,11 @@
             super(position.iconResId, position.textResId, launcher, itemInfo, originalView);
 
             mPosition = position;
+
+            mSplitPlaceholderSize = launcher.getResources().getDimensionPixelSize(
+                    R.dimen.split_placeholder_size);
+            mSplitPlaceholderInset = launcher.getResources().getDimensionPixelSize(
+                    R.dimen.split_placeholder_inset);
         }
 
         @Override
@@ -72,11 +90,39 @@
                 return;
             }
 
-            RecentsView recentsView = mTarget.getOverviewPanel();
             StatsLogManager.EventEnum splitEvent = getLogEventForPosition(mPosition.stagePosition);
-            recentsView.initiateSplitSelect(
-                    new SplitSelectSource(mOriginalView, new BitmapDrawable(bitmap), intent,
-                            mPosition, mItemInfo, splitEvent));
+            SplitSelectSource source = new SplitSelectSource(mOriginalView,
+                    new BitmapDrawable(bitmap), intent, mPosition, mItemInfo, splitEvent);
+            if (ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+                startSplitToHome(source);
+            } else {
+                RecentsView recentsView = mTarget.getOverviewPanel();
+                recentsView.initiateSplitSelect(source);
+            }
+        }
+
+        private void startSplitToHome(SplitSelectSource source) {
+            AbstractFloatingView.closeAllOpenViews(mTarget);
+
+            SplitSelectStateController controller = mTarget.getSplitSelectStateController();
+            controller.setInitialTaskSelect(source.intent, source.position.stagePosition,
+                    source.itemInfo, source.splitEvent);
+
+            RecentsView recentsView = mTarget.getOverviewPanel();
+            recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds(
+                    mSplitPlaceholderSize, mSplitPlaceholderInset, mTarget.getDeviceProfile(),
+                    controller.getActiveSplitStagePosition(), mTempRect);
+
+            PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration());
+            RectF startingTaskRect = new RectF();
+            FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(mTarget,
+                    source.view, null /* thumbnail */,
+                    source.drawable, startingTaskRect);
+            floatingTaskView.setAlpha(1);
+            floatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
+                    false /* fadeWithThumbnail */, true /* isStagedTask */);
+            controller.setFirstFloatingTaskView(floatingTaskView);
+            anim.buildAnim().start();
         }
     }
 
@@ -86,7 +132,7 @@
         public final Drawable drawable;
         public final Intent intent;
         public final SplitPositionOption position;
-        public final ItemInfo mItemInfo;
+        public final ItemInfo itemInfo;
         public final StatsLogManager.EventEnum splitEvent;
 
         public SplitSelectSource(View view, Drawable drawable, Intent intent,
@@ -96,7 +142,7 @@
             this.drawable = drawable;
             this.intent = intent;
             this.position = position;
-            this.mItemInfo = itemInfo;
+            this.itemInfo = itemInfo;
             this.splitEvent = splitEvent;
         }
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 9813c8a..2d1a6ca 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -96,6 +96,7 @@
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.WellbeingModel;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.proxy.ProxyActivityStarter;
 import com.android.launcher3.proxy.StartActivityParams;
@@ -136,6 +137,7 @@
 import com.android.quickstep.util.RemoteAnimationProvider;
 import com.android.quickstep.util.RemoteFadeOutAnimationListener;
 import com.android.quickstep.util.SplitSelectStateController;
+import com.android.quickstep.util.SplitToWorkspaceController;
 import com.android.quickstep.util.SplitWithKeyboardShortcutController;
 import com.android.quickstep.util.TISBindHelper;
 import com.android.quickstep.views.OverviewActionsView;
@@ -182,7 +184,10 @@
     private @Nullable RotationChangeProvider mRotationChangeProvider;
     private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
 
+    private SplitSelectStateController mSplitSelectStateController;
     private SplitWithKeyboardShortcutController mSplitWithKeyboardShortcutController;
+    private SplitToWorkspaceController mSplitToWorkspaceController;
+
     /**
      * If Launcher restarted while in the middle of an Overview split select, it needs this data to
      * recover. In all other cases this will remain null.
@@ -199,12 +204,14 @@
 
         mActionsView = findViewById(R.id.overview_actions_view);
         RecentsView overviewPanel = getOverviewPanel();
-        SplitSelectStateController controller =
+        mSplitSelectStateController =
                 new SplitSelectStateController(this, mHandler, getStateManager(),
                         getDepthController(), getStatsLogManager());
-        overviewPanel.init(mActionsView, controller);
+        overviewPanel.init(mActionsView, mSplitSelectStateController);
         mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this,
-                controller);
+                mSplitSelectStateController);
+        mSplitToWorkspaceController = new SplitToWorkspaceController(this,
+                mSplitSelectStateController);
         mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
         mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
 
@@ -330,7 +337,7 @@
     }
 
     protected void onItemClicked(View view) {
-        if (!mSplitWithKeyboardShortcutController.handleSecondAppSelectionForSplit(view)) {
+        if (!mSplitToWorkspaceController.handleSecondAppSelectionForSplit(view)) {
             QuickstepLauncher.super.getItemOnClickListener().onClick(view);
         }
     }
@@ -724,6 +731,10 @@
         return mTaskbarUIController;
     }
 
+    public SplitSelectStateController getSplitSelectStateController() {
+        return mSplitSelectStateController;
+    }
+
     public <T extends OverviewActionsView> T getActionsView() {
         return (T) mActionsView;
     }
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index ef7c6dc..bb97334 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -561,6 +561,20 @@
         }
     }
 
+    public void startIntents(PendingIntent pendingIntent1, Bundle options1,
+            PendingIntent pendingIntent2, Bundle options2,
+            @SplitConfigurationOptions.StagePosition int splitPosition,
+            float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSplitScreen.startIntents(pendingIntent1, options1, pendingIntent2, options2,
+                        splitPosition, splitRatio, remoteTransition, instanceId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startIntents");
+            }
+        }
+    }
+
     public void startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId,
             Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
             float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
@@ -617,6 +631,20 @@
         }
     }
 
+    public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1, Bundle options1,
+            PendingIntent pendingIntent2, Bundle options2,
+            @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio,
+            RemoteAnimationAdapter adapter, InstanceId instanceId) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, options1,
+                        pendingIntent2, options2, sidePosition, splitRatio, adapter, instanceId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startIntentsWithLegacyTransition");
+            }
+        }
+    }
+
     public void startShortcut(String packageName, String shortcutId, int position,
             Bundle options, UserHandle user, InstanceId instanceId) {
         if (mSplitScreen != null) {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 4a74ac6..c263fe8 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -37,6 +37,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.view.RemoteAnimationAdapter;
@@ -207,8 +208,8 @@
      * fill in intent with a taskId2 are set.
      * @param intent1 is null when split is initiated from Overview
      * @param stagePosition representing location of task1
-     * @param shellInstanceId loggingId to be used by shell, will be non-null for actions that create
-     *                   a split instance, null for cases that bring existing instaces to the
+     * @param shellInstanceId loggingId to be used by shell, will be non-null for actions that
+     *                   create a split instance, null for cases that bring existing instaces to the
      *                   foreground (quickswitch, launching previous pairs from overview)
      */
     public void launchTasks(int taskId1, @Nullable Intent intent1, int taskId2,
@@ -238,7 +239,9 @@
                         getOppositeStagePosition(stagePosition), splitRatio, remoteTransition,
                         shellInstanceId);
             } else {
-                // TODO: the case when both split apps are started from an intent.
+                mSystemUiProxy.startIntents(getPendingIntent(intent1), options1.toBundle(),
+                        getPendingIntent(intent2), null /* options2 */, stagePosition,
+                        splitRatio, remoteTransition, shellInstanceId);
             }
         } else {
             final RemoteSplitLaunchAnimationRunner animationRunner =
@@ -259,7 +262,9 @@
                         getOppositeStagePosition(stagePosition), splitRatio, adapter,
                         shellInstanceId);
             } else {
-                // TODO: the case when both split apps are started from an intent.
+                mSystemUiProxy.startIntentsWithLegacyTransition(getPendingIntent(intent1),
+                        options1.toBundle(), getPendingIntent(intent2), null /* options2 */,
+                        stagePosition, splitRatio, adapter, shellInstanceId);
             }
         }
     }
@@ -305,7 +310,6 @@
                 : PendingIntent.getActivity(mContext, 0, intent, FLAG_MUTABLE));
     }
 
-
     public @StagePosition int getActiveSplitStagePosition() {
         return mStagePosition;
     }
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
new file mode 100644
index 0000000..e8a4b0a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util;
+
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
+
+import android.content.Intent;
+import android.view.View;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+
+/** Handles when the stage split lands on the home screen. */
+public class SplitToWorkspaceController {
+
+    private final Launcher mLauncher;
+    private final SplitSelectStateController mController;
+
+    public SplitToWorkspaceController(Launcher launcher, SplitSelectStateController controller) {
+        mLauncher = launcher;
+        mController = controller;
+    }
+
+    /**
+     * Handles second app selection from stage split. If the item can't be opened in split or
+     * it's not in stage split state, we pass it onto Launcher's default item click handler.
+     */
+    public boolean handleSecondAppSelectionForSplit(View view) {
+        if ((!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
+                && !ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get())
+                || !mController.isSplitSelectActive()) {
+            return false;
+        }
+        Object tag = view.getTag();
+        Intent intent;
+        if (tag instanceof WorkspaceItemInfo) {
+            final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag;
+            intent = workspaceItemInfo.intent;
+        } else if (tag instanceof com.android.launcher3.model.data.AppInfo) {
+            final com.android.launcher3.model.data.AppInfo appInfo =
+                    (com.android.launcher3.model.data.AppInfo) tag;
+            intent = appInfo.intent;
+        } else {
+            return false;
+        }
+        mController.setSecondTask(intent);
+        mController.launchSplitTasks(aBoolean -> mLauncher.getDragLayer().removeView(
+                mController.getFirstFloatingTaskView()));
+        return true;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 3587bd1..24d8326 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -101,33 +101,6 @@
         });
     }
 
-    /**
-     * Handles second app selection from stage split. If the item can't be opened in split or
-     * it's not in stage split state, we pass it onto Launcher's default item click handler.
-     */
-    public boolean handleSecondAppSelectionForSplit(View view) {
-        if (!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
-                || !mController.isSplitSelectActive()) {
-            return false;
-        }
-        Object tag = view.getTag();
-        Intent intent;
-        if (tag instanceof WorkspaceItemInfo) {
-            final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag;
-            intent = workspaceItemInfo.intent;
-        } else if (tag instanceof com.android.launcher3.model.data.AppInfo) {
-            final com.android.launcher3.model.data.AppInfo appInfo =
-                    (com.android.launcher3.model.data.AppInfo) tag;
-            intent = appInfo.intent;
-        } else {
-            return false;
-        }
-        mController.setSecondTask(intent);
-        mController.launchSplitTasks(aBoolean -> mLauncher.getDragLayer().removeView(
-                mController.getFirstFloatingTaskView()));
-        return true;
-    }
-
     public void onDestroy() {
         mOverviewComponentObserver.onDestroy();
     }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index ff0c984..ce84869 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -4232,7 +4232,7 @@
     public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) {
         mSplitSelectSource = splitSelectSource;
         mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
-                splitSelectSource.position.stagePosition, splitSelectSource.mItemInfo,
+                splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
                 splitSelectSource.splitEvent);
     }
 
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 9484fff..fd06279 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -257,6 +257,10 @@
             getDebugFlag("ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", false,
                     "Enable splitting from fullscreen app with keyboard shortcuts");
 
+    public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
+            "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", false,
+            "Enable initiating split screen from workspace to workspace.");
+
     public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(
             "ENABLE_NEW_MIGRATION_LOGIC", true,
             "Enable the new grid migration logic, keeping pages when src < dest");