Merge Task level of window hierarchy (58/n)

Bug: 80414790
Fixes: 143491035
Test: Existing tests pass
Change-Id: I1b39a70afce86f9807ee7b257e10b7e9d6b6e95b
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 48a7b73..1268113 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -41,7 +41,6 @@
 import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
 import static com.android.server.am.ActivityDisplayProto.STACKS;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
@@ -1523,7 +1522,7 @@
             final ActivityStack stack = getChildAt(i);
             final ArrayList<TaskRecord> tasks = stack.getAllTasks();
             for (int j = tasks.size() - 1; j >= 0; --j) {
-                stack.removeTask(tasks.get(j), "removeAllTasks", REMOVE_TASK_MODE_DESTROYING);
+                stack.removeChild(tasks.get(j), "removeAllTasks");
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d4dd033..b95d327 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1148,56 +1148,11 @@
         }
     }
 
-    // TODO(task-unify): Remove once TaskRecord and Task are unified.
     TaskRecord getTaskRecord() {
         return task;
     }
 
     /**
-     * Sets reference to the {@link TaskRecord} the {@link ActivityRecord} will treat as its parent.
-     * Note that this does not actually add the {@link ActivityRecord} as a {@link TaskRecord}
-     * children. However, this method will clean up references to this {@link ActivityRecord} in
-     * {@link ActivityStack}.
-     * @param task The new parent {@link TaskRecord}.
-     */
-    // TODO(task-unify): Can be remove after task level unification. Callers can just use addChild
-    void setTask(TaskRecord task) {
-        // Do nothing if the {@link TaskRecord} is the same as the current {@link getTaskRecord}.
-        if (task != null && task == getTaskRecord()) {
-            return;
-        }
-
-        final ActivityStack oldStack = getActivityStack();
-        final ActivityStack newStack = task != null ? task.getStack() : null;
-
-        // Inform old stack (if present) of activity removal and new stack (if set) of activity
-        // addition.
-        if (oldStack != newStack) {
-            if (oldStack != null) {
-                oldStack.onActivityRemovedFromStack(this);
-            }
-
-            if (newStack != null) {
-                newStack.onActivityAddedToStack(this);
-            }
-        }
-
-        final TaskRecord oldTask = this.task;
-        this.task = task;
-
-        // This is attaching the activity to the task which we only want to do once.
-        // TODO(task-unify): Need to re-work after unifying the task level since it will already
-        // have a parent then. Just need to restructure the re-parent case not to do this. NOTE that
-        // the reparenting flag passed in can't be used directly for this as it isn't set in
-        // ActivityRecord#reparent() case that ends up calling this method.
-        if (task != null && getParent() == null) {
-            task.addChild(this);
-        } else {
-            onParentChanged(task, oldTask);
-        }
-    }
-
-    /**
      * Sets the Task on this activity for the purposes of re-use during launch where we will
      * re-use another activity instead of this one for the launch.
      */
@@ -1220,8 +1175,8 @@
 
     @Override
     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        final TaskRecord oldTask = (oldParent != null) ? ((Task) oldParent).mTaskRecord : null;
-        final TaskRecord newTask = (newParent != null) ? ((Task) newParent).mTaskRecord : null;
+        final TaskRecord oldTask = oldParent != null ? (TaskRecord) oldParent : null;
+        final TaskRecord newTask = newParent != null ? (TaskRecord) newParent : null;
         this.task = newTask;
 
         super.onParentChanged(newParent, oldParent);
@@ -1230,14 +1185,12 @@
 
         if (oldParent == null && newParent != null) {
             // First time we are adding the activity to the system.
-            // TODO(task-unify): See if mVoiceInteraction variable is really needed after task level
-            // unification.
-            mVoiceInteraction = task.mTaskRecord != null && task.mTaskRecord.voiceSession != null;
+            mVoiceInteraction = newTask.voiceSession != null;
             mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L;
             onDisplayChanged(task.getDisplayContent());
-            if (task.mTaskRecord != null) {
-                task.mTaskRecord.updateOverrideConfigurationFromLaunchBounds();
-            }
+            // TODO(b/36505427): Maybe this call should be moved inside
+            // updateOverrideConfiguration()
+            newTask.updateOverrideConfigurationFromLaunchBounds();
             // Make sure override configuration is up-to-date before using to create window
             // controller.
             updateSizeCompatMode();
@@ -1279,8 +1232,6 @@
         // Inform old stack (if present) of activity removal and new stack (if set) of activity
         // addition.
         if (oldStack != newStack) {
-            // TODO(task-unify): Might be better to use onChildAdded and onChildRemoved signal for
-            // this once task level is unified.
             if (oldStack !=  null) {
                 oldStack.onActivityRemovedFromStack(this);
             }
@@ -1964,15 +1915,7 @@
 
         ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s"
                 + " to task=%d at %d", this, task.mTaskId, position);
-
-        reparent(newTask.getTask(), position);
-    }
-
-    // TODO(task-unify): Remove once Task level is unified.
-    void onParentChanged(TaskRecord newParent, TaskRecord oldParent) {
-        onParentChanged(
-                newParent != null ? newParent.mTask : null,
-                oldParent != null ? oldParent.mTask : null);
+        reparent(newTask, position);
     }
 
     private boolean isHomeIntent(Intent intent) {
@@ -2051,7 +1994,7 @@
     /**
      * @return Stack value from current task, null if there is no task.
      */
-    // TODO: Remove once ActivityStack and TaskStack are unified.
+    // TODO(stack-unify): Remove once ActivityStack and TaskStack are unified.
     <T extends ActivityStack> T getActivityStack() {
         return task != null ? (T) task.getStack() : null;
     }
@@ -2339,7 +2282,7 @@
 
     /** Finish all activities in the task with the same affinity as this one. */
     void finishActivityAffinity() {
-        final ArrayList<ActivityRecord> activities = getTaskRecord().mActivities;
+        final ArrayList<ActivityRecord> activities = getTaskRecord().mChildren;
         for (int index = activities.indexOf(this); index >= 0; --index) {
             final ActivityRecord cur = activities.get(index);
             if (!Objects.equals(cur.taskAffinity, taskAffinity)) {
@@ -2451,7 +2394,7 @@
             EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                     mUserId, System.identityHashCode(this),
                     task.mTaskId, shortComponentName, reason);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
+            final ArrayList<ActivityRecord> activities = task.mChildren;
             final int index = activities.indexOf(this);
             if (index < (task.getChildCount() - 1)) {
                 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
@@ -2505,7 +2448,7 @@
                 // When finishing the activity preemptively take the snapshot before the app window
                 // is marked as hidden and any configuration changes take place
                 if (mAtmService.mWindowManager.mTaskSnapshotController != null) {
-                    final ArraySet<Task> tasks = Sets.newArraySet(task.mTask);
+                    final ArraySet<Task> tasks = Sets.newArraySet(task);
                     mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
                     mAtmService.mWindowManager.mTaskSnapshotController
                             .addSkipClosingAppSnapshotTasks(tasks);
@@ -2547,7 +2490,8 @@
                 // In this case, we can set the visibility of all the task overlay activities when
                 // we detect the last one is finishing to keep them in sync.
                 if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {
-                    for (ActivityRecord taskOverlay : task.mActivities) {
+                    for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
+                        final ActivityRecord taskOverlay = task.getChildAt(i);
                         if (!taskOverlay.mTaskOverlay) {
                             continue;
                         }
@@ -2819,8 +2763,6 @@
     }
 
     /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */
-    // TODO(task-unify): Look into consolidating this with TaskRecord.removeChild once we unify
-    // task level.
     void removeFromHistory(String reason) {
         finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */);
         makeFinishingLocked();
@@ -4659,7 +4601,7 @@
         }
 
         // Check if position in task allows to become paused
-        final int positionInTask = task.mActivities.indexOf(this);
+        final int positionInTask = task.mChildren.indexOf(this);
         if (positionInTask == -1) {
             throw new IllegalStateException("Activity not found in its task");
         }
@@ -5387,7 +5329,7 @@
             return INVALID_TASK_ID;
         }
         final TaskRecord task = r.task;
-        final int activityNdx = task.mActivities.indexOf(r);
+        final int activityNdx = task.mChildren.indexOf(r);
         if (activityNdx < 0
                 || (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) {
             return INVALID_TASK_ID;
@@ -5751,7 +5693,7 @@
     @Override
     boolean isWaitingForTransitionStart() {
         final DisplayContent dc = getDisplayContent();
-        // TODO: Test for null can be removed once unification is done.
+        // TODO(display-unify): Test for null can be removed once unification is done.
         if (dc == null) return false;
         return dc.mAppTransition.isTransitionSet()
                 && (dc.mOpeningApps.contains(this)
@@ -6559,8 +6501,7 @@
                 // If the changes come from change-listener, the incoming parent configuration is
                 // still the old one. Make sure their orientations are the same to reduce computing
                 // the compatibility bounds for the intermediate state.
-                && (task.mTaskRecord == null || task.mTaskRecord
-                .getConfiguration().orientation == newParentConfig.orientation)) {
+                && (task.getConfiguration().orientation == newParentConfig.orientation)) {
             final Rect taskBounds = task.getBounds();
             // Since we only center the activity horizontally, if only the fixed height is smaller
             // than its container, the override bounds don't need to take effect.
@@ -6878,8 +6819,7 @@
             preserveWindow &= isResizeOnlyChange(changes);
             final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
             if (hasResizeChange) {
-                final boolean isDragResizing =
-                        getTaskRecord().getTask().isDragResizing();
+                final boolean isDragResizing = getTaskRecord().isDragResizing();
                 mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE
                         : RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
             } else {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 8e3995bf..9dade2c 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -254,7 +254,11 @@
     @Override
     protected void onParentChanged(
             ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        ActivityDisplay display = getParent();
+        if (oldParent != null) {
+            mPrevDisplayId = ((ActivityDisplay) oldParent).mDisplayId;
+        }
+
+        final ActivityDisplay display = getParent();
         if (display != null) {
             // Rotations are relative to the display. This means if there are 2 displays rotated
             // differently (eg. 2 monitors with one landscape and one portrait), moving a stack
@@ -292,18 +296,6 @@
         RESTARTING_PROCESS
     }
 
-    @VisibleForTesting
-    /* The various modes for the method {@link #removeTask}. */
-    // Task is being completely removed from all stacks in the system.
-    protected static final int REMOVE_TASK_MODE_DESTROYING = 0;
-    // Task is being removed from this stack so we can add it to another stack. In the case we are
-    // moving we don't want to perform some operations on the task like removing it from window
-    // manager or recents.
-    static final int REMOVE_TASK_MODE_MOVING = 1;
-    // Similar to {@link #REMOVE_TASK_MODE_MOVING} and the task will be added to the top of its new
-    // stack and the new stack will be on top of all stacks.
-    static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
-
     final ActivityTaskManagerService mService;
     final WindowManagerService mWindowManager;
 
@@ -381,6 +373,8 @@
     final int mStackId;
     /** The attached Display's unique identifier, or -1 if detached */
     int mDisplayId;
+    // Id of the previous display the stack was on.
+    int mPrevDisplayId = INVALID_DISPLAY;
 
     /** Stores the override windowing-mode from before a transient mode change (eg. split) */
     private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED;
@@ -962,7 +956,7 @@
     void positionChildWindowContainerAtTop(TaskRecord child) {
         if (mTaskStack != null) {
             // TODO: Remove after unification. This cannot be false after that.
-            mTaskStack.positionChildAtTop(child.getTask(), true /* includingParents */);
+            mTaskStack.positionChildAtTop(child, true /* includingParents */);
         }
     }
 
@@ -974,7 +968,7 @@
                 child.getStack(), true /* ignoreCurrent */);
         if (mTaskStack != null) {
             // TODO: Remove after unification. This cannot be false after that.
-            mTaskStack.positionChildAtBottom(child.getTask(),
+            mTaskStack.positionChildAtBottom(child,
                     nextFocusableStack == null /* includingParents */);
         }
     }
@@ -1168,7 +1162,7 @@
         }
         final TaskRecord task = r.getTaskRecord();
         final ActivityStack stack = r.getActivityStack();
-        if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
+        if (stack != null && task.mChildren.contains(r) && mTaskHistory.contains(task)) {
             if (stack != this) Slog.w(TAG,
                     "Illegal state! task does not point to stack it is in.");
             return r;
@@ -1183,7 +1177,8 @@
     /** Checks if there are tasks with specific UID in the stack. */
     boolean isUidPresent(int uid) {
         for (TaskRecord task : mTaskHistory) {
-            for (ActivityRecord r : task.mActivities) {
+            for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
+                final ActivityRecord r = task.getChildAt(i);
                 if (r.getUid() == uid) {
                     return true;
                 }
@@ -1195,7 +1190,8 @@
     /** Get all UIDs that are present in the stack. */
     void getPresentUIDs(IntArray presentUIDs) {
         for (TaskRecord task : mTaskHistory) {
-            for (ActivityRecord r : task.mActivities) {
+            for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
+                final ActivityRecord r = task.getChildAt(i);
                 presentUIDs.add(r.getUid());
             }
         }
@@ -1207,12 +1203,6 @@
         return display != null && display.isSingleTaskInstance();
     }
 
-    private void removeActivitiesFromLRUList(TaskRecord task) {
-        for (ActivityRecord r : task.mActivities) {
-            mLRUActivities.remove(r);
-        }
-    }
-
     /** @return {@code true} if LRU list contained the specified activity. */
     final boolean removeActivityFromLRUList(ActivityRecord activity) {
         return mLRUActivities.remove(activity);
@@ -3016,19 +3006,19 @@
         mTaskHistory.remove(task);
         mTaskHistory.add(position, task);
         if (mTaskStack != null) {
-            // TODO: this could not be false after unification.
-            mTaskStack.positionChildAt(task.getTask(), position);
+            // TODO: this can not be false after unification Stack.
+            mTaskStack.positionChildAt(task, position);
         }
-        updateTaskMovement(task, true);
+        task.updateTaskMovement(true);
     }
 
-    private void insertTaskAtTop(TaskRecord task, ActivityRecord starting) {
-        // TODO: Better place to put all the code below...may be addTask...
+    void insertTaskAtTop(TaskRecord task, ActivityRecord starting) {
+        // TODO: Better place to put all the code below...may be addChild...
         mTaskHistory.remove(task);
         // Now put task at top.
         final int position = getAdjustedPositionForTask(task, mTaskHistory.size(), starting);
         mTaskHistory.add(position, task);
-        updateTaskMovement(task, true);
+        task.updateTaskMovement(true);
         positionChildWindowContainerAtTop(task);
     }
 
@@ -3036,7 +3026,7 @@
         mTaskHistory.remove(task);
         final int position = getAdjustedPositionForTask(task, 0, null);
         mTaskHistory.add(position, task);
-        updateTaskMovement(task, true);
+        task.updateTaskMovement(true);
         positionChildWindowContainerAtBottom(task);
     }
 
@@ -3070,7 +3060,7 @@
                     if (!startIt) {
                         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                                 + task, new RuntimeException("here").fillInStackTrace());
-                        r.setTask(rTask);
+                        rTask.positionChildAtTop(r);
                         ActivityOptions.abort(options);
                         return;
                     }
@@ -3097,7 +3087,7 @@
         // Slot the activity into the history stack and proceed
         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
                 new RuntimeException("here").fillInStackTrace());
-        r.setTask(task);
+        task.positionChildAtTop(r);
 
         // The transition animation and starting window are not needed if {@code allowMoveToFront}
         // is false, because the activity won't be visible.
@@ -3272,7 +3262,7 @@
                 // with the same affinity is unlikely to be in the same stack.
                 final TaskRecord targetTask;
                 final ActivityRecord bottom =
-                        !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
+                        !mTaskHistory.isEmpty() && mTaskHistory.get(0).hasChild() ?
                                 mTaskHistory.get(0).getChildAt(0) : null;
                 if (bottom != null && target.taskAffinity.equals(bottom.getTaskRecord().affinity)) {
                     // If the activity currently at the bottom has the
@@ -3483,7 +3473,7 @@
                     // instance of the same activity?  Then we drop the instance
                     // below so it remains singleTop.
                     if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
-                        final ArrayList<ActivityRecord> taskActivities = task.mActivities;
+                        final ArrayList<ActivityRecord> taskActivities = task.mChildren;
                         final int targetNdx = taskActivities.indexOf(target);
                         if (targetNdx > 0) {
                             final ActivityRecord p = taskActivities.get(targetNdx - 1);
@@ -3637,7 +3627,7 @@
         finishedTask = r.getTaskRecord();
         int taskNdx = mTaskHistory.indexOf(finishedTask);
         final TaskRecord task = finishedTask;
-        int activityNdx = task.mActivities.indexOf(r);
+        int activityNdx = task.mChildren.indexOf(r);
         getDisplay().mDisplayContent.prepareAppTransition(
                 TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
         r.finishIfPossible(reason, false /* oomAdj */);
@@ -3774,7 +3764,7 @@
     final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
             Intent resultData) {
         final TaskRecord task = srec.getTaskRecord();
-        final ArrayList<ActivityRecord> activities = task.mActivities;
+        final ArrayList<ActivityRecord> activities = task.mChildren;
         final int start = activities.indexOf(srec);
         if (!mTaskHistory.contains(task) || (start < 0)) {
             return false;
@@ -3868,8 +3858,16 @@
      * an activity moves away from the stack.
      */
     void onActivityRemovedFromStack(ActivityRecord r) {
+        removeActivityFromLRUList(r);
         removeTimeoutsForActivity(r);
 
+        // TODO(stack-unify): null check will no longer be needed.
+        if (mTaskStack != null) {
+            mTaskStack.mExitingActivities.remove(r);
+        }
+        // TODO(stack-unify): Remove if no bugs showed up...
+        //r.mIsExiting = false;
+
         if (mResumedActivity != null && mResumedActivity == r) {
             setResumedActivity(null, "onActivityRemovedFromStack");
         }
@@ -4062,7 +4060,7 @@
         if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                 "Removing app " + app + " from history with " + i + " entries");
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mChildren;
             mTmpActivities.clear();
             mTmpActivities.addAll(activities);
 
@@ -4151,19 +4149,6 @@
         getDisplay().mDisplayContent.prepareAppTransition(transit, false);
     }
 
-    private void updateTaskMovement(TaskRecord task, boolean toFront) {
-        if (task.isPersistable) {
-            task.mLastTimeMoved = System.currentTimeMillis();
-            // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
-            // recently will be most negative, tasks sent to the bottom before that will be less
-            // negative. Similarly for recent tasks moved to the top which will be most positive.
-            if (!toFront) {
-                task.mLastTimeMoved *= -1;
-            }
-        }
-        mRootActivityContainer.invalidateTaskLayers();
-    }
-
     final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
             AppTimeTracker timeTracker, String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
@@ -4296,7 +4281,7 @@
 
         mTaskHistory.remove(tr);
         mTaskHistory.add(0, tr);
-        updateTaskMovement(tr, false);
+        tr.updateTaskMovement(false);
 
         getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
         moveToBack("moveTaskToBackLocked", tr);
@@ -4335,7 +4320,7 @@
 
         for (int taskIndex = mTaskHistory.indexOf(startTask); taskIndex >= 0; --taskIndex) {
             final TaskRecord task = mTaskHistory.get(taskIndex);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
+            final ArrayList<ActivityRecord> activities = task.mChildren;
             int activityIndex = (start.getTaskRecord() == task)
                     ? activities.indexOf(start) : activities.size() - 1;
             for (; activityIndex >= 0; --activityIndex) {
@@ -4375,10 +4360,10 @@
                 final TaskRecord task = mTaskHistory.get(i);
                 if (task.isResizeable()) {
                     if (tempTaskInsetBounds != null && !tempTaskInsetBounds.isEmpty()) {
-                        task.setDisplayedBounds(taskBounds);
+                        task.setOverrideDisplayedBounds(taskBounds);
                         task.setBounds(tempTaskInsetBounds);
                     } else {
-                        task.setDisplayedBounds(null);
+                        task.setOverrideDisplayedBounds(null);
                         task.setBounds(taskBounds);
                     }
                 }
@@ -4430,9 +4415,9 @@
         for (int i = mTaskHistory.size() - 1; i >= 0; i--) {
             final TaskRecord task = mTaskHistory.get(i);
             if (bounds == null || bounds.isEmpty()) {
-                task.setDisplayedBounds(null);
+                task.setOverrideDisplayedBounds(null);
             } else if (task.isResizeable()) {
-                task.setDisplayedBounds(bounds);
+                task.setOverrideDisplayedBounds(bounds);
             }
         }
     }
@@ -4477,7 +4462,7 @@
         TaskRecord lastTask = null;
         ComponentName homeActivity = null;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mChildren;
             mTmpActivities.clear();
             mTmpActivities.addAll(activities);
 
@@ -4675,7 +4660,7 @@
             pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
             pw.println(prefix + "* " + task);
             task.dump(pw, prefix + "  ");
-            dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities,
+            dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mChildren,
                     prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task);
         }
         return true;
@@ -4686,15 +4671,15 @@
 
         if ("all".equals(name)) {
             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-                activities.addAll(mTaskHistory.get(taskNdx).mActivities);
+                activities.addAll(mTaskHistory.get(taskNdx).mChildren);
             }
         } else if ("top".equals(name)) {
             final int top = mTaskHistory.size() - 1;
             if (top >= 0) {
-                final ArrayList<ActivityRecord> list = mTaskHistory.get(top).mActivities;
-                int listTop = list.size() - 1;
+                final TaskRecord task = mTaskHistory.get(top);
+                int listTop = task.getChildCount() - 1;
                 if (listTop >= 0) {
-                    activities.add(list.get(listTop));
+                    activities.add(task.getChildAt(listTop));
                 }
             }
         } else {
@@ -4702,7 +4687,9 @@
             matcher.build(name);
 
             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-                for (ActivityRecord r1 : mTaskHistory.get(taskNdx).mActivities) {
+                final TaskRecord task = mTaskHistory.get(taskNdx);
+                for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+                    final ActivityRecord r1 = task.getChildAt(activityNdx);
                     if (matcher.match(r1, r1.intent.getComponent())) {
                         activities.add(r1);
                     }
@@ -4734,57 +4721,50 @@
         return starting;
     }
 
+    // TODO(stack-unify): Merge into removeChild method below.
+    void onChildRemoved(TaskRecord child, DisplayContent dc) {
+        mTaskHistory.remove(child);
+        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, child.mTaskId, mStackId);
+
+        ActivityDisplay display = getDisplay();
+        if (display == null && dc != null) {
+            display = dc.mActivityDisplay;
+        }
+
+        if (display.isSingleTaskInstance()) {
+            mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
+        }
+
+        display.mDisplayContent.setLayoutNeeded();
+
+        if (mTaskHistory.isEmpty()) {
+            // Stack is now empty...
+            remove();
+        }
+    }
+
     /**
      * Removes the input task from this stack.
      *
      * @param task to remove.
      * @param reason for removal.
-     * @param mode task removal mode. Either {@link #REMOVE_TASK_MODE_DESTROYING},
-     *             {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
      */
-    void removeTask(TaskRecord task, String reason, int mode) {
-        if (!mTaskHistory.remove(task)) {
-            // Not really in this stack anymore...
-            return;
-        }
-
-        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.mTaskId, getStackId());
-
-        removeActivitiesFromLRUList(task);
-        updateTaskMovement(task, true);
-
-        if (mode == REMOVE_TASK_MODE_DESTROYING) {
-            task.cleanUpResourcesForDestroy();
-        }
-
+    void removeChild(TaskRecord task, String reason) {
         final ActivityDisplay display = getDisplay();
-        if (mTaskHistory.isEmpty()) {
-            if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
+        final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this);
+        mTaskStack.removeChild(task);
+        moveHomeStackToFrontIfNeeded(topFocused, display, reason);
+    }
+
+    void moveHomeStackToFrontIfNeeded(
+            boolean wasTopFocusedStack, ActivityDisplay display, String reason) {
+        if (mTaskHistory.isEmpty() && wasTopFocusedStack) {
             // We only need to adjust focused stack if this stack is in focus and we are not in the
             // process of moving the task to the top of the stack that will be focused.
-            if (mode != REMOVE_TASK_MODE_MOVING_TO_TOP
-                    && mRootActivityContainer.isTopDisplayFocusedStack(this)) {
-                String myReason = reason + " leftTaskHistoryEmpty";
-                if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) {
-                    display.moveHomeStackToFront(myReason);
-                }
+            String myReason = reason + " leftTaskHistoryEmpty";
+            if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) {
+                display.moveHomeStackToFront(myReason);
             }
-            if (isAttached()) {
-                display.positionChildAtBottom(this);
-            }
-            if (!isActivityTypeHome() || !isAttached()) {
-                remove();
-            }
-        }
-
-        task.setStack(null);
-
-        // Notify if a task from the pinned stack is being removed (or moved depending on the mode)
-        if (inPinnedWindowingMode()) {
-            mService.getTaskChangeNotificationController().notifyActivityUnpinned();
-        }
-        if (display != null && display.isSingleTaskInstance()) {
-            mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
         }
     }
 
@@ -4800,9 +4780,9 @@
             boolean toTop, ActivityRecord activity, ActivityRecord source,
             ActivityOptions options) {
         final TaskRecord task = TaskRecord.create(
-                mService, taskId, info, intent, voiceSession, voiceInteractor);
+                mService, taskId, info, intent, voiceSession, voiceInteractor, this);
         // add the task to stack first, mTaskPositioner might need the stack association
-        addTask(task, toTop, "createTaskRecord");
+        addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
         final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
         final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
                 .isKeyguardOrAodShowing(displayId);
@@ -4811,7 +4791,6 @@
                 && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
             task.setBounds(getRequestedOverrideBounds());
         }
-        task.createTask(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
         return task;
     }
 
@@ -4819,34 +4798,31 @@
         return new ArrayList<>(mTaskHistory);
     }
 
-    void addTask(final TaskRecord task, final boolean toTop, String reason) {
-        addTask(task, toTop ? MAX_VALUE : 0, true /* schedulePictureInPictureModeChange */, reason);
-        if (toTop) {
-            // TODO: figure-out a way to remove this call.
-            positionChildWindowContainerAtTop(task);
-        }
+    // TODO(stack-unify): Merge with addChild below.
+    void onChildAdded(TaskRecord task, int position) {
+        final boolean toTop = position >= mTaskHistory.size();
+        mTaskHistory.add(position, task);
+
+        // TODO: Feels like this should go in TaskRecord#onParentChanged
+        task.updateTaskMovement(toTop);
     }
 
-    // TODO: This shouldn't allow automatic reparenting. Remove the call to preAddTask and deal
-    // with the fall-out...
-    void addTask(final TaskRecord task, int position, boolean schedulePictureInPictureModeChange,
-            String reason) {
-        // TODO: Is this remove really needed? Need to look into the call path for the other addTask
-        mTaskHistory.remove(task);
+    void addChild(final TaskRecord task, final boolean toTop, boolean showForAllUsers) {
         if (isSingleTaskInstance() && !mTaskHistory.isEmpty()) {
             throw new IllegalStateException("Can only have one child on stack=" + this);
         }
 
-        position = getAdjustedPositionForTask(task, position, null /* starting */);
-        final boolean toTop = position >= mTaskHistory.size();
-        final ActivityStack prevStack = preAddTask(task, reason, toTop);
+        final int position =
+                getAdjustedPositionForTask(task, toTop ? MAX_VALUE : 0, null /* starting */);
 
-        mTaskHistory.add(position, task);
-        task.setStack(this);
+        // We only want to move the parents to the parents if we are creating this task at the
+        // top of its stack.
+        mTaskStack.addChild(task, position, showForAllUsers, toTop /*moveParents*/);
 
-        updateTaskMovement(task, toTop);
-
-        postAddTask(task, prevStack, schedulePictureInPictureModeChange);
+        if (toTop) {
+            // TODO: figure-out a way to remove this call.
+            positionChildWindowContainerAtTop(task);
+        }
     }
 
     void positionChildAt(TaskRecord task, int index) {
@@ -4861,8 +4837,14 @@
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
         final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
         insertTaskAtPosition(task, index);
-        task.setStack(this);
-        postAddTask(task, null /* prevStack */, true /* schedulePictureInPictureModeChange */);
+
+        // TODO: Investigate if this random code is really needed.
+        if (task.voiceSession != null) {
+            try {
+                task.voiceSession.taskStarted(task.intent, task.mTaskId);
+            } catch (RemoteException e) {
+            }
+        }
 
         if (wasResumed) {
             if (mResumedActivity != null) {
@@ -4879,32 +4861,6 @@
         mRootActivityContainer.resumeFocusedStacksTopActivities();
     }
 
-    private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) {
-        final ActivityStack prevStack = task.getStack();
-        if (prevStack != null && prevStack != this) {
-            prevStack.removeTask(task, reason,
-                    toTop ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
-        }
-        return prevStack;
-    }
-
-    /**
-     * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
-     *            change. Callers may set this to false if they are explicitly scheduling PiP mode
-     *            changes themselves, like during the PiP animation
-     */
-    private void postAddTask(TaskRecord task, ActivityStack prevStack,
-            boolean schedulePictureInPictureModeChange) {
-        if (schedulePictureInPictureModeChange && prevStack != null) {
-            mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, prevStack);
-        } else if (task.voiceSession != null) {
-            try {
-                task.voiceSession.taskStarted(task.intent, task.mTaskId);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
     public void setAlwaysOnTop(boolean alwaysOnTop) {
         if (isAlwaysOnTop() == alwaysOnTop) {
             return;
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index dc3d263..f8a7397 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -52,7 +52,6 @@
 
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
@@ -83,6 +82,7 @@
 import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import android.Manifest;
 import android.app.Activity;
@@ -1420,7 +1420,7 @@
                 // WM resizeTask must be done after the task is moved to the correct stack,
                 // because Task's setBounds() also updates dim layer's bounds, but that has
                 // dependency on the stack.
-                task.resizeWindowContainer();
+                task.resize(false /* relayout */, false /* forced */);
             }
         }
 
@@ -1885,26 +1885,22 @@
         final ActivityStack stack =
                 mRootActivityContainer.getLaunchStack(null, aOptions, task, onTop);
         final ActivityStack currentStack = task.getStack();
-        if (currentStack != null) {
-            // Task has already been restored once. See if we need to do anything more
-            if (currentStack == stack) {
-                // Nothing else to do since it is already restored in the right stack.
-                return true;
-            }
-            // Remove current stack association, so we can re-associate the task with the
-            // right stack below.
-            currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
+
+        if (currentStack == stack) {
+            // Nothing else to do since it is already restored in the right stack.
+            return true;
         }
 
-        stack.addTask(task, onTop, "restoreRecentTask");
-        // TODO: move call for creation here and other place into Stack.addTask()
-        task.createTask(onTop, true /* showForAllUsers */);
+        if (currentStack != null) {
+            // Task has already been restored once. Just re-parent it to the new stack.
+            task.reparent(stack.mTaskStack,
+                    POSITION_TOP, true /*moveParents*/, "restoreRecentTaskLocked");
+            return true;
+        }
+
+        stack.addChild(task, onTop, true /* showForAllUsers */);
         if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
                 "Added restored task=" + task + " to stack=" + stack);
-        for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-            final ActivityRecord r = task.getChildAt(activityNdx);
-            r.setTask(task);
-        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d1bb255..6edcb02 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -50,6 +50,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -1842,7 +1843,7 @@
             // {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The task
             // reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded}
             if (targetTaskTop.getTaskRecord() == null) {
-                targetTaskTop.setTask(targetTask);
+                targetTask.addChild(targetTaskTop);
             }
 
             if (top != null) {
@@ -1862,8 +1863,8 @@
                     // Go ahead and reset it.
                     mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
                             mLaunchFlags, mOptions);
-                    mTargetStack.addTask(targetTask,
-                            !mLaunchTaskBehind /* toTop */, "complyActivityFlags");
+                    mTargetStack.addChild(targetTask, !mLaunchTaskBehind /* toTop */,
+                            (mStartActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
                 }
             }
         } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) == 0 && !mAddingToTask
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 222f26e..da7af5f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -85,7 +85,6 @@
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -1996,7 +1995,7 @@
                     return false;
                 }
                 final TaskRecord task = r.getTaskRecord();
-                int index = task.mActivities.lastIndexOf(r);
+                int index = task.mChildren.lastIndexOf(r);
                 if (index > 0) {
                     ActivityRecord under = task.getChildAt(index - 1);
                     under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
@@ -2221,18 +2220,10 @@
                     Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
                     return rect;
                 }
-                if (task.getStack() != null) {
-                    // Return the bounds from window manager since it will be adjusted for various
-                    // things like the presense of a docked stack for tasks that aren't resizeable.
-                    task.getWindowContainerBounds(rect);
-                } else {
-                    // Task isn't in window manager yet since it isn't associated with a stack.
-                    // Return the persist value from activity manager
-                    if (!task.matchParentBounds()) {
-                        rect.set(task.getBounds());
-                    } else if (task.mLastNonFullscreenBounds != null) {
-                        rect.set(task.mLastNonFullscreenBounds);
-                    }
+                if (task.getParent() != null) {
+                    rect.set(task.getBounds());
+                } else if (task.mLastNonFullscreenBounds != null) {
+                    rect.set(task.mLastNonFullscreenBounds);
                 }
             }
         } finally {
@@ -2249,7 +2240,7 @@
             final TaskRecord tr = mRootActivityContainer.anyTaskForId(id,
                     MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
             if (tr != null) {
-                return tr.mTaskDescription;
+                return tr.getTaskDescription();
             }
         }
         return null;
@@ -3168,10 +3159,10 @@
                         null /* voiceSession */, null /* voiceInteractor */, !ON_TOP);
                 if (!mRecentTasks.addToBottom(task)) {
                     // The app has too many tasks already and we can't add any more
-                    stack.removeTask(task, "addAppTask", REMOVE_TASK_MODE_DESTROYING);
+                    stack.removeChild(task, "addAppTask");
                     return INVALID_TASK_ID;
                 }
-                task.mTaskDescription.copyFrom(description);
+                task.getTaskDescription().copyFrom(description);
 
                 // TODO: Send the thumbnail to WM to store it.
 
@@ -4489,7 +4480,7 @@
                     Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
                     return;
                 }
-                task.cancelWindowTransition();
+                task.cancelTaskWindowTransition();
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 8b4f7cc..30f3bc5 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -134,9 +134,9 @@
         onConfigurationChanged(newParentConfig, true /*forwardToChildren*/);
     }
 
-    // TODO: Consolidate with onConfigurationChanged() method above once unification is done. This
-    // is only currently need during the process of unification where we don't want configuration
-    // forwarded to a child from both parents.
+    // TODO(root-unify): Consolidate with onConfigurationChanged() method above once unification is
+    //  done. This is only currently need during the process of unification where we don't want
+    //  configuration forwarded to a child from both parents.
     public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
         mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
         resolveOverrideConfiguration(newParentConfig);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 2dae126..01cbc5d 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -211,9 +211,9 @@
                 // If there are multiple tasks in the target stack (ie. the home stack, with 3p
                 // and default launchers coexisting), then move the task to the top as a part of
                 // moving the stack to the front
-                if (targetStack.topTask() != targetActivity.getTaskRecord()) {
-                    targetStack.addTask(targetActivity.getTaskRecord(), true /* toTop */,
-                            "startRecentsActivity");
+                final TaskRecord task = targetActivity.getTaskRecord();
+                if (targetStack.topTask() != task) {
+                    targetStack.insertTaskAtTop(task, targetActivity);
                 }
             } else {
                 // No recents activity, create the new recents activity bottom most
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 51a3e720..dc78922 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -1265,8 +1265,7 @@
                     : task.realActivity != null ? task.realActivity.flattenToString()
                     : task.getTopActivity() != null ? task.getTopActivity().packageName
                     : "unknown";
-            taskBounds[i] = new Rect();
-            task.getWindowContainerBounds(taskBounds[i]);
+            taskBounds[i] = mService.getTaskBounds(task.mTaskId);
             taskUserIds[i] = task.mUserId;
         }
         info.taskIds = taskIds;
@@ -1876,7 +1875,12 @@
     ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus,
             boolean ignoreCurrent) {
         // First look for next focusable stack on the same display
-        final ActivityDisplay preferredDisplay = currentFocus.getDisplay();
+        ActivityDisplay preferredDisplay = currentFocus.getDisplay();
+        if (preferredDisplay == null) {
+            // Stack is currently detached because it is being removed. Use the previous display it
+            // was on.
+            preferredDisplay = getActivityDisplay(currentFocus.mPrevDisplayId);
+        }
         final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack(
                 currentFocus, ignoreCurrent);
         if (preferredFocusableStack != null) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f5d3aff..149bcfb 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -206,7 +206,7 @@
     }
 
     @Override
-    void onChildPositionChanged() {
+    void onChildPositionChanged(WindowContainer child) {
         mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
                 !mWmService.mPerDisplayFocusEnabled /* updateInputWindows */);
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 634990b..dce15bc 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
@@ -24,6 +25,7 @@
 import static android.content.res.Configuration.EMPTY;
 import static android.view.SurfaceControl.METADATA_TASK_ID;
 
+import static com.android.server.EventLogTags.WM_TASK_CREATED;
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS;
@@ -63,17 +65,21 @@
 class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener{
     static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
 
+    final ActivityTaskManagerService mAtmService;
+
     // TODO: Track parent marks like this in WindowContainer.
     TaskStack mStack;
     /* Unique identifier for this task. */
     final int mTaskId;
     /* User for which this task was created. */
-    final int mUserId;
+    // TODO: Make final
+    int mUserId;
 
     final Rect mPreparedFrozenBounds = new Rect();
     final Configuration mPreparedFrozenMergedConfig = new Configuration();
 
     // If non-empty, bounds used to display the task during animations/interactions.
+    // TODO(b/119687367): This member is temporary.
     private final Rect mOverrideDisplayedBounds = new Rect();
 
     /** ID of the display which rotation {@link #mRotation} has. */
@@ -90,11 +96,12 @@
     private Rect mTmpRect2 = new Rect();
 
     // Resize mode of the task. See {@link ActivityInfo#resizeMode}
-    private int mResizeMode;
+    // Based on the {@link ActivityInfo#resizeMode} of the root activity.
+    int mResizeMode;
 
-    // Whether the task supports picture-in-picture.
-    // See {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE}
-    private boolean mSupportsPictureInPicture;
+    // Whether or not this task and its activities support PiP. Based on the
+    // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity.
+    boolean mSupportsPictureInPicture;
 
     // Whether the task is currently being drag-resized
     private boolean mDragResizing;
@@ -116,40 +123,23 @@
     /** @see #setCanAffectSystemUiFlags */
     private boolean mCanAffectSystemUiFlags = true;
 
-    // TODO: remove after unification
-    TaskRecord mTaskRecord;
-
-    // TODO: Remove after unification.
-    @Override
-    public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
-        // Forward configuration changes in cases
-        // - children won't get it from TaskRecord
-        // - it's a pinned task
-        forwardToChildren &= (mTaskRecord == null) || inPinnedWindowingMode();
-        super.onConfigurationChanged(newParentConfig, forwardToChildren);
-    }
-
-    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode,
-            boolean supportsPictureInPicture, TaskDescription taskDescription,
-            TaskRecord taskRecord) {
-        super(service);
+    Task(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture,
+            TaskDescription taskDescription, ActivityTaskManagerService atm) {
+        super(atm.mWindowManager);
+        mAtmService = atm;
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mResizeMode = resizeMode;
         mSupportsPictureInPicture = supportsPictureInPicture;
-        mTaskRecord = taskRecord;
         mTaskDescription = taskDescription;
+        EventLog.writeEvent(WM_TASK_CREATED, mTaskId,
+                stack != null ? stack.mStackId : INVALID_STACK_ID);
 
         // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
         setOrientation(SCREEN_ORIENTATION_UNSET);
-        if (mTaskRecord != null) {
-            // This can be null when we call createTaskInStack in WindowTestUtils. Remove this after
-            // unification.
-            mTaskRecord.registerConfigurationChangeListener(this);
-        } else {
-            setBounds(getResolvedOverrideBounds());
-        }
+        // TODO(task-merge): Is this really needed?
+        setBounds(getResolvedOverrideBounds());
     }
 
     @Override
@@ -157,37 +147,40 @@
         return mStack != null ? mStack.getDisplayContent() : null;
     }
 
-    private int getAdjustedAddPosition(int suggestedPosition) {
-        final int size = mChildren.size();
-        if (suggestedPosition >= size) {
-            return Math.min(size, suggestedPosition);
+    int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
+        int maxPosition = mChildren.size();
+        if (!r.mTaskOverlay) {
+            // We want to place all non-overlay activities below overlays.
+            while (maxPosition > 0) {
+                final ActivityRecord current = mChildren.get(maxPosition - 1);
+                if (current.mTaskOverlay && !current.removed) {
+                    --maxPosition;
+                    continue;
+                }
+                break;
+            }
+            if (maxPosition < 0) {
+                maxPosition = 0;
+            }
         }
 
-        for (int pos = 0; pos < size && pos < suggestedPosition; ++pos) {
+        if (suggestedPosition >= maxPosition) {
+            return Math.min(maxPosition, suggestedPosition);
+        }
+
+        for (int pos = 0; pos < maxPosition && pos < suggestedPosition; ++pos) {
             // TODO: Confirm that this is the behavior we want long term.
             if (mChildren.get(pos).removed) {
                 // suggestedPosition assumes removed tokens are actually gone.
                 ++suggestedPosition;
             }
         }
-        return Math.min(size, suggestedPosition);
-    }
-
-    @Override
-    void addChild(ActivityRecord child, int position) {
-        position = getAdjustedAddPosition(position);
-        super.addChild(child, position);
-
-        // Inform the TaskRecord side of the child addition
-        // TODO(task-unify): Will be removed after task unification.
-        if (mTaskRecord != null) {
-            mTaskRecord.onChildAdded(child, position);
-        }
+        return Math.min(maxPosition, suggestedPosition);
     }
 
     @Override
     void positionChildAt(int position, ActivityRecord child, boolean includingParents) {
-        position = getAdjustedAddPosition(position);
+        position = getAdjustedAddPosition(child, position);
         super.positionChildAt(position, child, includingParents);
     }
 
@@ -222,47 +215,34 @@
     void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
-        if (mTaskRecord != null) {
-            mTaskRecord.unregisterConfigurationChangeListener(this);
-        }
-
         super.removeImmediately();
     }
 
-    void reparent(TaskStack stack, int position, boolean moveParents) {
-        if (stack == mStack) {
-            throw new IllegalArgumentException(
-                    "task=" + this + " already child of stack=" + mStack);
-        }
-        if (stack == null) {
-            throw new IllegalArgumentException("reparent: could not find stack.");
-        }
+    // TODO: Consolidate this with TaskRecord.reparent()
+    void reparent(TaskStack stack, int position, boolean moveParents, String reason) {
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
-        final DisplayContent prevDisplayContent = getDisplayContent();
 
-        // If we are moving from the fullscreen stack to the pinned stack
-        // then we want to preserve our insets so that there will not
-        // be a jump in the area covered by system decorations. We rely
-        // on the pinned animation to later unset this value.
-        if (stack.inPinnedWindowingMode()) {
-            mPreserveNonFloatingState = true;
-        } else {
-            mPreserveNonFloatingState = false;
+        final ActivityStack prevStack = mStack.mActivityStack;
+        final boolean wasTopFocusedStack =
+                mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
+        final ActivityDisplay prevStackDisplay = prevStack.getDisplay();
+
+        reparent(stack, position);
+
+        if (!moveParents) {
+            // Only move home stack forward if we are not going to move the new parent forward.
+            prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason);
         }
 
-        getParent().removeChild(this);
-        stack.addTask(this, position, showForAllUsers(), moveParents);
+        mStack = stack;
+        stack.positionChildAt(position, this, moveParents);
 
-        // Relayout display(s).
-        final DisplayContent displayContent = stack.getDisplayContent();
-        displayContent.setLayoutNeeded();
-        if (prevDisplayContent != displayContent) {
-            onDisplayChanged(displayContent);
-            prevDisplayContent.setLayoutNeeded();
-        }
-        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+        // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
+        // our insets so that there will not be a jump in the area covered by system decorations.
+        // We rely on the pinned animation to later unset this value.
+        mPreserveNonFloatingState = stack.inPinnedWindowingMode();
     }
 
     /** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */
@@ -270,46 +250,6 @@
         mStack.positionChildAt(position, this, false /* includingParents */);
     }
 
-    @Override
-    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        super.onParentChanged(newParent, oldParent);
-
-        // Update task bounds if needed.
-        adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
-
-        if (getWindowConfiguration().windowsAreScaleable()) {
-            // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
-            // while a resize is pending.
-            forceWindowsScaleable(true /* force */);
-        } else {
-            forceWindowsScaleable(false /* force */);
-        }
-    }
-
-    @Override
-    void removeChild(ActivityRecord child) {
-        if (!mChildren.contains(child)) {
-            Slog.e(TAG, "removeChild: token=" + this + " not found.");
-            return;
-        }
-
-        super.removeChild(child);
-
-        // Inform the TaskRecord side of the child removal
-        // TODO(task-unify): Will be removed after task unification.
-        if (mTaskRecord != null) {
-            mTaskRecord.onChildRemoved(child);
-        }
-
-        // TODO(task-unify): Need to make this account for what we are doing in
-        // ActivityRecord.removeFromHistory so that the task isn't removed in some situations when
-        // we unify task level.
-        if (mChildren.isEmpty()) {
-            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeActivity: last activity");
-            removeIfPossible();
-        }
-    }
-
     void setSendingToBottom(boolean toBottom) {
         for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) {
             mChildren.get(appTokenNdx).sendingToBottom = toBottom;
@@ -331,7 +271,7 @@
     @Override
     public int setBounds(Rect bounds) {
         int rotation = Surface.ROTATION_0;
-        final DisplayContent displayContent = mStack.getDisplayContent();
+        final DisplayContent displayContent = mStack != null ? mStack.getDisplayContent() : null;
         if (displayContent != null) {
             rotation = displayContent.getDisplayInfo().rotation;
         } else if (bounds == null) {
@@ -355,9 +295,8 @@
 
         // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
         // it if possible.
-        // TODO: Move to TaskRecord after unification is done.
-        if (mTaskRecord != null && mTaskRecord.getParent() != null) {
-            mTaskRecord.onConfigurationChanged(mTaskRecord.getParent().getConfiguration());
+        if (getParent() != null) {
+            onConfigurationChanged(getParent().getConfiguration());
             return true;
         }
         return false;
@@ -379,8 +318,9 @@
     }
 
     /**
-     * Sets bounds that override where the task is displayed. Used during transient operations
-     * like animation / interaction.
+     * Displayed bounds are used to set where the task is drawn at any given time. This is
+     * separate from its actual bounds so that the app doesn't see any meaningful configuration
+     * changes during transitionary periods.
      */
     void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) {
         if (overrideDisplayedBounds != null) {
@@ -399,13 +339,13 @@
         return mOverrideDisplayedBounds;
     }
 
-    void setResizeable(int resizeMode) {
-        mResizeMode = resizeMode;
+    boolean isResizeable(boolean checkSupportsPip) {
+        return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
+                || (checkSupportsPip && mSupportsPictureInPicture));
     }
 
     boolean isResizeable() {
-        return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture
-                || mWmService.mAtmService.mForceResizableActivities;
+        return isResizeable(true /* checkSupportsPip */);
     }
 
     /**
@@ -462,6 +402,10 @@
         }
     }
 
+    /**
+     * Gets the current overridden displayed bounds. These will be empty if the task is not
+     * currently overriding where it is displayed.
+     */
     @Override
     public Rect getDisplayedBounds() {
         if (mOverrideDisplayedBounds.isEmpty()) {
@@ -577,7 +521,7 @@
         setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
     }
 
-    private void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
+    void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
         if (displayContent == null) {
             return;
         }
@@ -618,9 +562,7 @@
 
         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
-            if (mTaskRecord != null) {
-                mTaskRecord.requestResize(getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
-            }
+            mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
         }
     }
 
@@ -758,7 +700,8 @@
     }
 
     void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
-        mTaskRecord.onSnapshotChanged(snapshot);
+        mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
+                mTaskId, snapshot);
     }
 
     TaskDescription getTaskDescription() {
@@ -794,11 +737,6 @@
         mDimmer.dontAnimateExit();
     }
 
-    @Override
-    public String toString() {
-        return "{taskId=" + mTaskId + " appTokens=" + mChildren + "}";
-    }
-
     String getName() {
         return toShortString();
     }
@@ -825,9 +763,8 @@
         }
     }
 
-    @CallSuper
-    @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged.
+    void writeToProtoInnerTaskOnly(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
             return;
@@ -843,8 +780,10 @@
         proto.write(FILLS_PARENT, matchParentBounds());
         getBounds().writeToProto(proto, BOUNDS);
         mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
-        proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
-        proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
+        if (mSurfaceControl != null) {
+            proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
+            proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
+        }
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 6920d9d..672827f 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -52,11 +52,10 @@
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.server.EventLogTags.WM_TASK_CREATED;
+import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.am.TaskRecordProto.ACTIVITIES;
 import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
 import static com.android.server.am.TaskRecordProto.BOUNDS;
-import static com.android.server.am.TaskRecordProto.CONFIGURATION_CONTAINER;
 import static com.android.server.am.TaskRecordProto.FULLSCREEN;
 import static com.android.server.am.TaskRecordProto.ID;
 import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
@@ -66,11 +65,9 @@
 import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
 import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
 import static com.android.server.am.TaskRecordProto.STACK_ID;
+import static com.android.server.am.TaskRecordProto.TASK;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
@@ -85,10 +82,6 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import static java.lang.Integer.MAX_VALUE;
 
@@ -143,7 +136,7 @@
 import java.util.ArrayList;
 import java.util.Objects;
 
-class TaskRecord extends ConfigurationContainer {
+class TaskRecord extends Task {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -212,7 +205,6 @@
      */
     private static TaskRecordFactory sTaskRecordFactory;
 
-    final int mTaskId;      // Unique identifier for this task.
     String affinity;        // The affinity name for this task, or null; may change identity.
     String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
     final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
@@ -238,17 +230,11 @@
     boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
 
     String stringName;      // caching of toString() result.
-    int mUserId;            // user for which this task was created
     boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
                                 // was changed.
 
     int numFullscreen;      // Number of fullscreen activities.
 
-    int mResizeMode;        // The resize mode of this task and its activities.
-                            // Based on the {@link ActivityInfo#resizeMode} of the root activity.
-    private boolean mSupportsPictureInPicture;  // Whether or not this task and its activities
-            // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag
-            // of the root activity.
     /** Can't be put in lockTask mode. */
     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
     /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
@@ -264,13 +250,6 @@
 
     int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
 
-    // This represents the last resolved activity values for this task
-    // NOTE: This value needs to be persisted with each task
-    TaskDescription mTaskDescription;
-
-    /** List of all activities in the task arranged in history order */
-    final ArrayList<ActivityRecord> mActivities;
-
     /** Current stack. Setter must always be used to update the value. */
     private ActivityStack mStack;
 
@@ -308,8 +287,6 @@
     int mCallingUid;
     String mCallingPackage;
 
-    final ActivityTaskManagerService mAtmService;
-
     private final Rect mTmpStableBounds = new Rect();
     private final Rect mTmpNonDecorBounds = new Rect();
     private final Rect mTmpBounds = new Rect();
@@ -328,17 +305,9 @@
     // This number will be assigned when we evaluate OOM scores for all visible tasks.
     int mLayerRank = -1;
 
-    // When non-empty, this represents the bounds this task will be drawn at. This gets set during
-    // transient operations such as split-divider dragging and animations.
-    // TODO(b/119687367): This member is temporary.
-    final Rect mDisplayedBounds = new Rect();
-
     /** Helper object used for updating override configuration. */
     private Configuration mTmpConfig = new Configuration();
 
-    // TODO: remove after unification
-    Task mTask;
-
     /** Used by fillTaskInfo */
     final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
 
@@ -346,21 +315,21 @@
      * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
      * ActivityInfo, Intent, TaskDescription)} instead.
      */
-    TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info,
-            Intent _intent, IVoiceInteractionSession _voiceSession,
-            IVoiceInteractor _voiceInteractor, TaskDescription _taskDescription) {
+    TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
+            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+            TaskDescription _taskDescription, ActivityStack stack) {
         this(atmService, _taskId, _intent,  null /*_affinityIntent*/, null /*_affinity*/,
                 null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
                 false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
                 UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
-                null /*_lastDescription*/, new ArrayList<>(), System.currentTimeMillis(),
+                null /*_lastDescription*/, System.currentTimeMillis(),
                 true /*neverRelinquishIdentity*/,
                 _taskDescription != null ? _taskDescription : new TaskDescription(),
                 _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
                 info.applicationInfo.uid, info.packageName, info.resizeMode,
                 info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
                 false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
-                _voiceSession, _voiceInteractor);
+                _voiceSession, _voiceInteractor, stack);
     }
 
     /** Don't use constructor directly. This is only used by XML parser. */
@@ -368,15 +337,16 @@
             Intent _affinityIntent, String _affinity, String _rootAffinity,
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
             boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
-            int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
+            int _effectiveUid, String _lastDescription,
             long lastTimeMoved, boolean neverRelinquishIdentity,
             TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
             int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
             int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
             boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
-            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
-        mAtmService = atmService;
-        mTaskId = _taskId;
+            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+            ActivityStack stack) {
+        super(_taskId, stack != null ? stack.mTaskStack : null, _userId, resizeMode,
+                supportsPictureInPicture, _lastTaskDescription, atmService);
         mRemoteToken = new RemoteToken(this);
         affinityIntent = _affinityIntent;
         affinity = _affinity;
@@ -390,15 +360,12 @@
         isAvailable = true;
         autoRemoveRecents = _autoRemoveRecents;
         askedCompatMode = _askedCompatMode;
-        mUserId = _userId;
         mUserSetupComplete = userSetupComplete;
         effectiveUid = _effectiveUid;
         touchActiveTime();
         lastDescription = _lastDescription;
-        mActivities = activities;
         mLastTimeMoved = lastTimeMoved;
         mNeverRelinquishIdentity = neverRelinquishIdentity;
-        mTaskDescription = _lastTaskDescription;
         mAffiliatedTaskId = taskAffiliation;
         mAffiliatedTaskColor = taskAffiliationColor;
         mPrevAffiliateTaskId = prevTaskId;
@@ -406,7 +373,6 @@
         mCallingUid = callingUid;
         mCallingPackage = callingPackage;
         mResizeMode = resizeMode;
-        mSupportsPictureInPicture = supportsPictureInPicture;
         if (info != null) {
             setIntent(_intent, info);
             setMinDimensions(info);
@@ -418,39 +384,6 @@
         mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
     }
 
-    Task getTask() {
-        return mTask;
-    }
-
-    void createTask(boolean onTop, boolean showForAllUsers) {
-        if (mTask != null) {
-            throw new IllegalArgumentException("mTask=" + mTask
-                    + " already created for task=" + this);
-        }
-
-        final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
-        final TaskStack stack = getStack().getTaskStack();
-
-        if (stack == null) {
-            throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack);
-        }
-        EventLog.writeEvent(WM_TASK_CREATED, mTaskId, stack.mStackId);
-        mTask = new Task(mTaskId, stack, mUserId, mAtmService.mWindowManager, mResizeMode,
-                mSupportsPictureInPicture, mTaskDescription, this);
-        final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
-
-        if (!mDisplayedBounds.isEmpty()) {
-            mTask.setOverrideDisplayedBounds(mDisplayedBounds);
-        }
-        // We only want to move the parents to the parents if we are creating this task at the
-        // top of its stack.
-        stack.addTask(mTask, position, showForAllUsers, onTop /* moveParents */);
-    }
-
-    void setTask(Task task) {
-        mTask = task;
-    }
-
     void cleanUpResourcesForDestroy() {
         if (hasChild()) {
             return;
@@ -473,60 +406,33 @@
             mAtmService.mStackSupervisor.mRecentTasks.remove(this);
         }
 
-        removeWindowContainer();
+        removeIfPossible();
     }
 
     @VisibleForTesting
-    void removeWindowContainer() {
+    @Override
+    void removeIfPossible() {
         mAtmService.getLockTaskController().clearLockedTask(this);
-        if (mTask == null) {
-            if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId);
-            return;
-        }
-        mTask.removeIfPossible();
-        mTask = null;
-        if (!getWindowConfiguration().persistTaskBounds()) {
-            // Reset current bounds for task whose bounds shouldn't be persisted so it uses
-            // default configuration the next time it launches.
-            setBounds(null);
-        }
+        super.removeIfPossible();
         mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
     }
 
-    void onSnapshotChanged(TaskSnapshot snapshot) {
-        mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(mTaskId, snapshot);
-    }
-
     void setResizeMode(int resizeMode) {
         if (mResizeMode == resizeMode) {
             return;
         }
         mResizeMode = resizeMode;
-        mTask.setResizeable(resizeMode);
         mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
         mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
     }
 
-    void setTaskDockedResizing(boolean resizing) {
-        if (mTask == null) {
-            Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found.");
-            return;
-        }
-        mTask.setTaskDockedResizing(resizing);
-    }
-
-    // TODO: Consolidate this with the resize() method below.
-    public void requestResize(Rect bounds, int resizeMode) {
-        mAtmService.resizeTask(mTaskId, bounds, resizeMode);
-    }
-
     boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
         mAtmService.deferWindowLayout();
 
         try {
             final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
 
-            if (mTask == null) {
+            if (getParent() == null) {
                 // Task doesn't exist in window manager yet (e.g. was restored from recents).
                 // All we can do for now is update the bounds so it can be used when the task is
                 // added to window manager.
@@ -577,7 +483,7 @@
                     }
                 }
             }
-            mTask.resize(kept, forced);
+            resize(kept, forced);
 
             saveLaunchingStateIfNeeded();
 
@@ -588,19 +494,6 @@
         }
     }
 
-    // TODO: Investigate combining with the resize() method above.
-    void resizeWindowContainer() {
-        mTask.resize(false /* relayout */, false /* forced */);
-    }
-
-    void getWindowContainerBounds(Rect bounds) {
-        if (mTask != null) {
-            mTask.getBounds(bounds);
-        } else {
-            bounds.setEmpty();
-        }
-    }
-
     /**
      * Convenience method to reparent a task to the top or bottom position of the stack.
      */
@@ -708,32 +601,16 @@
             // Adjust the position for the new parent stack as needed.
             position = toStack.getAdjustedPositionForTask(this, position, null /* starting */);
 
-            // Must reparent first in window manager to avoid a situation where AM can delete the
-            // we are coming from in WM before we reparent because it became empty.
-            mTask.reparent(toStack.getTaskStack(), position,
-                    moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
-
             final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
                     || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
-            // Move the task
-            sourceStack.removeTask(this, reason, moveStackToFront
-                    ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
-            toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason);
+
+            reparent(toStack.getTaskStack(), position, moveStackToFront, reason);
 
             if (schedulePictureInPictureModeChange) {
                 // Notify of picture-in-picture mode changes
                 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
             }
 
-            // TODO: Ensure that this is actually necessary here
-            // Notify the voice session if required
-            if (voiceSession != null) {
-                try {
-                    voiceSession.taskStarted(intent, mTaskId);
-                } catch (RemoteException e) {
-                }
-            }
-
             // If the task had focus before (or we're requested to move focus), move focus to the
             // new stack by moving the stack to the front.
             if (r != null) {
@@ -809,14 +686,6 @@
                 || targetWindowingMode == WINDOWING_MODE_FREEFORM;
     }
 
-    void cancelWindowTransition() {
-        if (mTask == null) {
-            Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found.");
-            return;
-        }
-        mTask.cancelTaskWindowTransition();
-    }
-
     /**
      * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
      */
@@ -970,67 +839,105 @@
         return (T) mStack;
     }
 
-    /**
-     * Must be used for setting parent stack because it performs configuration updates.
-     * Must be called after adding task as a child to the stack.
-     */
-    // TODO(task-unify): Remove or rework after task level unification.
-    void setStack(ActivityStack stack) {
-        if (stack != null && !stack.isInStackLocked(this)) {
-            throw new IllegalStateException("Task must be added as a Stack child first.");
-        }
-        final ActivityStack oldStack = mStack;
-        mStack = stack;
+    // TODO(stack-unify): Can be removed on stack unified.
+    void onParentChanged(ActivityStack newParent, ActivityStack oldParent) {
+        onParentChanged(
+                newParent != null ? newParent.mTaskStack : null,
+                oldParent != null ? oldParent.mTaskStack : null);
+    }
 
-        // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this
-        // {@link ActivityRecord} from its current {@link ActivityStack}.
+    @Override
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        final ActivityStack oldStack = (oldParent != null)
+                ? ((TaskStack) oldParent).mActivityStack : null;
+        final ActivityStack newStack = (newParent != null)
+                ? ((TaskStack) newParent).mActivityStack : null;
 
-        if (oldStack != mStack) {
+        mStack = newStack;
+
+        super.onParentChanged(newParent, oldParent);
+
+        if (oldStack != null) {
             for (int i = getChildCount() - 1; i >= 0; --i) {
                 final ActivityRecord activity = getChildAt(i);
+                oldStack.onActivityRemovedFromStack(activity);
+            }
 
-                if (oldStack != null) {
-                    oldStack.onActivityRemovedFromStack(activity);
-                }
+            updateTaskMovement(true /*toFront*/);
 
-                if (mStack != null) {
-                    stack.onActivityAddedToStack(activity);
+            if (oldStack.inPinnedWindowingMode()
+                    && (newStack == null || !newStack.inPinnedWindowingMode())) {
+                // Notify if a task from the pinned stack is being removed
+                // (or moved depending on the mode).
+                mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
+            }
+        }
+
+        if (newStack != null) {
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityRecord activity = getChildAt(i);
+                newStack.onActivityAddedToStack(activity);
+            }
+
+            // TODO: Ensure that this is actually necessary here
+            // Notify the voice session if required
+            if (voiceSession != null) {
+                try {
+                    voiceSession.taskStarted(intent, mTaskId);
+                } catch (RemoteException e) {
                 }
             }
         }
 
-        onParentChanged(mStack, oldStack);
+        // First time we are adding the task to the system.
+        if (oldParent == null && newParent != null) {
+
+            // TODO: Super random place to be doing this, but aligns with what used to be done
+            // before we unified Task level. Look into if this can be done in a better place.
+            updateOverrideConfigurationFromLaunchBounds();
+        }
+
+        // Task is being removed.
+        if (oldParent != null && newParent == null) {
+            cleanUpResourcesForDestroy();
+        }
+
+
+        // Update task bounds if needed.
+        adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
+
+        if (getWindowConfiguration().windowsAreScaleable()) {
+            // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
+            // while a resize is pending.
+            forceWindowsScaleable(true /* force */);
+        } else {
+            forceWindowsScaleable(false /* force */);
+        }
+
+        mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
+    }
+
+    /** TODO(task-merge): Consolidate into {@link TaskStack#onChildPositionChanged}. */
+    void updateTaskMovement(boolean toFront) {
+        if (isPersistable) {
+            mLastTimeMoved = System.currentTimeMillis();
+            // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
+            // recently will be most negative, tasks sent to the bottom before that will be less
+            // negative. Similarly for recent tasks moved to the top which will be most positive.
+            if (!toFront) {
+                mLastTimeMoved *= -1;
+            }
+        }
+        mAtmService.mRootActivityContainer.invalidateTaskLayers();
     }
 
     /**
-     * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set.
+     * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
      */
     int getStackId() {
         return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
     }
 
-    @Override
-    protected int getChildCount() {
-        return mActivities.size();
-    }
-
-    @Override
-    protected ActivityRecord getChildAt(int index) {
-        return mActivities.get(index);
-    }
-
-    @Override
-    protected ConfigurationContainer getParent() {
-        return mStack;
-    }
-
-    @Override
-    protected void onParentChanged(
-            ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        super.onParentChanged(newParent, oldParent);
-        mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
-    }
-
     // Close up recents linked list.
     private void closeRecentsChain() {
         if (mPrevAffiliate != null) {
@@ -1121,16 +1028,6 @@
         return null;
     }
 
-    boolean isVisible() {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = getChildAt(i);
-            if (r.visible) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Return true if any activities in this task belongs to input uid.
      */
@@ -1210,15 +1107,10 @@
      * Reorder the history stack so that the passed activity is brought to the front.
      */
     final void moveActivityToFrontLocked(ActivityRecord newTop) {
-        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
-                "Removing and adding activity " + newTop
-                + " to stack at top callers=" + Debug.getCallers(4));
+        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
+                + newTop + " to stack at top callers=" + Debug.getCallers(4));
 
-        mActivities.remove(newTop);
-        mActivities.add(newTop);
-
-        // Make sure window manager is aware of the position change.
-        mTask.positionChildAtTop(newTop);
+        positionChildAtTop(newTop);
         updateEffectiveIntent();
     }
 
@@ -1232,19 +1124,29 @@
         return getChildAt(0).getActivityType();
     }
 
-    /** Called when a Task child is added from the Task.java side. */
-    // TODO(task-unify): Just override addChild to do what is needed when someone calls to add a
-    // child.
-    void onChildAdded(ActivityRecord r, int index) {
+    @Override
+    void addChild(ActivityRecord r, int index) {
+        if (r.getParent() != null) {
+            // Shouldn't already have a parent since we are just adding to the task...Maybe you
+            // meant to use reparent?
+            throw new IllegalStateException(
+                    "r=" + r + " parent=" + r.getParent() + " task=" + this);
+        }
+
+        // If this task had any child before we added this one.
+        boolean hadChild = hasChild();
+
+        index = getAdjustedAddPosition(r, index);
+        super.addChild(r, index);
+
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
         r.inHistory = true;
 
-        // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
-        if (!mActivities.remove(r) && r.occludesParent()) {
-            // Was not previously in list.
+        if (r.occludesParent()) {
             numFullscreen++;
         }
         // Only set this based on the first activity
-        if (!hasChild()) {
+        if (!hadChild) {
             if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
                 // Normally non-standard activity type for the activity record will be set when the
                 // object is created, however we delay setting the standard application type until
@@ -1264,20 +1166,6 @@
             r.setActivityType(getActivityType());
         }
 
-        final int size = getChildCount();
-
-        if (index == size && size > 0) {
-            final ActivityRecord top = getChildAt(size - 1);
-            if (top.mTaskOverlay) {
-                // Place below the task overlay activity since the overlay activity should always
-                // be on top.
-                index--;
-            }
-        }
-
-        index = Math.min(size, index);
-        mActivities.add(index, r);
-
         updateEffectiveIntent();
         if (r.isPersistable()) {
             mAtmService.notifyTaskPersisterLocked(this, false);
@@ -1288,31 +1176,23 @@
         mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
     }
 
-    // TODO(task-unify): Merge onChildAdded method below into this since task will be a single
-    //  object.
     void addChild(ActivityRecord r) {
-        if (r.getParent() != null) {
-            // Shouldn't already have a parent since we are just adding to the task...
-            throw new IllegalStateException(
-                    "r=" + r + " parent=" + r.getParent() + " task=" + this);
-        }
-
-        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
-        // This means the activity isn't attached to Task.java yet. Go ahead and do that.
-        // TODO(task-unify): Remove/call super once we unify task level.
-        if (mTask != null) {
-            mTask.addChild(r, Integer.MAX_VALUE /* add on top */);
-        } else {
-            onChildAdded(r, Integer.MAX_VALUE);
-        }
+        addChild(r, Integer.MAX_VALUE /* add on top */);
     }
 
-    /** Called when a Task child is removed from the Task.java side. */
-    // TODO(task-unify): Just override removeChild to do what is needed when someone calls to remove
-    // a child.
-    void onChildRemoved(ActivityRecord r) {
-        if (mActivities.remove(r) && r.occludesParent()) {
-            // Was previously in list.
+    @Override
+    void removeChild(ActivityRecord r) {
+        removeChild(r, "removeChild");
+    }
+
+    void removeChild(ActivityRecord r, String reason) {
+        if (!mChildren.contains(r)) {
+            Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
+            return;
+        }
+
+        super.removeChild(r);
+        if (r.occludesParent()) {
             numFullscreen--;
         }
         if (r.isPersistable()) {
@@ -1336,16 +1216,19 @@
                 // When destroying a task, tell the supervisor to remove it so that any activity it
                 // has can be cleaned up correctly. This is currently the only place where we remove
                 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
-                // state into removeTask(), we just clear the task here before the other residual
+                // state into removeChild(), we just clear the task here before the other residual
                 // work.
-                // TODO: If the callers to removeTask() changes such that we have multiple places
-                //       where we are destroying the task, move this back into removeTask()
+                // TODO: If the callers to removeChild() changes such that we have multiple places
+                //       where we are destroying the task, move this back into removeChild()
                 mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
-                        !REMOVE_FROM_RECENTS, "onChildRemoved");
+                        !REMOVE_FROM_RECENTS, reason);
             }
         } else if (!mReuseTask) {
             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
-            mStack.removeTask(this, "onChildRemoved", REMOVE_TASK_MODE_DESTROYING);
+            mStack.removeChild(this, reason);
+            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
+                    "removeChild: last r=" + r + " in t=" + this);
+            removeIfPossible();
         }
     }
 
@@ -1380,7 +1263,7 @@
      * Completely remove all activities associated with an existing
      * task starting at a specified index.
      */
-    final void performClearTaskAtIndexLocked(int activityNdx, String reason) {
+    private void performClearTaskAtIndexLocked(int activityNdx, String reason) {
         int numActivities = getChildCount();
         for ( ; activityNdx < numActivities; ++activityNdx) {
             final ActivityRecord r = getChildAt(activityNdx);
@@ -1390,7 +1273,7 @@
             if (mStack == null) {
                 // Task was restored from persistent storage.
                 r.takeFromHistory();
-                mActivities.remove(activityNdx);
+                removeChild(r);
                 --activityNdx;
                 --numActivities;
             } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
@@ -1526,20 +1409,13 @@
                 " mLockTaskAuth=" + lockTaskAuthToString());
     }
 
-    private boolean isResizeable(boolean checkSupportsPip) {
-        return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
-                || (checkSupportsPip && mSupportsPictureInPicture));
-    }
-
-    boolean isResizeable() {
-        return isResizeable(true /* checkSupportsPip */);
-    }
-
     @Override
     public boolean supportsSplitScreenWindowingMode() {
         // A task can not be docked even if it is considered resizeable because it only supports
         // picture-in-picture mode but has a non-resizeable resizeMode
         return super.supportsSplitScreenWindowingMode()
+                // TODO(task-group): Probably makes sense to move this and associated code into
+                // WindowContainer so it affects every node.
                 && mAtmService.mSupportsSplitScreenMultiWindow
                 && (mAtmService.mForceResizableActivities
                         || (isResizeable(false /* checkSupportsPip */)
@@ -1672,15 +1548,13 @@
                 }
                 topActivity = false;
             }
-            mTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
-                    colorPrimary, colorBackground, statusBarColor, navigationBarColor,
+            final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
+                    iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
                     statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent);
-            if (mTask != null) {
-                mTask.setTaskDescription(mTaskDescription);
-            }
+            setTaskDescription(taskDescription);
             // Update the task affiliation color if we are the parent of the group
             if (mTaskId == mAffiliatedTaskId) {
-                mAffiliatedTaskColor = mTaskDescription.getPrimaryColor();
+                mAffiliatedTaskColor = taskDescription.getPrimaryColor();
             }
         }
     }
@@ -1903,38 +1777,6 @@
     }
 
     /**
-     * Displayed bounds are used to set where the task is drawn at any given time. This is
-     * separate from its actual bounds so that the app doesn't see any meaningful configuration
-     * changes during transitionary periods.
-     */
-    void setDisplayedBounds(Rect bounds) {
-        if (bounds == null) {
-            mDisplayedBounds.setEmpty();
-        } else {
-            mDisplayedBounds.set(bounds);
-        }
-        if (mTask != null) {
-            mTask.setOverrideDisplayedBounds(
-                    mDisplayedBounds.isEmpty() ? null : mDisplayedBounds);
-        }
-    }
-
-    /**
-     * Gets the current overridden displayed bounds. These will be empty if the task is not
-     * currently overriding where it is displayed.
-     */
-    Rect getDisplayedBounds() {
-        return mDisplayedBounds;
-    }
-
-    /**
-     * @return {@code true} if this has overridden displayed bounds.
-     */
-    boolean hasDisplayedBounds() {
-        return !mDisplayedBounds.isEmpty();
-    }
-
-    /**
      * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
      * intersectBounds on a side, then the respective side will not be intersected.
      *
@@ -2190,16 +2032,10 @@
         computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
     }
 
-    /** @see WindowContainer#handlesOrientationChangeFromDescendant */
-    boolean handlesOrientationChangeFromDescendant() {
-        return mTask != null && mTask.getParent() != null
-                && mTask.getParent().handlesOrientationChangeFromDescendant();
-    }
-
     /**
-     * Compute bounds (letterbox or pillarbox) for {@link #WINDOWING_MODE_FULLSCREEN} when the
-     * parent doesn't handle the orientation change and the requested orientation is different from
-     * the parent.
+     * Compute bounds (letterbox or pillarbox) for
+     * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
+     * orientation change and the requested orientation is different from the parent.
      */
     void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
             @NonNull Rect parentBounds, int parentOrientation) {
@@ -2345,7 +2181,7 @@
         info.realActivity = realActivity;
         info.numActivities = mReuseActivitiesReport.numActivities;
         info.lastActiveTime = lastActiveTime;
-        info.taskDescription = new ActivityManager.TaskDescription(mTaskDescription);
+        info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
         info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
         info.resizeMode = mResizeMode;
         info.configuration.setTo(getConfiguration());
@@ -2435,7 +2271,7 @@
                     }
                     pw.println(")");
         }
-        pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
+        pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
         if (!askedCompatMode || !inRecents || !isAvailable) {
             pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
                     pw.print(" inRecents="); pw.print(inRecents);
@@ -2490,6 +2326,7 @@
         return toString();
     }
 
+    @Override
     public void writeToProto(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
@@ -2497,13 +2334,13 @@
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
+        writeToProtoInnerTaskOnly(proto, TASK, logLevel);
         proto.write(ID, mTaskId);
         for (int i = getChildCount() - 1; i >= 0; i--) {
-            ActivityRecord activity = getChildAt(i);
+            final ActivityRecord activity = getChildAt(i);
             activity.writeToProto(proto, ACTIVITIES);
         }
-        proto.write(STACK_ID, mStack.mStackId);
+        proto.write(STACK_ID, getStackId());
         if (mLastNonFullscreenBounds != null) {
             mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
         }
@@ -2579,8 +2416,8 @@
         if (lastDescription != null) {
             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
         }
-        if (mTaskDescription != null) {
-            mTaskDescription.saveToXml(out);
+        if (getTaskDescription() != null) {
+            getTaskDescription().saveToXml(out);
         }
         out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
         out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
@@ -2641,14 +2478,14 @@
 
     static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
             Intent intent, IVoiceInteractionSession voiceSession,
-            IVoiceInteractor voiceInteractor) {
+            IVoiceInteractor voiceInteractor, ActivityStack stack) {
         return getTaskRecordFactory().create(
-                service, taskId, info, intent, voiceSession, voiceInteractor);
+                service, taskId, info, intent, voiceSession, voiceInteractor, stack);
     }
 
     static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-            Intent intent, TaskDescription taskDescription) {
-        return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription);
+            Intent intent, TaskDescription taskDescription, ActivityStack stack) {
+        return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription, stack);
     }
 
     static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
@@ -2665,15 +2502,15 @@
 
         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
                 Intent intent, IVoiceInteractionSession voiceSession,
-                IVoiceInteractor voiceInteractor) {
+                IVoiceInteractor voiceInteractor, ActivityStack stack) {
             return new TaskRecord(service, taskId, info, intent, voiceSession, voiceInteractor,
-                    null /*taskDescription*/);
+                    null /*taskDescription*/, stack);
         }
 
         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                Intent intent, TaskDescription taskDescription) {
+                Intent intent, TaskDescription taskDescription, ActivityStack stack) {
             return new TaskRecord(service, taskId, info, intent, null /*voiceSession*/,
-                    null /*voiceInteractor*/, taskDescription);
+                    null /*voiceInteractor*/, taskDescription, stack);
         }
 
         /**
@@ -2683,20 +2520,20 @@
                 Intent affinityIntent, String affinity, String rootAffinity,
                 ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
                 boolean autoRemoveRecents, boolean askedCompatMode, int userId,
-                int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities,
+                int effectiveUid, String lastDescription,
                 long lastTimeMoved, boolean neverRelinquishIdentity,
                 TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
                 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
                 int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
-                boolean userSetupComplete, int minWidth, int minHeight) {
+                boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
             return new TaskRecord(service, taskId, intent, affinityIntent, affinity,
                     rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
-                    askedCompatMode, userId, effectiveUid, lastDescription, activities,
+                    askedCompatMode, userId, effectiveUid, lastDescription,
                     lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
                     prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
                     resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
                     minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
-                    null /*_voiceInteractor*/);
+                    null /*_voiceInteractor*/, stack);
         }
 
         TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
@@ -2908,15 +2745,15 @@
                     taskId, intent, affinityIntent,
                     affinity, rootAffinity, realActivity, origActivity, rootHasReset,
                     autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
-                    activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription,
+                    lastTimeOnTop, neverRelinquishIdentity, taskDescription,
                     taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
                     callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
-                    userSetupComplete, minWidth, minHeight);
+                    userSetupComplete, minWidth, minHeight, null /*stack*/);
             task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
             task.setBounds(lastNonFullscreenBounds);
 
             for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
-                activities.get(activityNdx).setTask(task);
+                task.addChild(activities.get(activityNdx));
             }
 
             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 56211e2..68b76fb 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -116,7 +116,6 @@
 
     /** ActivityRecords that are exiting, but still on screen for animations. */
     final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>();
-    final ArrayList<ActivityRecord> mTmpActivities = new ArrayList<>();
 
     /** Detach this stack from its display when animation completes. */
     // TODO: maybe tie this to WindowContainer#removeChild some how...
@@ -330,7 +329,7 @@
     }
 
     /** Bounds of the stack with other system factors taken into consideration. */
-    public void getDimBounds(Rect out) {
+    void getDimBounds(Rect out) {
         getBounds(out);
     }
 
@@ -482,11 +481,6 @@
                 dividerSize);
     }
 
-    // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC.
-    void addTask(Task task, int position) {
-        addTask(task, position, task.showForAllUsers(), true /* moveParents */);
-    }
-
     /**
      * Put a Task in this stack. Used for adding only.
      * When task is added to top of the stack, the entire branch of the hierarchy (including stack
@@ -495,22 +489,21 @@
      * @param position Target position to add the task to.
      * @param showForAllUsers Whether to show the task regardless of the current user.
      */
-    void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
-        final TaskStack currentStack = task.mStack;
-        // TODO: We pass stack to task's constructor, but we still need to call this method.
-        // This doesn't make sense, mStack will already be set equal to "this" at this point.
-        if (currentStack != null && currentStack.mStackId != mStackId) {
-            throw new IllegalStateException("Trying to add taskId=" + task.mTaskId
-                    + " to stackId=" + mStackId
-                    + ", but it is already attached to stackId=" + task.mStack.mStackId);
-        }
-
+    void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) {
         // Add child task.
         task.mStack = this;
         addChild(task, null);
 
         // Move child to a proper position, as some restriction for position might apply.
-        positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
+        position = positionChildAt(
+                position, task, moveParents /* includingParents */, showForAllUsers);
+        // TODO(task-merge): Remove cast.
+        mActivityStack.onChildAdded((TaskRecord) task, position);
+    }
+
+    @Override
+    void addChild(Task task, int position) {
+        addChild(task, position, task.showForAllUsers(), false /* includingParents */);
     }
 
     void positionChildAt(Task child, int position) {
@@ -563,13 +556,12 @@
 
     /**
      * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in
-     * {@link TaskStack#addTask(Task, int, boolean showForAllUsers, boolean)}, as it can receive
-     * showForAllUsers param from {@link AppWindowToken} instead of {@link Task#showForAllUsers()}.
+     * {@link TaskStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it can receive
+     * showForAllUsers param from {@link ActivityRecord} instead of {@link Task#showForAllUsers()}.
      */
-    private void positionChildAt(int position, Task child, boolean includingParents,
+    int positionChildAt(int position, Task child, boolean includingParents,
             boolean showForAllUsers) {
-        final int targetPosition = findPositionForTask(child, position, showForAllUsers,
-                false /* addingNew */);
+        final int targetPosition = findPositionForTask(child, position, showForAllUsers);
         super.positionChildAt(targetPosition, child, includingParents);
 
         // Log positioning.
@@ -578,6 +570,14 @@
 
         final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
+
+        return targetPosition;
+    }
+
+    @Override
+    void onChildPositionChanged(WindowContainer child) {
+        // TODO(task-merge): Read comment on updateTaskMovement method.
+        //((TaskRecord) child).updateTaskMovement(true);
     }
 
     void reparent(int displayId, Rect outStackBounds, boolean onTop) {
@@ -597,14 +597,13 @@
 
     // TODO: We should really have users as a window container in the hierarchy so that we don't
     // have to do complicated things like we are doing in this method.
-    private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers,
-            boolean addingNew) {
+    private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers) {
         final boolean canShowTask =
                 showForAllUsers || mWmService.isCurrentProfileLocked(task.mUserId);
 
         final int stackSize = mChildren.size();
         int minPosition = 0;
-        int maxPosition = addingNew ? stackSize : stackSize - 1;
+        int maxPosition = stackSize - 1;
 
         if (canShowTask) {
             minPosition = computeMinPosition(minPosition, stackSize);
@@ -615,8 +614,7 @@
         // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
         if (targetPosition == POSITION_BOTTOM && minPosition == 0) {
             return POSITION_BOTTOM;
-        } else if (targetPosition == POSITION_TOP
-                && maxPosition == (addingNew ? stackSize : stackSize - 1)) {
+        } else if (targetPosition == POSITION_TOP && maxPosition == (stackSize - 1)) {
             return POSITION_TOP;
         }
         // Reset position based on minimum/maximum possible positions.
@@ -669,24 +667,17 @@
      */
     @Override
     void removeChild(Task task) {
+        if (!mChildren.contains(task)) {
+            // Not really in this stack anymore...
+            return;
+        }
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task);
 
         super.removeChild(task);
         task.mStack = null;
 
-        if (mDisplayContent != null) {
-            if (mChildren.isEmpty()) {
-                getParent().positionChildAt(POSITION_BOTTOM, this, false /* includingParents */);
-            }
-            mDisplayContent.setLayoutNeeded();
-        }
-        for (int appNdx = mExitingActivities.size() - 1; appNdx >= 0; --appNdx) {
-            final ActivityRecord activity = mExitingActivities.get(appNdx);
-            if (activity.getTask() == task) {
-                activity.mIsExiting = false;
-                mExitingActivities.remove(appNdx);
-            }
-        }
+        // TODO(task-merge): Remove cast.
+        mActivityStack.onChildRemoved((TaskRecord) task, mDisplayContent);
     }
 
     @Override
@@ -1298,7 +1289,7 @@
         super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
         proto.write(ID, mStackId);
         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
-            mChildren.get(taskNdx).writeToProto(proto, TASKS, logLevel);
+            mChildren.get(taskNdx).writeToProtoInnerTaskOnly(proto, TASKS, logLevel);
         }
         proto.write(FILLS_PARENT, matchParentBounds());
         getRawBounds().writeToProto(proto, BOUNDS);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 7ce2b5e..a393ba6 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -428,7 +428,7 @@
             parent.mTreeWeight += child.mTreeWeight;
             parent = parent.getParent();
         }
-        onChildPositionChanged();
+        onChildPositionChanged(child);
     }
 
     /**
@@ -454,7 +454,7 @@
             parent.mTreeWeight -= child.mTreeWeight;
             parent = parent.getParent();
         }
-        onChildPositionChanged();
+        onChildPositionChanged(child);
     }
 
     /**
@@ -583,7 +583,7 @@
                 if (mChildren.peekLast() != child) {
                     mChildren.remove(child);
                     mChildren.add(child);
-                    onChildPositionChanged();
+                    onChildPositionChanged(child);
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_TOP, this /* child */,
@@ -594,7 +594,7 @@
                 if (mChildren.peekFirst() != child) {
                     mChildren.remove(child);
                     mChildren.addFirst(child);
-                    onChildPositionChanged();
+                    onChildPositionChanged(child);
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
@@ -608,14 +608,14 @@
                 //       doing this adjustment here and remove any adjustments in the callers.
                 mChildren.remove(child);
                 mChildren.add(position, child);
-                onChildPositionChanged();
+                onChildPositionChanged(child);
         }
     }
 
     /**
      * Notify that a child's position has changed. Possible changes are adding or removing a child.
      */
-    void onChildPositionChanged() { }
+    void onChildPositionChanged(WindowContainer child) { }
 
     /**
      * Update override configuration and recalculate full config.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 38d6c9c..2ce37f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -53,8 +53,6 @@
 import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
@@ -136,13 +134,13 @@
 
     @Test
     public void testStackCleanupOnActivityRemoval() {
-        mTask.mTask.removeChild(mActivity);
+        mTask.removeChild(mActivity);
         verify(mStack, times(1)).onActivityRemovedFromStack(any());
     }
 
     @Test
     public void testStackCleanupOnTaskRemoval() {
-        mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING);
+        mStack.removeChild(mTask, null /*reason*/);
         // Stack should be gone on task removal.
         assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId));
     }
@@ -325,7 +323,7 @@
                 : ORIENTATION_PORTRAIT;
         mTask.onRequestedOverrideConfigurationChanged(newConfig);
 
-        doReturn(true).when(mTask.mTask).isDragResizing();
+        doReturn(true).when(mTask).isDragResizing();
 
         mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 
@@ -382,7 +380,7 @@
         }
 
         // Mimic the behavior that display doesn't handle app's requested orientation.
-        final DisplayContent dc = mTask.mTask.getDisplayContent();
+        final DisplayContent dc = mTask.getDisplayContent();
         doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
         doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
 
@@ -1174,7 +1172,7 @@
         // Empty the home stack.
         final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
         for (TaskRecord t : homeStack.getAllTasks()) {
-            homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING);
+            homeStack.removeChild(t, "test");
         }
         mActivity.finishing = true;
         doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
@@ -1200,7 +1198,7 @@
         // Empty the home stack.
         final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
         for (TaskRecord t : homeStack.getAllTasks()) {
-            homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING);
+            homeStack.removeChild(t, "test");
         }
         mActivity.finishing = true;
         spyOn(mStack);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index fcebb81..cc0cc3f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -38,7 +38,6 @@
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
@@ -93,21 +92,6 @@
     }
 
     @Test
-    public void testEmptyTaskCleanupOnRemove() {
-        assertNotNull(mTask.getTask());
-        mStack.removeTask(mTask, "testEmptyTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING);
-        assertNull(mTask.getTask());
-    }
-
-    @Test
-    public void testOccupiedTaskCleanupOnRemove() {
-        final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
-        assertNotNull(mTask.getTask());
-        mStack.removeTask(mTask, "testOccupiedTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING);
-        assertNotNull(mTask.getTask());
-    }
-
-    @Test
     public void testResumedActivity() {
         final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
         assertNull(mStack.getResumedActivity());
@@ -996,27 +980,6 @@
     }
 
     @Test
-    public void testAdjustFocusedStackToHomeWhenNoActivity() {
-        final ActivityStack homeStask = mDefaultDisplay.getHomeStack();
-        TaskRecord homeTask = homeStask.topTask();
-        if (homeTask == null) {
-            // Create home task if there isn't one.
-            homeTask = new TaskBuilder(mSupervisor).setStack(homeStask).build();
-        }
-
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        mStack.moveToFront("testAdjustFocusedStack");
-
-        // Simulate that home activity has not been started or is force-stopped.
-        homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING);
-
-        // Finish the only activity.
-        topActivity.finishIfPossible("testAdjustFocusedStack", false /* oomAdj */);
-        // Although home stack is empty, it should still be the focused stack.
-        assertEquals(homeStask, mDefaultDisplay.getFocusedStack());
-    }
-
-    @Test
     public void testWontFinishHomeStackImmediately() {
         final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ace5d4e..a28bbb6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -715,7 +715,7 @@
         if (startedActivity != null && startedActivity.getTaskRecord() != null) {
             // Remove the activity so it doesn't interfere with with subsequent activity launch
             // tests from this method.
-            startedActivity.getTaskRecord().mTask.removeChild(startedActivity);
+            startedActivity.getTaskRecord().removeChild(startedActivity);
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 78db6c9..1db8f1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -269,7 +269,7 @@
                 // fullscreen value is normally read from resources in ctor, so for testing we need
                 // to set it somewhere else since we can't mock resources.
                 doReturn(true).when(activity).occludesParent();
-                activity.setTask(mTaskRecord);
+                mTaskRecord.addChild(activity);
                 // Make visible by default...
                 activity.setHidden(false);
             }
@@ -376,15 +376,13 @@
 
             final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
                     intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
-                    null /*taskDescription*/);
+                    null /*taskDescription*/, mStack);
             spyOn(task);
             task.mUserId = mUserId;
 
             if (mStack != null) {
                 mStack.moveToFront("test");
-                mStack.addTask(task, true, "creating test task");
-                task.createTask(true, true);
-                spyOn(task.mTask);
+                mStack.addChild(task, true, true);
             }
 
             return task;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 1fb6a56..c5301b8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -165,7 +165,7 @@
         // setup currently defaults to no snapshot.
         setUpOnDisplay(mDisplayContent);
 
-        mTask.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
         assertEquals(1, mDisplayContent.mChangingApps.size());
         assertTrue(mActivity.isInChangeTransition());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 2f0486d..d33dbd1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -48,7 +48,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
 import android.content.res.Configuration;
@@ -63,7 +63,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
 
 /**
  * Tests for the {@link ActivityRecord} class.
@@ -209,9 +208,11 @@
 
     @Test
     public void testSizeCompatBounds() {
+        // TODO(task-merge): Move once Task is merged into TaskRecord
+        final TaskRecord tr = (TaskRecord) mTask;
         // Disable the real configuration resolving because we only simulate partial flow.
         // TODO: Have test use full flow.
-        doNothing().when(mTask.mTaskRecord).computeConfigResourceOverrides(any(), any());
+        doNothing().when(tr).computeConfigResourceOverrides(any(), any());
         final Rect fixedBounds = mActivity.getRequestedOverrideConfiguration().windowConfiguration
                 .getBounds();
         fixedBounds.set(0, 0, 1200, 1600);
@@ -337,11 +338,9 @@
 
         mDisplayContent.getDisplayRotation().setFixedToUserRotation(
                 DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
-
-        mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS);
+        reset(mTask);
         mActivity.reportDescendantOrientationChangeIfNeeded();
-
-        verify(mTask.mTaskRecord).onConfigurationChanged(any(Configuration.class));
+        verify(mTask).onConfigurationChanged(any(Configuration.class));
     }
 
     @Test
@@ -451,6 +450,7 @@
 
     @Test
     public void testTransitionAnimationBounds() {
+        removeGlobalMinSizeRestriction();
         final Rect stackBounds = new Rect(0, 0, 1000, 600);
         final Rect taskBounds = new Rect(100, 400, 600, 800);
         mStack.setBounds(stackBounds);
@@ -458,16 +458,16 @@
 
         // Check that anim bounds for freeform window match task bounds
         mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_NONE));
+        assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_NONE));
 
         // STACK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by
         // bounds animation layer.
         mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM));
+        assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM));
 
         // STACK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later.
         mTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-        assertEquals(stackBounds, mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
+        assertEquals(mStack.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index cc598ff..69091c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -885,7 +885,7 @@
         final int taskId = task.mTaskId;
         mRecentTasks.add(task);
         // Only keep the task in RecentTasks.
-        task.removeWindowContainer();
+        task.removeIfPossible();
         mStack.remove();
 
         // The following APIs should not restore task from recents to the active list.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 839ddb2..ca8f535 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -196,9 +196,6 @@
         doReturn(app).when(mService).getProcessController(eq(recentActivity.processName), anyInt());
         ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
         doNothing().when(lifecycleManager).scheduleTransaction(any());
-        AppWarnings appWarnings = mService.getAppWarningsLocked();
-        spyOn(appWarnings);
-        doNothing().when(appWarnings).onStartActivity(any());
 
         startRecentsActivity();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index aa97de72..63f70c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -36,7 +36,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
 
@@ -272,8 +271,7 @@
         assertTrue(pinnedActivity.isFocusable());
 
         // Without the overridding activity, stack should not be focusable.
-        pinnedStack.removeTask(pinnedActivity.getTaskRecord(), "testFocusability",
-                REMOVE_TASK_MODE_DESTROYING);
+        pinnedStack.removeChild(pinnedActivity.getTaskRecord(), "testFocusability");
         assertFalse(pinnedStack.isFocusable());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index fa1f435..ad1d1af 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -437,6 +437,10 @@
             spyOn(getLockTaskController());
             spyOn(getTaskChangeNotificationController());
             initRootActivityContainerMocks();
+
+            AppWarnings appWarnings = getAppWarningsLocked();
+            spyOn(appWarnings);
+            doNothing().when(appWarnings).onStartActivity(any());
         }
 
         void initRootActivityContainerMocks() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index df55b39..012eb52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -79,8 +79,9 @@
         // This should be the same calculation as the TaskPositioner uses.
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
+        removeGlobalMinSizeRestriction();
 
-        mPositioner = new TaskPositioner(mWm, mock(IActivityTaskManager.class));
+        mPositioner = new TaskPositioner(mWm, mWm.mAtmService);
         mPositioner.register(mDisplayContent);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
@@ -493,10 +494,7 @@
                         + ") " + Log.getStackTraceString(new Throwable()));
             }
         }
-        assertEquals("left", expected.left, actual.left);
-        assertEquals("right", expected.right, actual.right);
-        assertEquals("top", expected.top, actual.top);
-        assertEquals("bottom", expected.bottom, actual.bottom);
+        assertEquals(expected, actual);
     }
 
     @FlakyTest(bugId = 129492888)
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index f8d49ad..d2342f0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -66,7 +66,8 @@
                 any(InputChannel.class))).thenReturn(true);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
-        mWindow.getTask().setResizeable(RESIZE_MODE_RESIZEABLE);
+        // TODO(task-merge): Remove cast.
+        ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_RESIZEABLE);
         mWindow.mInputChannel = new InputChannel();
         mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
@@ -142,7 +143,8 @@
         doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt());
         assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
 
-        mWindow.getTask().setResizeable(RESIZE_MODE_UNRESIZEABLE);
+        // TODO(task-merge): Remove cast.
+        ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_UNRESIZEABLE);
 
         mTarget.handleTapOutsideTask(content, 0, 0);
         // Wait until the looper processes finishTaskPositioning.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index a4e38f1..2cafc96 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -132,7 +132,7 @@
     @Test
     public void testCopyBaseIntentForTaskInfo() {
         final TaskRecord task = createTaskRecord(1);
-        task.mTaskDescription = new ActivityManager.TaskDescription();
+        task.setTaskDescription(new ActivityManager.TaskDescription());
         final TaskInfo info = task.getTaskInfo();
 
         // The intent of info should be a copy so assert that they are different instances.
@@ -348,10 +348,12 @@
         TaskRecord task = stack.getChildAt(0);
         ActivityRecord root = task.getTopActivity();
 
-        final WindowContainer parentWindowContainer = mock(WindowContainer.class);
-        Mockito.doReturn(parentWindowContainer).when(task.mTask).getParent();
-        Mockito.doReturn(true).when(parentWindowContainer)
-                .handlesOrientationChangeFromDescendant();
+        final WindowContainer parentWindowContainer =
+                new WindowContainer(mSystemServicesTestRule.getWindowManagerService());
+        spyOn(parentWindowContainer);
+        parentWindowContainer.setBounds(fullScreenBounds);
+        doReturn(parentWindowContainer).when(task).getParent();
+        doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
 
         // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the
         // bounds because its parent says it will handle it at a later time.
@@ -433,7 +435,7 @@
         info.targetActivity = targetClassName;
 
         final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent,
-                null /* taskDescription */);
+                null /* taskDescription */, null /*stack*/);
         assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
                 task.intent.getComponent().getClassName());
 
@@ -834,8 +836,9 @@
     private TaskRecord createTaskRecord(int taskId) {
         return new TaskRecord(mService, taskId, new Intent(), null, null, null,
                 ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
-                new ArrayList<>(), 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
-                0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/);
+                0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
+                0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
+                null /*stack*/);
     }
 
     private static class TestTaskRecordFactory extends TaskRecordFactory {
@@ -843,16 +846,16 @@
 
         @Override
         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                Intent intent,
-                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+                Intent intent, IVoiceInteractionSession voiceSession,
+                IVoiceInteractor voiceInteractor, ActivityStack stack) {
             mCreated = true;
             return null;
         }
 
         @Override
         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                Intent intent,
-                ActivityManager.TaskDescription taskDescription) {
+                Intent intent, ActivityManager.TaskDescription taskDescription,
+                ActivityStack stack) {
             mCreated = true;
             return null;
         }
@@ -863,14 +866,14 @@
                 ComponentName realActivity,
                 ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents,
                 boolean askedCompatMode, int userId, int effectiveUid, String lastDescription,
-                ArrayList<ActivityRecord> activities, long lastTimeMoved,
+                long lastTimeMoved,
                 boolean neverRelinquishIdentity,
                 ActivityManager.TaskDescription lastTaskDescription,
                 int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
                 int callingUid, String callingPackage, int resizeMode,
                 boolean supportsPictureInPicture,
                 boolean realActivitySuspended, boolean userSetupComplete, int minWidth,
-                int minHeight) {
+                int minHeight, ActivityStack stack) {
             mCreated = true;
             return null;
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 4dfa266..cb2e1e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -92,7 +94,7 @@
 
         boolean gotException = false;
         try {
-            task.reparent(stackController1, 0, false/* moveParents */);
+            task.reparent(stackController1, 0, false/* moveParents */, "testReparent");
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
@@ -100,14 +102,14 @@
 
         gotException = false;
         try {
-            task.reparent(null, 0, false/* moveParents */);
+            task.reparent(null, 0, false/* moveParents */, "testReparent");
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
         assertTrue("Should not be able to reparent to a stack that doesn't exist",
                 gotException);
 
-        task.reparent(stackController2, 0, false/* moveParents */);
+        task.reparent(stackController2, 0, false/* moveParents */, "testReparent");
         assertEquals(stackController2, task.getParent());
         assertEquals(0, task.getParent().mChildren.indexOf(task));
         assertEquals(1, task2.getParent().mChildren.indexOf(task2));
@@ -125,7 +127,7 @@
         final TaskStack stack2 = createTaskStackOnDisplay(dc);
         final Task task2 = createTaskInStack(stack2, 0 /* userId */);
         // Reparent and check state
-        task.reparent(stack2, 0, false /* moveParents */);
+        task.reparent(stack2, 0, false /* moveParents */, "testReparent_BetweenDisplays");
         assertEquals(stack2, task.getParent());
         assertEquals(0, task.getParent().mChildren.indexOf(task));
         assertEquals(1, task2.getParent().mChildren.indexOf(task2));
@@ -138,6 +140,7 @@
         final Task task = createTaskInStack(stack1, 0 /* userId */);
 
         // Check that setting bounds also updates surface position
+        task.setWindowingMode(WINDOWING_MODE_FREEFORM);
         Rect bounds = new Rect(10, 10, 100, 200);
         task.setBounds(bounds);
         assertEquals(new Point(bounds.left, bounds.top), task.getLastSurfacePosition());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 8cd97cb..428d869 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -255,6 +255,7 @@
 
     @Test
     public void testLayoutNonfullscreenTask() {
+        removeGlobalMinSizeRestriction();
         final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
         final int logicalWidth = displayInfo.logicalWidth;
         final int logicalHeight = displayInfo.logicalHeight;
@@ -264,8 +265,8 @@
         WindowState w = createWindow();
         final Task task = w.getTask();
         // Use split-screen because it is non-fullscreen, but also not floating
-        task.mTaskRecord.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-        task.mTaskRecord.setBounds(taskBounds);
+        task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        task.setBounds(taskBounds);
         // The bounds we are requesting might be different from what the system resolved based on
         // other factors.
         final Rect resolvedTaskBounds = task.getBounds();
@@ -303,8 +304,8 @@
         final int insetTop = logicalHeight / 5;
         final int insetRight = insetLeft + (resolvedTaskBounds.right - resolvedTaskBounds.left);
         final int insetBottom = insetTop + (resolvedTaskBounds.bottom - resolvedTaskBounds.top);
-        task.mTaskRecord.setDisplayedBounds(resolvedTaskBounds);
-        task.mTaskRecord.setBounds(insetLeft, insetTop, insetRight, insetBottom);
+        task.setOverrideDisplayedBounds(resolvedTaskBounds);
+        task.setBounds(insetLeft, insetTop, insetRight, insetBottom);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
         assertEquals(resolvedTaskBounds, w.getFrameLw());
@@ -477,7 +478,7 @@
         WindowState w = createWindow();
         final Task task = w.getTask();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
-        task.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        task.setWindowingMode(WINDOWING_MODE_FREEFORM);
 
         DisplayContent dc = mTestDisplayContent;
         dc.mInputMethodTarget = w;
@@ -499,7 +500,7 @@
         // First check that it only gets moved up enough to show window.
         final Rect winRect = new Rect(200, 200, 300, 500);
 
-        task.mTaskRecord.setBounds(winRect);
+        task.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
         w.computeFrameLw();
 
@@ -511,7 +512,7 @@
 
         // Now check that it won't get moved beyond the top and then has appropriate insets
         winRect.bottom = 600;
-        task.mTaskRecord.setBounds(winRect);
+        task.setBounds(winRect);
         w.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
         w.computeFrameLw();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 51daf65..3f32e33 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -42,7 +42,7 @@
                     .setUserId(userId)
                     .setStack(stack.mActivityStack)
                     .build();
-            return task.mTask;
+            return task;
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 780fed9..c3f59eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -384,7 +384,7 @@
     }
 
     /** Sets the default minimum task size to 1 so that tests can use small task sizes */
-    public void removeGlobalMinSizeRestriction() {
+    void removeGlobalMinSizeRestriction() {
         mWm.mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
     }
 }