Merge "Make pip task could be enter split" into udc-dev
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 18898f1..07d11cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -534,17 +534,6 @@
             return;
         }
 
-        if (ENABLE_SHELL_TRANSITIONS) {
-            if (requestEnterSplit && mSplitScreenOptional.isPresent()) {
-                mSplitScreenOptional.get().prepareEnterSplitScreen(wct, mTaskInfo,
-                        isPipTopLeft()
-                                ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
-                mPipTransitionController.startExitTransition(
-                        TRANSIT_EXIT_PIP_TO_SPLIT, wct, null /* destinationBounds */);
-                return;
-            }
-        }
-
         final Rect displayBounds = mPipBoundsState.getDisplayBounds();
         final Rect destinationBounds = new Rect(displayBounds);
         final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
@@ -553,10 +542,8 @@
         // For exiting to fullscreen, the windowing mode of task will be changed to fullscreen
         // until the animation is finished. Otherwise if the activity is resumed and focused at the
         // begin of aniamtion, the app may do something too early to distub the animation.
-        final boolean toFullscreen = destinationBounds.equals(displayBounds);
 
-        if (Transitions.SHELL_TRANSITIONS_ROTATION || (Transitions.ENABLE_SHELL_TRANSITIONS
-                && !toFullscreen)) {
+        if (Transitions.SHELL_TRANSITIONS_ROTATION) {
             // When exit to fullscreen with Shell transition enabled, we update the Task windowing
             // mode directly so that it can also trigger display rotation and visibility update in
             // the same transition if there will be any.
@@ -588,9 +575,29 @@
         mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
 
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+            if (requestEnterSplit && mSplitScreenOptional.isPresent()) {
+                wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+                mSplitScreenOptional.get().prepareEnterSplitScreen(wct, mTaskInfo,
+                        isPipToTopLeft()
+                                ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
+                mPipTransitionController.startExitTransition(
+                        TRANSIT_EXIT_PIP_TO_SPLIT, wct, destinationBounds);
+                return;
+            }
+
+            if (mSplitScreenOptional.isPresent()) {
+                // If pip activity will reparent to origin task case and if the origin task still
+                // under split root, apply exit split transaction to make it expand to fullscreen.
+                SplitScreenController split = mSplitScreenOptional.get();
+                if (split.isTaskInSplitScreen(mTaskInfo.lastParentTaskIdBeforePip)) {
+                    split.prepareExitSplitScreen(wct, split.getStageOfTask(
+                            mTaskInfo.lastParentTaskIdBeforePip));
+                }
+            }
             mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, destinationBounds);
             return;
         }
+
         if (mSplitScreenOptional.isPresent()) {
             // If pip activity will reparent to origin task case and if the origin task still under
             // split root, just exit split screen here to ensure it could expand to fullscreen.
@@ -1666,17 +1673,6 @@
         }
     }
 
-    private boolean isPipTopLeft() {
-        if (!mSplitScreenOptional.isPresent()) {
-            return false;
-        }
-        final Rect topLeft = new Rect();
-        final Rect bottomRight = new Rect();
-        mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
-
-        return topLeft.contains(mPipBoundsState.getBounds());
-    }
-
     private boolean isPipToTopLeft() {
         if (!mSplitScreenOptional.isPresent()) {
             return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index bf75132..fb966c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -989,12 +989,7 @@
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback,
             @NonNull TaskInfo taskInfo) {
-        final int changeSize = info.getChanges().size();
-        if (changeSize < 4) {
-            throw new RuntimeException(
-                    "Got an exit-pip-to-split transition with unexpected change-list");
-        }
-        for (int i = changeSize - 1; i >= 0; i--) {
+        for (int i = info.getChanges().size() - 1; i >= 0; i--) {
             final TransitionInfo.Change change = info.getChanges().get(i);
             final int mode = change.getMode();
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 2fff0e4..e1bcd70c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -38,6 +38,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.split.SplitScreenUtils;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
@@ -223,6 +224,13 @@
         return false;
     }
 
+    /** Whether a particular package is same as current pip package. */
+    public boolean isInPipPackage(String packageName) {
+        final TaskInfo inPipTask = mPipOrganizer.getTaskInfo();
+        return packageName != null && inPipTask != null
+                && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent));
+    }
+
     /** Add PiP-related changes to `outWCT` for the given request. */
     public void augmentRequest(@NonNull IBinder transition,
             @NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWCT) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index ea33a1f..e7a367f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -88,6 +88,7 @@
 import com.android.wm.shell.draganddrop.DragAndDropPolicy;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.splitscreen.SplitScreen.StageType;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
@@ -332,6 +333,11 @@
         return mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
     }
 
+    /** Get the split stage of task is under it. */
+    public @StageType int getStageOfTask(int taskId) {
+        return mStageCoordinator.getStageOfTask(taskId);
+    }
+
     /** Check split is foreground and task is under split or not by taskId. */
     public boolean isTaskInSplitScreenForeground(int taskId) {
         return isTaskInSplitScreen(taskId) && isSplitScreenVisible();
@@ -378,17 +384,35 @@
         mStageCoordinator.setSideStagePosition(sideStagePosition, null /* wct */);
     }
 
-    public void enterSplitScreen(int taskId, boolean leftOrTop) {
-        enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
-    }
-
+    /**
+     * Doing necessary window transaction for other transition handler need to enter split in
+     * transition.
+     */
     public void prepareEnterSplitScreen(WindowContainerTransaction wct,
             ActivityManager.RunningTaskInfo taskInfo, int startPosition) {
-        mStageCoordinator.prepareEnterSplitScreen(wct, taskInfo, startPosition);
+        mStageCoordinator.prepareEnterSplitScreen(wct, taskInfo, startPosition,
+                false /* resizeAnim */);
     }
 
-    public void finishEnterSplitScreen(SurfaceControl.Transaction t) {
-        mStageCoordinator.finishEnterSplitScreen(t);
+    /**
+     * Doing necessary surface transaction for other transition handler need to enter split in
+     * transition when finished.
+     */
+    public void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
+        mStageCoordinator.finishEnterSplitScreen(finishT);
+    }
+
+    /**
+     * Doing necessary window transaction for other transition handler need to exit split in
+     * transition.
+     */
+    public void prepareExitSplitScreen(WindowContainerTransaction wct,
+            @StageType int stageToTop) {
+        mStageCoordinator.prepareExitSplitScreen(stageToTop, wct);
+    }
+
+    public void enterSplitScreen(int taskId, boolean leftOrTop) {
+        enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
     }
 
     public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a0bb29b..c1d1f5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -389,7 +389,7 @@
 
     boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
             WindowContainerTransaction wct) {
-        prepareEnterSplitScreen(wct, task, stagePosition);
+        prepareEnterSplitScreen(wct, task, stagePosition, false /* resizeAnim */);
         if (ENABLE_SHELL_TRANSITIONS) {
             mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct,
                     null, this,
@@ -487,20 +487,26 @@
     /** Launches an activity into split. */
     void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
             @Nullable Bundle options) {
+        mSplitRequest = new SplitRequest(intent.getIntent(), position);
         if (!ENABLE_SHELL_TRANSITIONS) {
             startIntentLegacy(intent, fillInIntent, position, options);
             return;
         }
 
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-
         options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
         wct.sendPendingIntent(intent, fillInIntent, options);
 
+        // If this should be mixed, just send the intent to avoid split handle transition directly.
+        if (mMixedHandler != null && mMixedHandler.shouldSplitEnterMixed(intent)) {
+            mTaskOrganizer.applyTransaction(wct);
+            return;
+        }
+
         // If split screen is not activated, we're expecting to open a pair of apps to split.
         final int extraTransitType = mMainStage.isActive()
                 ? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
-        prepareEnterSplitScreen(wct, null /* taskInfo */, position);
+        prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering);
 
         mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
                 extraTransitType, !mIsDropEntering);
@@ -557,7 +563,6 @@
         if (isEnteringSplit && mLogger.isEnterRequestedByDrag()) {
             updateWindowBounds(mSplitLayout, wct);
         }
-        mSplitRequest = new SplitRequest(intent.getIntent(), position);
         wct.sendPendingIntent(intent, fillInIntent, options);
         mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
     }
@@ -1445,7 +1450,7 @@
      * an existing WindowContainerTransaction (rather than applying immediately). This is intended
      * to be used when exiting split might be bundled with other window operations.
      */
-    private void prepareExitSplitScreen(@StageType int stageToTop,
+    void prepareExitSplitScreen(@StageType int stageToTop,
             @NonNull WindowContainerTransaction wct) {
         if (!mMainStage.isActive()) return;
         mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
@@ -1453,7 +1458,8 @@
     }
 
     private void prepareEnterSplitScreen(WindowContainerTransaction wct) {
-        prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED);
+        prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED,
+                !mIsDropEntering);
     }
 
     /**
@@ -1461,17 +1467,19 @@
      * into side stage.
      */
     void prepareEnterSplitScreen(WindowContainerTransaction wct,
-            @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+            @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
+            boolean resizeAnim) {
         onSplitScreenEnter();
         if (isSplitActive()) {
-            prepareBringSplit(wct, taskInfo, startPosition);
+            prepareBringSplit(wct, taskInfo, startPosition, resizeAnim);
         } else {
-            prepareActiveSplit(wct, taskInfo, startPosition);
+            prepareActiveSplit(wct, taskInfo, startPosition, resizeAnim);
         }
     }
 
     private void prepareBringSplit(WindowContainerTransaction wct,
-            @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+            @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
+            boolean resizeAnim) {
         if (taskInfo != null) {
             wct.startTask(taskInfo.taskId,
                     resolveStartStage(STAGE_TYPE_UNDEFINED, startPosition, null, wct));
@@ -1483,12 +1491,13 @@
             // won't guarantee to put the task to the indicated new position.
             mMainStage.evictAllChildren(wct);
             mMainStage.reparentTopTask(wct);
-            prepareSplitLayout(wct);
+            prepareSplitLayout(wct, resizeAnim);
         }
     }
 
     private void prepareActiveSplit(WindowContainerTransaction wct,
-            @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+            @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
+            boolean resizeAnim) {
         if (!ENABLE_SHELL_TRANSITIONS) {
             // Legacy transition we need to create divider here, shell transition case we will
             // create it on #finishEnterSplitScreen
@@ -1499,17 +1508,17 @@
             mSideStage.addTask(taskInfo, wct);
         }
         mMainStage.activate(wct, true /* includingTopTask */);
-        prepareSplitLayout(wct);
+        prepareSplitLayout(wct, resizeAnim);
     }
 
-    private void prepareSplitLayout(WindowContainerTransaction wct) {
-        if (mIsDropEntering) {
-            mSplitLayout.resetDividerPosition();
-        } else {
+    private void prepareSplitLayout(WindowContainerTransaction wct, boolean resizeAnim) {
+        if (resizeAnim) {
             mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
+        } else {
+            mSplitLayout.resetDividerPosition();
         }
         updateWindowBounds(mSplitLayout, wct);
-        if (!mIsDropEntering) {
+        if (resizeAnim) {
             // Reset its smallest width dp to avoid is change layout before it actually resized to
             // split bounds.
             wct.setSmallestScreenWidthDp(mMainStage.mRootTaskInfo.token,
@@ -1519,21 +1528,22 @@
         setRootForceTranslucent(false, wct);
     }
 
-    void finishEnterSplitScreen(SurfaceControl.Transaction t) {
-        mSplitLayout.update(t);
+    void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
+        mSplitLayout.update(finishT);
         mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash,
                 getMainStageBounds());
         mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash,
                 getSideStageBounds());
-        setDividerVisibility(true, t);
+        setDividerVisibility(true, finishT);
         // Ensure divider surface are re-parented back into the hierarchy at the end of the
         // transition. See Transition#buildFinishTransaction for more detail.
-        t.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
+        finishT.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
 
-        updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
-        t.show(mRootTaskLeash);
+        updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */);
+        finishT.show(mRootTaskLeash);
         setSplitsVisible(true);
         mIsDropEntering = false;
+        mSplitRequest = null;
         updateRecentTasksSplitPair();
         if (!mLogger.hasStartedSession()) {
             mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 92ff5fe..60628e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -183,12 +183,12 @@
             final int taskId = taskInfo.taskId;
             mChildrenLeashes.put(taskId, leash);
             mChildrenTaskInfo.put(taskId, taskInfo);
-            updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
             mCallbacks.onChildTaskStatusChanged(taskId, true /* present */, taskInfo.isVisible);
             if (ENABLE_SHELL_TRANSITIONS) {
                 // Status is managed/synchronized by the transition lifecycle.
                 return;
             }
+            updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
             mCallbacks.onChildTaskAppeared(taskId);
             sendStatusChanged();
         } else {
@@ -417,7 +417,7 @@
             }
             t.setCrop(leash, null);
             t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y);
-            if (firstAppeared && !ENABLE_SHELL_TRANSITIONS) {
+            if (firstAppeared) {
                 t.setAlpha(leash, 1f);
                 t.setMatrix(leash, 1, 0, 0, 1);
                 t.show(leash);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 3ec433e..b25437d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -30,6 +30,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.PendingIntent;
 import android.os.IBinder;
 import android.util.Log;
 import android.util.Pair;
@@ -41,6 +42,7 @@
 import android.window.WindowContainerTransactionCallback;
 
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.split.SplitScreenUtils;
 import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.phone.PipTouchHandler;
@@ -590,6 +592,17 @@
         return true;
     }
 
+    /** Use to when split use intent to enter, check if this enter transition should be mixed or
+     * not.*/
+    public boolean shouldSplitEnterMixed(PendingIntent intent) {
+        // Check if this intent package is same as pip one or not, if true we want let the pip
+        // task enter split.
+        if (mPipHandler != null) {
+            return mPipHandler.isInPipPackage(SplitScreenUtils.getPackageName(intent.getIntent()));
+        }
+        return false;
+    }
+
     @Override
     public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 66b6c62..2dcdc74 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -159,7 +159,7 @@
 
         mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
         verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
-                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
         verify(mMainStage).reparentTopTask(eq(wct));
         assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
         assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
@@ -177,7 +177,7 @@
 
         mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
         verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
-                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
         assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
         assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
     }
@@ -189,7 +189,7 @@
 
         mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
         verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
-                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
         assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
     }