Merge "Bunlde ClientTransactionItems when enter/exit PiP" into main
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a5687e6..a0f615b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3779,17 +3779,25 @@
                 }
                 EventLogTags.writeWmEnterPip(r.mUserId, System.identityHashCode(r),
                         r.shortComponentName, Boolean.toString(isAutoEnter));
-                r.setPictureInPictureParams(params);
-                r.mAutoEnteringPip = isAutoEnter;
-                mRootWindowContainer.moveActivityToPinnedRootTask(r,
-                        null /* launchIntoPipHostActivity */, "enterPictureInPictureMode",
-                        transition);
-                // Continue the pausing process after entering pip.
-                if (r.isState(PAUSING) && r.mPauseSchedulePendingForPip) {
-                    r.getTask().schedulePauseActivity(r, false /* userLeaving */,
-                            false /* pauseImmediately */, true /* autoEnteringPip */, "auto-pip");
+
+                // Ensure the ClientTransactionItems are bundled for this operation.
+                deferWindowLayout();
+                try {
+                    r.setPictureInPictureParams(params);
+                    r.mAutoEnteringPip = isAutoEnter;
+                    mRootWindowContainer.moveActivityToPinnedRootTask(r,
+                            null /* launchIntoPipHostActivity */, "enterPictureInPictureMode",
+                            transition);
+                    // Continue the pausing process after entering pip.
+                    if (r.isState(PAUSING) && r.mPauseSchedulePendingForPip) {
+                        r.getTask().schedulePauseActivity(r, false /* userLeaving */,
+                                false /* pauseImmediately */, true /* autoEnteringPip */,
+                                "auto-pip");
+                    }
+                    r.mAutoEnteringPip = false;
+                } finally {
+                    continueWindowLayout();
                 }
-                r.mAutoEnteringPip = false;
             }
         };
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3eea6ac..e9a877e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2378,6 +2378,14 @@
             return false;
         }
 
+        return resumeFocusedTasksTopActivitiesUnchecked(targetRootTask, target, targetOptions,
+                deferPause);
+    }
+
+    @VisibleForTesting
+    boolean resumeFocusedTasksTopActivitiesUnchecked(
+            Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
+            boolean deferPause) {
         boolean result = false;
         if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
                 || getTopDisplayFocusedRootTask() == targetRootTask)) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index e1ad1be..393a01f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -69,6 +69,7 @@
 import static com.android.server.wm.ActivityRecord.State.PAUSING;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
+import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;
 import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
@@ -829,18 +830,20 @@
     }
 
     private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) {
+        final boolean wasPrevFocusableAndVisible = tr.isFocusableAndVisible();
+
         int effects = applyChanges(tr, c);
         final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
 
         if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {
             if (tr.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, c.getHidden())) {
-                effects = TRANSACT_EFFECTS_LIFECYCLE;
+                effects |= TRANSACT_EFFECTS_LIFECYCLE;
             }
         }
 
         if ((c.getChangeMask() & CHANGE_FORCE_TRANSLUCENT) != 0) {
             tr.setForceTranslucent(c.getForceTranslucent());
-            effects = TRANSACT_EFFECTS_LIFECYCLE;
+            effects |= TRANSACT_EFFECTS_LIFECYCLE;
         }
 
         if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING) != 0) {
@@ -873,8 +876,17 @@
                 boolean canEnterPip = activity.checkEnterPictureInPictureState(
                         "applyTaskChanges", true /* beforeStopping */);
                 if (canEnterPip) {
-                    canEnterPip = mService.mActivityClientController
-                            .requestPictureInPictureMode(activity);
+                    mService.mTaskSupervisor.beginDeferResume();
+                    try {
+                        canEnterPip = mService.mActivityClientController
+                                .requestPictureInPictureMode(activity);
+                    } finally {
+                        mService.mTaskSupervisor.endDeferResume();
+                        if (canEnterPip && !isPip2ExperimentEnabled()) {
+                            // Wait until the transaction is applied to only resume once.
+                            effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                        }
+                    }
                 }
                 if (!canEnterPip) {
                     // Restore the flag to its previous state when the activity cannot enter PIP.
@@ -883,6 +895,11 @@
             }
         }
 
+        // Activity in this Task may resume/pause when enter/exit pip.
+        if (wasPrevFocusableAndVisible != tr.isFocusableAndVisible()) {
+            effects |= TRANSACT_EFFECTS_LIFECYCLE;
+        }
+
         return effects;
     }
 
@@ -948,7 +965,7 @@
         }
         if ((c.getChangeMask() & CHANGE_FORCE_TRANSLUCENT) != 0) {
             taskFragment.setForceTranslucent(c.getForceTranslucent());
-            effects = TRANSACT_EFFECTS_LIFECYCLE;
+            effects |= TRANSACT_EFFECTS_LIFECYCLE;
         }
 
         effects |= applyChanges(taskFragment, c);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 43b424f..69b5c37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -1681,7 +1681,8 @@
         WindowContainerToken wct = rootTask.mRemoteToken.toWindowContainerToken();
         t.setWindowingMode(wct, WINDOWING_MODE_PINNED);
         mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
-        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities();
+        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivitiesUnchecked(any(),
+                any(), any(), anyBoolean());
 
         clearInvocations(mWm.mAtmService.mRootWindowContainer);
         // The token for the PIP root task may have changed when the task entered PIP mode, so do
@@ -1690,7 +1691,8 @@
                 record.getRootTask().mRemoteToken.toWindowContainerToken();
         t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN);
         mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
-        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities();
+        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivitiesUnchecked(any(),
+                any(), any(), anyBoolean());
     }
 
     @Test