Merge changes I7d2ca2a2,I9f1fc593 into rvc-dev

* changes:
  Fix a couple issues with previous CL (keeping tasks hidden)
  Keep task hidden until task appeared
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
index 2091c93..39a0101 100644
--- a/core/java/android/window/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -254,7 +254,9 @@
             mTaskToken = taskInfo.token;
             mTaskLeash = mTaskToken.getLeash();
             mTransaction.reparent(mTaskLeash, mSurfaceControl)
-                    .show(mSurfaceControl).apply();
+                    .show(mTaskLeash)
+                    .show(mSurfaceControl)
+                    .apply();
             if (mPendingNotifyBoundsChanged) {
                 // TODO: Either defer show or hide and synchronize show with the resize
                 notifyBoundsChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index d219a9e..dba4343 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -319,6 +319,7 @@
                     getSurfaceTransactionHelper()
                             .crop(tx, leash, getDestinationBounds())
                             .round(tx, leash, shouldApplyCornerRadius());
+                    tx.show(leash);
                     tx.apply();
                 }
             };
@@ -359,6 +360,7 @@
                     getSurfaceTransactionHelper()
                             .alpha(tx, leash, 1f)
                             .round(tx, leash, shouldApplyCornerRadius());
+                    tx.show(leash);
                     tx.apply();
                 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index 0d66340..56a7484 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -51,7 +51,6 @@
 
     private PipAnimationController mPipAnimationController;
 
-    @Mock
     private SurfaceControl mLeash;
 
     @Mock
@@ -61,6 +60,10 @@
     public void setUp() throws Exception {
         mPipAnimationController = new PipAnimationController(
                 mContext, new PipSurfaceTransactionHelper(mContext));
+        mLeash = new SurfaceControl.Builder()
+                .setContainerLayer()
+                .setName("FakeLeash")
+                .build();
         MockitoAnnotations.initMocks(this);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c4d0342..856fbc7 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5212,6 +5212,12 @@
         updateReportedVisibilityLocked();
     }
 
+    void onStartingWindowDrawn() {
+        if (task != null) {
+            task.setHasBeenVisible(true);
+        }
+    }
+
     /** Called when the windows associated app window container are drawn. */
     void onWindowsDrawn(boolean drawn, long timestampNs) {
         mDrawn = drawn;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 15a09e5..11fda36 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -37,6 +37,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -2116,16 +2117,19 @@
 
         try {
             final Task task = r.getTask();
-
             final ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask();
+
             // This will change the pinned stack's windowing mode to its original mode, ensuring
             // we only have one stack that is in pinned mode.
             if (pinnedStack != null) {
                 pinnedStack.dismissPip();
             }
 
-            final boolean singleActivity = task.getChildCount() == 1;
+            // Set a transition to ensure that we don't immediately try and update the visibility
+            // of the activity entering PIP
+            r.getDisplayContent().prepareAppTransition(TRANSIT_NONE, false);
 
+            final boolean singleActivity = task.getChildCount() == 1;
             final ActivityStack stack;
             if (singleActivity) {
                 stack = r.getRootTask();
@@ -2148,11 +2152,6 @@
             mService.continueWindowLayout();
         }
 
-        // TODO: revisit the following statement after the animation is moved from WM to SysUI.
-        // Update the visibility of all activities after the they have been reparented to the new
-        // stack.  This MUST run after the animation above is scheduled to ensure that the windows
-        // drawn signal is scheduled after the bounds animation start call on the bounds animator
-        // thread.
         ensureActivitiesVisible(null, 0, false /* preserveWindows */);
         resumeFocusedStacksTopActivities();
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 106f070..1e70573 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4098,8 +4098,18 @@
     }
 
     void setHasBeenVisible(boolean hasBeenVisible) {
+        final boolean prevHasBeenVisible = mHasBeenVisible;
         mHasBeenVisible = hasBeenVisible;
         if (hasBeenVisible) {
+            // If the task is not yet visible when it is added to the task organizer, then we should
+            // hide it to allow the task organizer to show it when it is properly reparented. We
+            // skip this for tasks created by the organizer because they can synchronously update
+            // the leash before new children are added to the task.
+            if (!mCreatedByOrganizer && mTaskOrganizer != null && !prevHasBeenVisible) {
+                getPendingTransaction().hide(getSurfaceControl());
+                commitPendingTransaction();
+            }
+
             sendTaskAppeared();
             if (!isRootTask()) {
                 getRootTask().setHasBeenVisible(true);
@@ -4143,6 +4153,8 @@
         // Let the old organizer know it has lost control.
         sendTaskVanished();
         mTaskOrganizer = organizer;
+
+
         sendTaskAppeared();
         onTaskOrganizerChanged();
         return true;
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 22702dd..9873031 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -25,6 +25,7 @@
 import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
 
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.WindowConfiguration;
 import android.content.Intent;
@@ -38,6 +39,7 @@
 import android.window.ITaskOrganizerController;
 import android.window.WindowContainerToken;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
 import java.io.PrintWriter;
@@ -46,6 +48,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.WeakHashMap;
+import java.util.function.Consumer;
 
 /**
  * Stores the TaskOrganizers associated with a given windowing mode and
@@ -81,17 +84,105 @@
                 }
             }
         }
-    };
+    }
+
+    /**
+     * A wrapper class around ITaskOrganizer to ensure that the calls are made in the right
+     * lifecycle order since we may be updating the visibility of task surface controls in a pending
+     * transaction before they are presented to the task org.
+     */
+    private class TaskOrganizerCallbacks {
+        final WindowManagerService mService;
+        final ITaskOrganizer mTaskOrganizer;
+        final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
+
+        TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg,
+                Consumer<Runnable> deferTaskOrgCallbacksConsumer) {
+            mService = wm;
+            mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer;
+            mTaskOrganizer = taskOrg;
+        }
+
+        IBinder getBinder() {
+            return mTaskOrganizer.asBinder();
+        }
+
+        void onTaskAppeared(Task task) {
+            final RunningTaskInfo taskInfo = task.getTaskInfo();
+            mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                try {
+                    mTaskOrganizer.onTaskAppeared(taskInfo);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
+                }
+            });
+        }
+
+
+        void onTaskVanished(Task task) {
+            final RunningTaskInfo taskInfo = task.getTaskInfo();
+            mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                try {
+                    mTaskOrganizer.onTaskVanished(taskInfo);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Exception sending onTaskVanished callback", e);
+                }
+            });
+        }
+
+        void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
+            if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
+                // Skip if the task has not yet received taskAppeared(), except for tasks created
+                // by the organizer that don't receive that signal
+                return;
+            }
+            mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                if (!task.isOrganized()) {
+                    // This is safe to ignore if the task is no longer organized
+                    return;
+                }
+                try {
+                    mTaskOrganizer.onTaskInfoChanged(taskInfo);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
+                }
+            });
+        }
+
+        void onBackPressedOnTaskRoot(Task task) {
+            if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
+                // Skip if the task has not yet received taskAppeared(), except for tasks created
+                // by the organizer that don't receive that signal
+                return;
+            }
+            mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                if (!task.isOrganized()) {
+                    // This is safe to ignore if the task is no longer organized
+                    return;
+                }
+                try {
+                   mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
+                } catch (Exception e) {
+                    Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
+                }
+            });
+        }
+    }
 
     private class TaskOrganizerState {
-        private final ITaskOrganizer mOrganizer;
+        private final TaskOrganizerCallbacks mOrganizer;
         private final DeathRecipient mDeathRecipient;
         private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
         private final int mUid;
         private boolean mInterceptBackPressedOnTaskRoot;
 
         TaskOrganizerState(ITaskOrganizer organizer, int uid) {
-            mOrganizer = organizer;
+            final Consumer<Runnable> deferTaskOrgCallbacksConsumer =
+                    mDeferTaskOrgCallbacksConsumer != null
+                            ? mDeferTaskOrgCallbacksConsumer
+                            : mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable;
+            mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer,
+                    deferTaskOrgCallbacksConsumer);
             mDeathRecipient = new DeathRecipient(organizer);
             try {
                 organizer.asBinder().linkToDeath(mDeathRecipient, 0);
@@ -112,23 +203,15 @@
                 mOrganizedTasks.add(t);
             }
             if (t.taskAppearedReady()) {
-                try {
-                    t.mTaskAppearedSent = true;
-                    mOrganizer.onTaskAppeared(t.getTaskInfo());
-                } catch (Exception e) {
-                    Slog.e(TAG, "Exception sending taskAppeared callback" + e);
-                }
+                t.mTaskAppearedSent = true;
+                mOrganizer.onTaskAppeared(t);
             }
         }
 
         void removeTask(Task t) {
             if (t.mTaskAppearedSent) {
-                try {
-                    t.mTaskAppearedSent = false;
-                    mOrganizer.onTaskVanished(t.getTaskInfo());
-                } catch (Exception e) {
-                    Slog.e(TAG, "Exception sending taskVanished callback" + e);
-                }
+                t.mTaskAppearedSent = false;
+                mOrganizer.onTaskVanished(t);
             }
             mOrganizedTasks.remove(t);
         }
@@ -136,7 +219,7 @@
         void dispose() {
             releaseTasks();
             for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
-                mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.asBinder());
+                mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder());
             }
         }
 
@@ -149,7 +232,7 @@
         }
 
         void unlinkDeath() {
-            mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0);
+            mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0);
         }
     }
 
@@ -159,9 +242,10 @@
     private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
     private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
 
-    final ActivityTaskManagerService mService;
+    private final ActivityTaskManagerService mService;
 
-    RunningTaskInfo mTmpTaskInfo;
+    private RunningTaskInfo mTmpTaskInfo;
+    private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
 
     TaskOrganizerController(ActivityTaskManagerService atm) {
         mService = atm;
@@ -173,6 +257,15 @@
     }
 
     /**
+     * Specifies the consumer to run to defer the task org callbacks. Can be overridden while
+     * testing to allow the callbacks to be sent synchronously.
+     */
+    @VisibleForTesting
+    public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
+        mDeferTaskOrgCallbacksConsumer = consumer;
+    }
+
+    /**
      * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
      * If there was already a TaskOrganizer for this windowing mode it will be evicted
      * but will continue to organize it's existing tasks.
@@ -263,7 +356,7 @@
         if (state == null) {
             return null;
         }
-        return state.mOrganizer;
+        return state.mOrganizer.mTaskOrganizer;
     }
 
     void onTaskAppeared(ITaskOrganizer organizer, Task task) {
@@ -368,10 +461,15 @@
         // change.
         mTmpTaskInfo = null;
 
-        if (task.mTaskOrganizer != null) {
-            try {
-                task.mTaskOrganizer.onTaskInfoChanged(newInfo);
-            } catch (RemoteException e) {
+        if (task.isOrganized()) {
+            // Because we defer sending taskAppeared() until the app has drawn, we may receive a
+            // configuration change before the state actually has the task registered. As such we
+            // should ignore these change events to the organizer until taskAppeared(). If the task
+            // was created by the organizer, then we always send the info change.
+            final TaskOrganizerState state = mTaskOrganizerStates.get(
+                    task.mTaskOrganizer.asBinder());
+            if (state != null) {
+                state.mOrganizer.onTaskInfoChanged(task, newInfo);
             }
         }
     }
@@ -531,11 +629,7 @@
             return false;
         }
 
-        try {
-            state.mOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
-        } catch (Exception e) {
-            Slog.e(TAG, "Exception sending interceptBackPressedOnTaskRoot callback" + e);
-        }
+        state.mOrganizer.onBackPressedOnTaskRoot(task);
         return true;
     }
 
@@ -552,7 +646,7 @@
                 final TaskOrganizerState state =  mTaskOrganizerStates.get(taskOrgs.get(j));
                 final ArrayList<Task> tasks = state.mOrganizedTasks;
                 pw.print(innerPrefix + "    ");
-                pw.println(state.mOrganizer + " uid=" + state.mUid + ":");
+                pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
                 for (int k = 0; k < tasks.size(); k++) {
                     pw.println(innerPrefix + "      " + tasks.get(k));
                 }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 3c0eb88..ecc07bd 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2207,6 +2207,11 @@
 
     private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
                                     boolean isVoiceInteraction) {
+        if (isOrganized()) {
+            // Defer to the task organizer to run animations
+            return null;
+        }
+
         final DisplayContent displayContent = getDisplayContent();
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final int width = displayInfo.appWidth;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5a76bac..627fdc3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4274,9 +4274,12 @@
         logPerformShow("performShow on ");
 
         final int drawState = mWinAnimator.mDrawState;
-        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW)
-                && mAttrs.type != TYPE_APPLICATION_STARTING && mActivityRecord != null) {
-            mActivityRecord.onFirstWindowDrawn(this, mWinAnimator);
+        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
+            if (mAttrs.type != TYPE_APPLICATION_STARTING) {
+                mActivityRecord.onFirstWindowDrawn(this, mWinAnimator);
+            } else {
+                mActivityRecord.onStartingWindowDrawn();
+            }
         }
 
         if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 06ca6c1..f275e37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -69,6 +69,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -117,6 +119,13 @@
         return createTaskStackOnDisplay(mDisplayContent);
     }
 
+    @Before
+    public void setUp() {
+        // We defer callbacks since we need to adjust task surface visibility, but for these tests,
+        // just run the callbacks synchronously
+        mWm.mAtmService.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer((r) -> r.run());
+    }
+
     @Test
     public void testAppearVanish() throws RemoteException {
         final ActivityStack stack = createStack();