Added TaskWindowContainerController

For linking TaskRecord in AMS to Task window container in WMS.

Bug: 30060889
Test: bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
Test: bit FrameworksServicesTests:com.android.server.wm.TaskWindowContainerControllerTests
Test: Existing test pass and manual testing.
Change-Id: I16248f3e96e5087ba24198a48a3bd10a12ae76a6
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3ab30f2..5b4b4fe 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -367,6 +367,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
+import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -9527,12 +9528,7 @@
                 Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
                 return;
             }
-            if (task.mResizeMode != resizeableMode) {
-                task.mResizeMode = resizeableMode;
-                mWindowManager.setTaskResizeable(taskId, resizeableMode);
-                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-                mStackSupervisor.resumeFocusedStackTopActivityLocked();
-            }
+            task.setResizeMode(resizeableMode);
         }
     }
 
@@ -9565,13 +9561,12 @@
                 }
                 boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
                 if (stackId != task.getStackId()) {
-                    mStackSupervisor.moveTaskToStackUncheckedLocked(
-                            task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
+                    mStackSupervisor.moveTaskToStackUncheckedLocked(task, stackId, ON_TOP,
+                            !FORCE_FOCUS, "resizeTask", true /* allowStackOnTop */);
                     preserveWindow = false;
                 }
 
-                mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode, preserveWindow,
-                        false /* deferResume */);
+                task.resize(bounds, resizeMode, preserveWindow, false /* deferResume */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -9594,7 +9589,7 @@
                 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.
-                    mWindowManager.getTaskBounds(task.taskId, rect);
+                    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
@@ -9612,6 +9607,44 @@
     }
 
     @Override
+    public void cancelTaskWindowTransition(int taskId) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "cancelTaskWindowTransition()");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
+                        taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+                if (task == null) {
+                    Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
+                    return;
+                }
+                task.cancelWindowTransition();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public void cancelTaskThumbnailTransition(int taskId) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "cancelTaskThumbnailTransition()");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
+                        taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+                if (task == null) {
+                    Slog.w(TAG, "cancelTaskThumbnailTransition: taskId=" + taskId + " not found");
+                    return;
+                }
+                task.cancelThumbnailTransition();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
         if (userId != UserHandle.getCallingUserId()) {
             enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -9949,7 +9982,7 @@
                 // Defer the resume so resume/pausing while moving stacks is dangerous.
                 mStackSupervisor.moveTaskToStackLocked(topTask.taskId, DOCKED_STACK_ID,
                         false /* toTop */, !FORCE_FOCUS, "swapDockedAndFullscreenStack",
-                        ANIMATE, true /* deferResume */);
+                        ANIMATE, true /* deferResume */, true /* allowStackOnTop */);
                 final int size = tasks.size();
                 for (int i = 0; i < size; i++) {
                     final int id = tasks.get(i).taskId;
@@ -9958,7 +9991,8 @@
                     }
                     mStackSupervisor.moveTaskToStackLocked(id,
                             FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */, !FORCE_FOCUS,
-                            "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */);
+                            "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */,
+                            true /* allowStackOnTop */);
                 }
 
                 // Because we deferred the resume, to avoid conflicts with stack switches while
@@ -9999,7 +10033,7 @@
                 mWindowManager.setDockedStackCreateState(createMode, initialBounds);
                 final boolean moved = mStackSupervisor.moveTaskToStackLocked(
                         taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack",
-                        animate, DEFER_RESUME);
+                        animate, DEFER_RESUME, true /* allowStackOnTop */);
                 if (moved) {
                     if (moveHomeStackFront) {
                         mStackSupervisor.moveHomeStackToFront("moveTaskToDockedStack");
@@ -10113,10 +10147,12 @@
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (DEBUG_STACK) Slog.d(TAG_STACK,
-                        "positionTaskInStack: positioning task=" + taskId
-                        + " in stackId=" + stackId + " at position=" + position);
-                mStackSupervisor.positionTaskInStackLocked(taskId, stackId, position);
+                if (DEBUG_STACK) Slog.d(TAG_STACK, "positionTaskInStack: positioning task="
+                        + taskId + " in stackId=" + stackId + " at position=" + position);
+                final ActivityStack stack = mStackSupervisor.getStack(stackId, CREATE_IF_NEEDED,
+                        !ON_TOP);
+
+                stack.positionChildAt(taskId, position);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 0e4ab96..2963ad1 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -41,7 +41,6 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.os.Build.VERSION_CODES.HONEYCOMB;
 import static android.os.Process.SYSTEM_UID;
-import static android.view.Display.DEFAULT_DISPLAY;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
@@ -75,7 +74,6 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
@@ -103,6 +101,7 @@
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 import com.android.server.wm.AppWindowContainerController;
 import com.android.server.wm.AppWindowContainerListener;
+import com.android.server.wm.TaskWindowContainerController;
 
 import java.io.File;
 import java.io.IOException;
@@ -724,6 +723,10 @@
                 null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
     }
 
+    AppWindowContainerController getWindowContainerController() {
+        return mWindowContainerController;
+    }
+
     void createWindowContainer() {
         if (mWindowContainerController != null) {
             throw new IllegalArgumentException("Window container=" + mWindowContainerController
@@ -734,9 +737,10 @@
         inHistory = true;
 
         task.updateOverrideConfigurationFromLaunchBounds();
+        final TaskWindowContainerController taskController = task.getWindowContainerController();
 
-        mWindowContainerController = new AppWindowContainerController(appToken, this, task.taskId,
-                Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
+        mWindowContainerController = new AppWindowContainerController(taskController, appToken,
+                this, Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
                 (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
                 task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
                 appInfo.targetSdkVersion, mRotationAnimationHint,
@@ -749,12 +753,7 @@
 
     void removeWindowContainer() {
         mWindowContainerController.removeContainer(getDisplayId());
-    }
-
-    // TODO: Remove once task record is converted to use controller in which case we can use
-    // positionChildAt()
-    void positionWindowContainerAt(int index) {
-        mWindowContainerController.positionAt(task.taskId, index);
+        mWindowContainerController = null;
     }
 
     private boolean isHomeIntent(Intent intent) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f7c3cea..ab65eb1 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -737,7 +737,7 @@
 
         task = topTask();
         if (task != null) {
-            mWindowManager.moveTaskToTop(task.taskId);
+            task.moveWindowContainerToTop(true /* includingParents */);
         }
     }
 
@@ -756,7 +756,7 @@
             mTaskHistory.remove(task);
             mTaskHistory.add(0, task);
             updateTaskMovement(task, false);
-            mWindowManager.moveTaskToBottom(task.taskId);
+            task.moveWindowContainerToBottom();
         }
     }
 
@@ -2557,10 +2557,16 @@
         position = Math.min(position, maxPosition);
         mTaskHistory.remove(task);
         mTaskHistory.add(position, task);
+        task.positionWindowContainerAt(mStackId, position);
         updateTaskMovement(task, true);
     }
 
     private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity) {
+        insertTaskAtTop(task, newActivity, true /* allowStackOnTop */);
+    }
+
+    private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity,
+            boolean allowStackOnTop) {
         boolean isLastTaskOverHome = false;
         // If the moving task is over home stack, transfer its return type to next task
         if (task.isOverHomeStack()) {
@@ -2619,7 +2625,7 @@
         }
         mTaskHistory.add(taskNdx, task);
         updateTaskMovement(task, true);
-        mWindowManager.moveTaskToTop(task.taskId);
+        task.moveWindowContainerToTop(allowStackOnTop /* includingParents */);
     }
 
     final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
@@ -2863,7 +2869,7 @@
                     targetTask.addActivityAtBottom(p);
                 }
 
-                mWindowManager.moveTaskToBottom(targetTask.taskId);
+                targetTask.moveWindowContainerToBottom();
                 replyChainEnd = -1;
             } else if (forceReset || finishOnTaskLaunch || clearWhenTaskReset) {
                 // If the activity should just be removed -- either
@@ -2999,7 +3005,7 @@
                         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
                                 + " from " + srcPos + " in to resetting task " + task);
                     }
-                    mWindowManager.moveTaskToTop(taskId);
+                    task.moveWindowContainerToTop(true /* includingParents */);
 
                     // Now we've moved it in to place...  but what if this is
                     // a singleTop activity and we have put it on top of another
@@ -4368,7 +4374,7 @@
         }
 
         mWindowManager.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
-        mWindowManager.moveTaskToBottom(taskId);
+        tr.moveWindowContainerToBottom();
 
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
         if (prevIsHome || (task == tr && canGoHome) || (numTasks <= 1 && isOnHomeDisplay())) {
@@ -4800,14 +4806,7 @@
      */
     void removeTask(TaskRecord task, String reason, int mode) {
         if (mode == REMOVE_TASK_MODE_DESTROYING) {
-            mStackSupervisor.removeLockedTaskLocked(task);
-            mWindowManager.removeTask(task.taskId);
-            if (!StackId.persistTaskBounds(mStackId)) {
-                // Reset current bounds for task whose bounds shouldn't be persisted so it uses
-                // default configuration the next time it launches.
-                task.updateOverrideConfiguration(null);
-            }
-            mService.mTaskChangeNotificationController.notifyTaskRemoved(task.taskId);
+            task.removeWindowContainer();
         }
 
         final ActivityRecord r = mResumedActivity;
@@ -4879,11 +4878,7 @@
                 && !isLockscreenShown) {
             task.updateOverrideConfiguration(mBounds);
         }
-        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
-        final boolean showForAllUsers = (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0;
-        mWindowManager.addTask(taskId, mStackId, task.userId, bounds,
-                task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
-                task.isOnTopLauncher(), toTop, showForAllUsers);
+        task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
         return task;
     }
 
@@ -4900,11 +4895,16 @@
     }
 
     void addTask(final TaskRecord task, final boolean toTop, String reason) {
+        addTask(task, toTop, reason, true /* allowStackOnTop */);
+    }
+
+    void addTask(final TaskRecord task, final boolean toTop, String reason,
+            boolean allowStackOnTop) {
         final ActivityStack prevStack = preAddTask(task, reason, toTop);
 
         task.setStack(this);
         if (toTop) {
-            insertTaskAtTop(task, null);
+            insertTaskAtTop(task, null, allowStackOnTop);
         } else {
             mTaskHistory.add(0, task);
             updateTaskMovement(task, false);
@@ -4912,13 +4912,20 @@
         postAddTask(task, prevStack);
     }
 
-    /** @see ActivityManagerService#positionTaskInStack(int, int, int). */
-    void positionTask(final TaskRecord task, int position) {
+    void positionChildAt(int taskId, int index) {
+        final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+        if (task == null) {
+            Slog.w(TAG, "positionTaskInStackLocked: no task for id=" + taskId);
+            return;
+        }
+
+        task.updateOverrideConfigurationForStack(this);
+
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
         final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
         final ActivityStack prevStack = preAddTask(task, "positionTask", !ON_TOP);
         task.setStack(this);
-        insertTaskAtPosition(task, position);
+        insertTaskAtPosition(task, index);
         postAddTask(task, prevStack);
         if (wasResumed) {
             if (mResumedActivity != null) {
@@ -4928,6 +4935,11 @@
             }
             mResumedActivity = topRunningActivity;
         }
+
+        // The task might have already been running and its visibility needs to be synchronized with
+        // the visibility of the stack / windows.
+        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
     }
 
     private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8bd7c90..a0bb192 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -89,6 +89,8 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
 import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
+import static java.lang.Integer.MAX_VALUE;
+import static java.lang.Integer.MIN_VALUE;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -175,7 +177,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.Set;
 
 public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {
@@ -1923,7 +1924,7 @@
                 }
                 if (stackId != currentStack.mStackId) {
                     currentStack = moveTaskToStackUncheckedLocked(task, stackId, ON_TOP,
-                            !FORCE_FOCUS, reason);
+                            !FORCE_FOCUS, reason, true /* allowStackOnTop */);
                     stackId = currentStack.mStackId;
                     // moveTaskToStackUncheckedLocked() should already placed the task on top,
                     // still need moveTaskToFrontLocked() below for any transition settings.
@@ -1936,9 +1937,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.
-                    mWindowManager.resizeTask(task.taskId, task.mBounds,
-                            task.getOverrideConfiguration(), false /* relayout */,
-                            false /* forced */);
+                    task.resizeWindowContainer();
                 }
             }
         }
@@ -2164,8 +2163,10 @@
         continueUpdateBounds(HOME_STACK_ID);
         for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
             final int taskId = mResizingTasksDuringAnimation.valueAt(i);
-            if (anyTaskForIdLocked(taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID) != null) {
-                mWindowManager.setTaskDockedResizing(taskId, false);
+            final TaskRecord task =
+                    anyTaskForIdLocked(taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+            if (task != null) {
+                task.setTaskDockedResizing(false);
             }
         }
         mResizingTasksDuringAnimation.clear();
@@ -2211,7 +2212,7 @@
                 // display because it no longer contains any tasks.
                 mAllowDockedStackResize = false;
             }
-            final ActivityStack fullscreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
+            ActivityStack fullscreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
             final boolean isFullscreenStackVisible = fullscreenStack != null &&
                     fullscreenStack.getStackVisibilityLocked(null) == STACK_VISIBLE;
             final ArrayList<TaskRecord> tasks = stack.getAllTasks();
@@ -2228,15 +2229,18 @@
                     }
                     moveTaskToStackLocked(tasks.get(i).taskId,
                             FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/,
-                            "moveTasksToFullscreenStack", ANIMATE, DEFER_RESUME);
+                            "moveTasksToFullscreenStack - onTop", ANIMATE, DEFER_RESUME,
+                            true /* allowStackOnTop */);
                 }
 
                 ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
                 resumeFocusedStackTopActivityLocked();
             } else {
-                for (int i = size - 1; i >= 0; i--) {
-                    positionTaskInStackLocked(tasks.get(i).taskId,
-                            FULLSCREEN_WORKSPACE_STACK_ID, 0 /* position */);
+                for (int i = 0; i < size; i++) {
+                    moveTaskToStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID,
+                            true /* onTop */, false /* forceFocus */,
+                            "moveTasksToFullscreenStack - NOT_onTop", !ANIMATE, DEFER_RESUME,
+                            false /* allowStackOnTop */);
                 }
             }
         } finally {
@@ -2337,71 +2341,6 @@
         }
     }
 
-    boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow,
-            boolean deferResume) {
-        if (!task.isResizeable()) {
-            Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
-            return true;
-        }
-
-        // If this is a forced resize, let it go through even if the bounds is not changing,
-        // as we might need a relayout due to surface size change (to/from fullscreen).
-        final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
-        if (Objects.equals(task.mBounds, bounds) && !forced) {
-            // Nothing to do here...
-            return true;
-        }
-        bounds = TaskRecord.validateBounds(bounds);
-
-        if (!mWindowManager.isValidTaskId(task.taskId)) {
-            // 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.
-            task.updateOverrideConfiguration(bounds);
-            if (task.getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
-                // re-restore the task so it can have the proper stack association.
-                restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
-            }
-            return true;
-        }
-
-        if (!task.canResizeToBounds(bounds)) {
-            throw new IllegalArgumentException("resizeTaskLocked: Can not resize task=" + task
-                    + " to bounds=" + bounds + " resizeMode=" + task.mResizeMode);
-        }
-
-        // Do not move the task to another stack here.
-        // This method assumes that the task is already placed in the right stack.
-        // we do not mess with that decision and we only do the resize!
-
-        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId);
-
-        final boolean updatedConfig = task.updateOverrideConfiguration(bounds);
-        // This variable holds information whether the configuration didn't change in a significant
-        // way and the activity was kept the way it was. If it's false, it means the activity had
-        // to be relaunched due to configuration change.
-        boolean kept = true;
-        if (updatedConfig) {
-            final ActivityRecord r = task.topRunningActivityLocked();
-            if (r != null) {
-                kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow);
-
-                if (!deferResume) {
-                    // All other activities must be made visible with their correct configuration.
-                    ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
-                    if (!kept) {
-                        resumeFocusedStackTopActivityLocked();
-                    }
-                }
-            }
-        }
-        mWindowManager.resizeTask(task.taskId, task.mBounds, task.getOverrideConfiguration(), kept,
-                forced);
-
-        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
-        return kept;
-    }
-
     ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
         ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
         if (activityDisplay == null) {
@@ -2415,7 +2354,7 @@
     }
 
     /**
-     * Removes the stack associed with the given {@param stackId}.  If the {@param stackId} is the
+     * Removes the stack associated with the given {@param stackId}.  If the {@param stackId} is the
      * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but
      * instead moved back onto the fullscreen stack.
      */
@@ -2437,8 +2376,7 @@
                     final int insertPosition = isFullscreenStackVisible
                             ? Math.max(0, fullscreenStack.getChildCount() - 1)
                             : fullscreenStack.getChildCount();
-                    positionTaskInStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID,
-                            insertPosition);
+                    fullscreenStack.positionChildAt(tasks.get(i).taskId, insertPosition);
                 }
                 ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 resumeFocusedStackTopActivityLocked();
@@ -2568,7 +2506,7 @@
      *                or is not a static stack).
      * @return true if the task has been restored successfully.
      */
-    private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
+    boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
         if (!StackId.isStaticStack(stackId)) {
             // If stack is not static (or stack id is invalid) - use the default one.
             // This means that tasks that were on external displays will be restored on the
@@ -2603,10 +2541,8 @@
         }
 
         stack.addTask(task, false /* toTop */, "restoreRecentTask");
-        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
-        mWindowManager.addTask(task.taskId, stack.mStackId, task.userId, bounds,
-                task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
-                task.isOnTopLauncher(), false /* toTop */, true /* showForAllUsers */);
+        // TODO: move call for creation here and other place into Stack.addTask()
+        task.createWindowContainer(false /* toTop */, true /* showForAllUsers */);
         if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
                 "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -2660,10 +2596,13 @@
      * @param toTop True if the task should be placed at the top of the stack.
      * @param forceFocus if focus should be moved to the new stack
      * @param reason Reason the task is been moved.
+     * @param allowStackOnTop If stack movement should be moved to the top due to the addition of
+     *                        the task to the stack. E.g. Moving the stack to the front because it
+     *                        should be focused because it now contains the focused activity.
      * @return The stack the task was moved to.
      */
-    ActivityStack moveTaskToStackUncheckedLocked(
-            TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
+    ActivityStack moveTaskToStackUncheckedLocked(TaskRecord task, int stackId, boolean toTop,
+            boolean forceFocus, String reason, boolean allowStackOnTop) {
 
         if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) {
             throw new IllegalStateException("moveTaskToStackUncheckedLocked: Device doesn't "
@@ -2694,15 +2633,15 @@
         // if a docked stack is created below which will lead to the stack we are moving from and
         // its resizeable tasks being resized.
         task.mTemporarilyUnresizable = true;
-        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
+        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop && allowStackOnTop);
         task.mTemporarilyUnresizable = false;
-        mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
-        stack.addTask(task, toTop, reason);
+        task.reparentWindowContainer(stack.mStackId, toTop ? MAX_VALUE : MIN_VALUE);
+        stack.addTask(task, toTop, reason, allowStackOnTop);
 
         // 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.
         stack.moveToFrontAndResumeStateIfNeeded(
-                r, forceFocus || wasFocused || wasFront, wasResumed, reason);
+                r, allowStackOnTop && (forceFocus || wasFocused || wasFront), wasResumed, reason);
 
         return stack;
     }
@@ -2710,11 +2649,11 @@
     boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
             String reason, boolean animate) {
         return moveTaskToStackLocked(taskId, stackId, toTop, forceFocus, reason, animate,
-                false /* deferResume */);
+                false /* deferResume */, true /* allowStackOnTop */);
     }
 
     boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
-            String reason, boolean animate, boolean deferResume) {
+            String reason, boolean animate, boolean deferResume, boolean allowStackOnTop) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
             Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
@@ -2754,7 +2693,7 @@
         boolean kept = true;
         try {
             final ActivityStack stack = moveTaskToStackUncheckedLocked(
-                    task, stackId, toTop, forceFocus, reason + " moveTaskToStack");
+                    task, stackId, toTop, forceFocus, reason + " moveTaskToStack", allowStackOnTop);
             stackId = stack.mStackId;
 
             if (!animate) {
@@ -2766,19 +2705,18 @@
 
             // Make sure the task has the appropriate bounds/size for the stack it is in.
             if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
-                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM,
-                        !mightReplaceWindow, deferResume);
+                kept = task.resize(stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
+                        deferResume);
             } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
                 Rect bounds = task.getLaunchBounds();
                 if (bounds == null) {
                     stack.layoutTaskInStack(task, null);
                     bounds = task.mBounds;
                 }
-                kept = resizeTaskLocked(task, bounds, RESIZE_MODE_FORCED, !mightReplaceWindow,
-                        deferResume);
+                kept = task.resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
             } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
-                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM,
-                        !mightReplaceWindow, deferResume);
+                kept = task.resize(stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
+                        deferResume);
             }
         } finally {
             mWindowManager.continueSurfaceLayout();
@@ -2908,28 +2846,6 @@
         return true;
     }
 
-    /** @see ActivityManagerService#positionTaskInStack(int, int, int). */
-    void positionTaskInStackLocked(int taskId, int stackId, int position) {
-        final TaskRecord task = anyTaskForIdLocked(taskId);
-        if (task == null) {
-            Slog.w(TAG, "positionTaskInStackLocked: no task for id=" + taskId);
-            return;
-        }
-        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, !ON_TOP);
-
-        task.updateOverrideConfigurationForStack(stack);
-
-        // TODO: Return final position from WM for AM to use instead of duplicating computations in
-        // ActivityStack#insertTaskAtPosition.
-        mWindowManager.positionTaskInStack(
-                taskId, stackId, position, task.mBounds, task.getOverrideConfiguration());
-        stack.positionTask(task, position);
-        // The task might have already been running and its visibility needs to be synchronized with
-        // the visibility of the stack / windows.
-        stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeFocusedStackTopActivityLocked();
-    }
-
     ActivityRecord findTaskLocked(ActivityRecord r) {
         mTmpFindTaskResult.r = null;
         mTmpFindTaskResult.matchedByRootAffinity = false;
@@ -3352,7 +3268,7 @@
                 stack.switchUserLocked(userId);
                 TaskRecord task = stack.topTask();
                 if (task != null) {
-                    mWindowManager.moveTaskToTop(task.taskId);
+                    task.moveWindowContainerToTop(true /* includingParents */);
                 }
             }
         }
@@ -3813,7 +3729,7 @@
                     : task.getTopActivity() != null ? task.getTopActivity().packageName
                     : "unknown";
             taskBounds[i] = new Rect();
-            mWindowManager.getTaskBounds(task.taskId, taskBounds[i]);
+            task.getWindowContainerBounds(taskBounds[i]);
             taskUserIds[i] = task.userId;
         }
         info.taskIds = taskIds;
@@ -4768,11 +4684,11 @@
     /**
      * Puts a task into resizing mode during the next app transition.
      *
-     * @param taskId the id of the task to put into resizing mode
+     * @param task The task to put into resizing mode
      */
-    private void setResizingDuringAnimation(int taskId) {
-        mResizingTasksDuringAnimation.add(taskId);
-        mWindowManager.setTaskDockedResizing(taskId, true);
+    private void setResizingDuringAnimation(TaskRecord task) {
+        mResizingTasksDuringAnimation.add(task.taskId);
+        task.setTaskDockedResizing(true);
     }
 
     final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
@@ -4837,7 +4753,7 @@
             // the window renders full-screen with the background filling the void. Also only
             // call this at the end to make sure that tasks exists on the window manager side.
             if (launchStackId == DOCKED_STACK_ID) {
-                setResizingDuringAnimation(taskId);
+                setResizingDuringAnimation(task);
             }
 
             mService.mActivityStarter.postStartActivityUncheckedProcessing(task.getTopActivity(),
@@ -4854,7 +4770,7 @@
         int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
                 null, null, 0, 0, bOptions, userId, null, task);
         if (launchStackId == DOCKED_STACK_ID) {
-            setResizingDuringAnimation(task.taskId);
+            setResizingDuringAnimation(task);
         }
         return result;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 007a478..61e3ad5 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1770,8 +1770,8 @@
             mInTask.updateOverrideConfiguration(mLaunchBounds);
             int stackId = mInTask.getLaunchStackId();
             if (stackId != mInTask.getStackId()) {
-                final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
-                        mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+                final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(mInTask,
+                        stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront", true /* allowStackOnTop */);
                 stackId = stack.mStackId;
             }
             if (StackId.resizeStackWithLaunchBounds(stackId)) {
@@ -1824,7 +1824,7 @@
                 mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
                 mIntent, null, null, true, mStartActivity.mActivityType);
         mStartActivity.setTask(task, null);
-        mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
+        mStartActivity.task.moveWindowContainerToTop(true /* includingParents */);
         if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                 "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index a17cf3b..0d8829e 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -39,6 +39,7 @@
 import android.os.Debug;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
@@ -48,6 +49,7 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
 
+import com.android.server.wm.TaskWindowContainerController;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -58,6 +60,7 @@
 import java.util.ArrayList;
 import java.util.Objects;
 
+import static android.app.ActivityManager.RESIZE_MODE_FORCED;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
@@ -80,6 +83,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
@@ -95,6 +99,7 @@
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 
 final class TaskRecord extends ConfigurationContainer {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
@@ -280,6 +285,8 @@
     /** Helper object used for updating override configuration. */
     private Configuration mTmpConfig = new Configuration();
 
+    private TaskWindowContainerController mWindowContainerController;
+
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, int type) {
         mService = service;
@@ -389,6 +396,155 @@
         mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
     }
 
+    TaskWindowContainerController getWindowContainerController() {
+        return mWindowContainerController;
+    }
+
+    void createWindowContainer(boolean onTop, boolean showForAllUsers) {
+        if (mWindowContainerController != null) {
+            throw new IllegalArgumentException("Window container=" + mWindowContainerController
+                    + " already created for task=" + this);
+        }
+
+        final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
+        final Configuration overrideConfig = getOverrideConfiguration();
+        mWindowContainerController = new TaskWindowContainerController(taskId, getStackId(), userId,
+                bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
+                showForAllUsers);
+    }
+
+    void removeWindowContainer() {
+        mService.mStackSupervisor.removeLockedTaskLocked(this);
+        mWindowContainerController.removeContainer();
+        if (!StackId.persistTaskBounds(getStackId())) {
+            // Reset current bounds for task whose bounds shouldn't be persisted so it uses
+            // default configuration the next time it launches.
+            updateOverrideConfiguration(null);
+        }
+        mService.mTaskChangeNotificationController.notifyTaskRemoved(taskId);
+        mWindowContainerController = null;
+    }
+
+    void setResizeMode(int resizeMode) {
+        if (mResizeMode == resizeMode) {
+            return;
+        }
+        mResizeMode = resizeMode;
+        mWindowContainerController.setResizeable(resizeMode);
+        mService.mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+    }
+
+    void setTaskDockedResizing(boolean resizing) {
+        mWindowContainerController.setTaskDockedResizing(resizing);
+    }
+
+    boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
+        if (!isResizeable()) {
+            Slog.w(TAG, "resizeTask: task " + this + " not resizeable.");
+            return true;
+        }
+
+        // If this is a forced resize, let it go through even if the bounds is not changing,
+        // as we might need a relayout due to surface size change (to/from fullscreen).
+        final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
+        if (Objects.equals(mBounds, bounds) && !forced) {
+            // Nothing to do here...
+            return true;
+        }
+        bounds = validateBounds(bounds);
+
+        if (mWindowContainerController == 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.
+            updateOverrideConfiguration(bounds);
+            if (getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
+                // re-restore the task so it can have the proper stack association.
+                mService.mStackSupervisor.restoreRecentTaskLocked(this,
+                        FREEFORM_WORKSPACE_STACK_ID);
+            }
+            return true;
+        }
+
+        if (!canResizeToBounds(bounds)) {
+            throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
+                    + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
+        }
+
+        // Do not move the task to another stack here.
+        // This method assumes that the task is already placed in the right stack.
+        // we do not mess with that decision and we only do the resize!
+
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId);
+
+        final boolean updatedConfig = updateOverrideConfiguration(bounds);
+        // This variable holds information whether the configuration didn't change in a significant
+        // way and the activity was kept the way it was. If it's false, it means the activity had
+        // to be relaunched due to configuration change.
+        boolean kept = true;
+        if (updatedConfig) {
+            final ActivityRecord r = topRunningActivityLocked();
+            if (r != null) {
+                kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow);
+
+                if (!deferResume) {
+                    // All other activities must be made visible with their correct configuration.
+                    mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
+                    if (!kept) {
+                        mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+                    }
+                }
+            }
+        }
+        mWindowContainerController.resize(mBounds, getOverrideConfiguration(), kept, forced);
+
+        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+        return kept;
+    }
+
+    // TODO: Investigate combining with the resize() method above.
+    void resizeWindowContainer() {
+        mWindowContainerController.resize(mBounds, getOverrideConfiguration(), false /* relayout */,
+                false /* forced */);
+    }
+
+    // TODO: Remove once we have a stack controller.
+    void positionWindowContainerAt(int stackId, int index) {
+        mWindowContainerController.positionAt(stackId, index, mBounds, getOverrideConfiguration());
+    }
+
+    // TODO: Replace with moveChildToTop?
+    void moveWindowContainerToTop(boolean includingParents) {
+        if (mWindowContainerController != null) {
+            mWindowContainerController.moveToTop(includingParents);
+        }
+    }
+
+    // TODO: Replace with moveChildToBottom?
+    void moveWindowContainerToBottom() {
+        if (mWindowContainerController != null) {
+            mWindowContainerController.moveToBottom();
+        }
+    }
+
+    void getWindowContainerBounds(Rect bounds) {
+        mWindowContainerController.getBounds(bounds);
+    }
+
+    // TODO: make this part of adding it to the stack?
+    void reparentWindowContainer(int stackId, int position) {
+        mWindowContainerController.reparent(stackId, position);
+    }
+
+    void cancelWindowTransition() {
+        mWindowContainerController.cancelWindowTransition();
+    }
+
+    void cancelThumbnailTransition() {
+        mWindowContainerController.cancelThumbnailTransition();
+    }
+
     void touchActiveTime() {
         lastActiveTime = System.currentTimeMillis();
         if (firstActiveTime == 0) {
@@ -852,7 +1008,7 @@
 
         // Sync. with window manager
         updateOverrideConfigurationFromLaunchBounds();
-        r.positionWindowContainerAt(index);
+        mWindowContainerController.positionChildAt(r.getWindowContainerController(), index);
         r.onOverrideConfigurationSent();
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index cab39b5..7630984 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -31,7 +31,6 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
-import android.os.Binder;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
@@ -169,20 +168,21 @@
         }
     };
 
-    public AppWindowContainerController(IApplicationToken token,
-            AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
-            boolean fullscreen, boolean showForAllUsers, int configChanges,
+    public AppWindowContainerController(TaskWindowContainerController taskController,
+            IApplicationToken token, AppWindowContainerListener listener, int index,
+            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
             boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
             int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
-        this(token, listener, taskId, index, requestedOrientation, fullscreen, showForAllUsers,
+        this(taskController, token, listener, index, requestedOrientation, fullscreen,
+                showForAllUsers,
                 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
                 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
                 WindowManagerService.getInstance());
     }
 
-    public AppWindowContainerController(IApplicationToken token,
-            AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
-            boolean fullscreen, boolean showForAllUsers, int configChanges,
+    public AppWindowContainerController(TaskWindowContainerController taskController,
+            IApplicationToken token, AppWindowContainerListener listener, int index,
+            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
             boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
             int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
             WindowManagerService service) {
@@ -196,11 +196,10 @@
                 return;
             }
 
-            // TODO: Have the controller for the task passed in when task are changed to use
-            // controller.
-            final Task task = mService.mTaskIdToTask.get(taskId);
+            final Task task = taskController.mContainer;
             if (task == null) {
-                throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
+                throw new IllegalArgumentException("AppWindowContainerController: invalid "
+                        + " controller=" + taskController);
             }
 
             atoken = new AppWindowToken(mService, token, voiceInteraction, task.getDisplayContent(),
@@ -208,47 +207,27 @@
                     requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
                     alwaysFocusable, this);
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
-                    + " task=" + taskId + " at " + index);
+                    + " controller=" + taskController + " at " + index);
             task.addChild(atoken, index);
         }
     }
 
     public void removeContainer(int displayId) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(mWindowMap) {
-                final DisplayContent dc = mRoot.getDisplayContent(displayId);
-                if (dc == null) {
-                    Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
-                            + mToken + " from non-existing displayId=" + displayId);
-                    return;
-                }
-                dc.removeAppToken(mToken.asBinder());
-                super.removeContainer();
+        synchronized(mWindowMap) {
+            final DisplayContent dc = mRoot.getDisplayContent(displayId);
+            if (dc == null) {
+                Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
+                        + mToken + " from non-existing displayId=" + displayId);
+                return;
             }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
+            dc.removeAppToken(mToken.asBinder());
+            super.removeContainer();
         }
     }
 
-    // TODO: Move to task window controller when that is created and rename to positionChildAt()
-    public void positionAt(int taskId, int index) {
-        synchronized(mService.mWindowMap) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM,
-                        "Attempted to position of non-existing app token: " + mToken);
-                return;
-            }
-
-            // TODO: Should get the window container from this owner when the task owner stuff is
-            // hooked-up.
-            final Task task = mService.mTaskIdToTask.get(taskId);
-            if (task == null) {
-                throw new IllegalArgumentException("positionChildAt: invalid taskId=" + taskId);
-            }
-            task.addChild(mContainer, index);
-        }
-
+    @Override
+    public void removeContainer() {
+        throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
     }
 
     public Configuration setOrientation(int requestedOrientation, int displayId,
@@ -570,9 +549,7 @@
                         "Attempted to freeze screen with non-existing app token: " + mContainer);
                 return;
             }
-            final long origId = Binder.clearCallingIdentity();
             mContainer.startFreezingScreen();
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -581,11 +558,9 @@
             if (mContainer == null) {
                 return;
             }
-            final long origId = Binder.clearCallingIdentity();
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
                     + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
             mContainer.stopFreezingScreen(true, force);
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -635,4 +610,9 @@
     boolean keyDispatchingTimedOut(String reason) {
         return mListener != null && mListener.keyDispatchingTimedOut(reason);
     }
+
+    @Override
+    public String toString() {
+        return "{AppWindowContainerController token=" + mToken + "}";
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a468598..b1b7542 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -22,6 +22,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
+import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -89,8 +90,8 @@
     private boolean mIsOnTopLauncher;
 
     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
-            Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
-            boolean homeTask) {
+            Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode, boolean homeTask,
+            TaskWindowContainerController controller) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
@@ -98,6 +99,7 @@
         mIsOnTopLauncher = isOnTopLauncher;
         mResizeMode = resizeMode;
         mHomeTask = homeTask;
+        setController(controller);
         setBounds(bounds, overrideConfig);
     }
 
@@ -150,7 +152,7 @@
     @Override
     void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
-        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
+        EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
         mDeferRemoval = false;
 
         // Make sure to remove dim layer user first before removing task its from parent.
@@ -160,19 +162,17 @@
         }
 
         super.removeImmediately();
-        mService.mTaskIdToTask.delete(mTaskId);
     }
 
-    // TODO: Change to use re-parenting in WC.
-    void moveTaskToStack(TaskStack stack, boolean toTop) {
+    void reparent(TaskStack stack, int position) {
         if (stack == mStack) {
             return;
         }
-        if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
+        if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
-        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
+        EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
         getParent().removeChild(this);
-        stack.addTask(this, toTop);
+        stack.addTask(this, position, showForAllUsers(), false /* moveParents */);
     }
 
     /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
@@ -188,12 +188,13 @@
             // and add to top of the target stack. We will move it proper position afterwards.
             if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
                     + " from stack=" + mStack);
-            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
+            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "positionTaskInStack");
             mStack.removeChild(this);
-            stack.addTask(this, true /* toTop */);
+            stack.addTask(this, position);
+        } else {
+            stack.positionChildAt(position, this, true /* includingParents */);
         }
 
-        stack.positionChildAt(position, this, true /* includingParents */);
         resizeLocked(bounds, overrideConfig, false /* force */);
 
         for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -225,7 +226,7 @@
         super.removeChild(token);
 
         if (mChildren.isEmpty()) {
-            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
+            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
             if (mDeferRemoval) {
                 removeIfPossible();
             }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index d7c7cfa..eeea532 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -507,8 +507,8 @@
     }
 
     // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC.
-    void addTask(Task task, boolean toTop) {
-        addTask(task, toTop, task.showForAllUsers());
+    void addTask(Task task, int position) {
+        addTask(task, position, task.showForAllUsers(), true /* moveParents */);
     }
 
     /**
@@ -516,10 +516,10 @@
      * When task is added to top of the stack, the entire branch of the hierarchy (including stack
      * and display) will be brought to top.
      * @param task The task to add.
-     * @param toTop Whether to add it to the top or bottom.
+     * @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, boolean toTop, boolean showForAllUsers) {
+    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.
@@ -529,14 +529,12 @@
                     + ", but it is already attached to stackId=" + task.mStack.mStackId);
         }
 
-        final int targetPosition = toTop ? mChildren.size() : 0;
-
         // Add child task.
         task.mStack = this;
-        addChild(task, targetPosition);
+        addChild(task, null);
 
         // Move child to a proper position, as some restriction for position might apply.
-        positionChildAt(targetPosition, task, true /* includingParents */, showForAllUsers);
+        positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
     }
 
     @Override
@@ -546,7 +544,7 @@
 
     /**
      * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in
-     * {@link TaskStack#addTask(Task, boolean, boolean showForAllUsers)}, as it can receive
+     * {@link TaskStack#addTask(Task, int, boolean showForAllUsers, boolean)}, as it can receive
      * showForAllUsers param from {@link AppWindowToken} instead of {@link Task#showForAllUsers()}.
      */
     private void positionChildAt(int position, Task child, boolean includingParents,
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
new file mode 100644
index 0000000..9c303f8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.util.EventLog;
+import android.util.Slog;
+
+import static com.android.server.EventLogTags.WM_TASK_CREATED;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+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;
+
+/**
+ * Controller for the task container. This is created by activity manager to link task records to
+ * the task container they use in window manager.
+ *
+ * Test class: {@link TaskWindowContainerControllerTests}
+ */
+public class TaskWindowContainerController
+        extends WindowContainerController<Task, WindowContainerListener> {
+
+    private final int mTaskId;
+
+    public TaskWindowContainerController(int taskId, int stackId, int userId, Rect bounds,
+            Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
+            boolean toTop, boolean showForAllUsers) {
+        super(null, WindowManagerService.getInstance());
+        mTaskId = taskId;
+
+        synchronized(mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG_WM, "TaskWindowContainerController: taskId=" + taskId
+                    + " stackId=" + stackId + " bounds=" + bounds);
+
+            // TODO: Pass controller for the stack to get the container object when stack is
+            // switched to use controller.
+            final TaskStack stack = mService.mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("TaskWindowContainerController: invalid stackId="
+                        + stackId);
+            }
+            EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
+            final Task task = new Task(taskId, stack, userId, mService, bounds, overrideConfig,
+                    isOnTopLauncher, resizeMode, homeTask, this);
+            final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
+            stack.addTask(task, position, showForAllUsers, true /* moveParents */);
+        }
+    }
+
+    @Override
+    public void removeContainer() {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId);
+                return;
+            }
+            mContainer.removeIfPossible();
+            super.removeContainer();
+        }
+    }
+
+    public void positionChildAt(AppWindowContainerController childController, int index) {
+        synchronized(mService.mWindowMap) {
+            final AppWindowToken aToken = childController.mContainer;
+            if (aToken == null) {
+                Slog.w(TAG_WM,
+                        "Attempted to position of non-existing app : " + childController);
+                return;
+            }
+
+            final Task task = mContainer;
+            if (task == null) {
+                throw new IllegalArgumentException("positionChildAt: invalid task=" + this);
+            }
+            task.addChild(aToken, index);
+        }
+    }
+
+    public void reparent(int stackId, int position) {
+        synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId
+                    + " to stackId=" + stackId + " at " + position);
+            if (mContainer == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "reparent: could not find taskId=" + mTaskId);
+                return;
+            }
+            final TaskStack stack = mService.mStackIdToStack.get(stackId);
+            if (stack == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "reparent: could not find stackId=" + stackId);
+                return;
+            }
+            mContainer.reparent(stack, position);
+            final DisplayContent displayContent = stack.getDisplayContent();
+            displayContent.setLayoutNeeded();
+            mService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+    }
+
+    public void setResizeable(int resizeMode) {
+        synchronized (mWindowMap) {
+            if (mContainer != null) {
+                mContainer.setResizeable(resizeMode);
+            }
+        }
+    }
+
+    public void resize(Rect bounds, Configuration overrideConfig, boolean relayout,
+            boolean forced) {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                throw new IllegalArgumentException("resizeTask: taskId " + mTaskId + " not found.");
+            }
+
+            if (mContainer.resizeLocked(bounds, overrideConfig, forced) && relayout) {
+                mContainer.getDisplayContent().setLayoutNeeded();
+                mService.mWindowPlacerLocked.performSurfacePlacement();
+            }
+        }
+    }
+
+    // TODO: Move to positionChildAt() in stack controller once we have a stack controller.
+    public void positionAt(int stackId, int index, Rect bounds, Configuration overrideConfig) {
+        synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning taskId=" + mTaskId
+                    + " in stackId=" + stackId + " at " + index);
+            if (mContainer == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "positionTaskInStack: could not find taskId=" + mTaskId);
+                return;
+            }
+            final TaskStack stack = mService.mStackIdToStack.get(stackId);
+            if (stack == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "positionTaskInStack: could not find stackId=" + stackId);
+                return;
+            }
+            mContainer.positionTaskInStack(stack, index, bounds, overrideConfig);
+            final DisplayContent displayContent = stack.getDisplayContent();
+            displayContent.setLayoutNeeded();
+            mService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+    }
+
+    // TODO: Replace with moveChildToTop in stack controller?
+    public void moveToTop(boolean includingParents) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.e(TAG_WM, "moveToTop: taskId=" + mTaskId + " not found");
+                return;
+            }
+            final TaskStack stack = mContainer.mStack;
+            stack.positionChildAt(POSITION_TOP, mContainer, includingParents);
+
+            if (mService.mAppTransition.isTransitionSet()) {
+                mContainer.setSendingToBottom(false);
+            }
+            stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+        }
+    }
+
+    // TODO: Replace with moveChildToBottom in stack controller?
+    public void moveToBottom() {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.e(TAG_WM, "moveTaskToBottom: taskId=" + mTaskId + " not found");
+                return;
+            }
+            final TaskStack stack = mContainer.mStack;
+            stack.positionChildAt(POSITION_BOTTOM, mContainer, false /* includingParents */);
+            if (mService.mAppTransition.isTransitionSet()) {
+                mContainer.setSendingToBottom(true);
+            }
+            stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+        }
+    }
+
+    public void getBounds(Rect bounds) {
+        synchronized (mWindowMap) {
+            if (mContainer != null) {
+                mContainer.getBounds(bounds);
+                return;
+            }
+            bounds.setEmpty();
+        }
+    }
+
+    /**
+     * Puts this task into docked drag resizing mode. See {@link DragResizeMode}.
+     *
+     * @param resizing Whether to put the task into drag resize mode.
+     */
+    public void setTaskDockedResizing(boolean resizing) {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found.");
+                return;
+            }
+            mContainer.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+        }
+    }
+
+    public void cancelWindowTransition() {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found.");
+                return;
+            }
+            mContainer.cancelTaskWindowTransition();
+        }
+    }
+
+    public void cancelThumbnailTransition() {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "cancelThumbnailTransition: taskId " + mTaskId + " not found.");
+                return;
+            }
+            mContainer.cancelTaskThumbnailTransition();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "{TaskWindowContainerController taskId=" + mTaskId + "}";
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0e6ecde..fd7ea6d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -235,7 +235,7 @@
     @CallSuper
     void positionChildAt(int position, E child, boolean includingParents) {
         if ((position < 0 && position != POSITION_BOTTOM)
-                || (position >= mChildren.size() && position != POSITION_TOP)) {
+                || (position > mChildren.size() && position != POSITION_TOP)) {
             throw new IllegalArgumentException("positionAt: invalid position=" + position
                     + ", children number=" + mChildren.size());
         }
@@ -248,7 +248,7 @@
 
         switch (position) {
             case POSITION_TOP:
-                if (mChildren.getLast() != child) {
+                if (mChildren.peekLast() != child) {
                     mChildren.remove(child);
                     mChildren.addLast(child);
                 }
@@ -258,7 +258,7 @@
                 }
                 break;
             case POSITION_BOTTOM:
-                if (mChildren.getFirst() != child) {
+                if (mChildren.peekFirst() != child) {
                     mChildren.remove(child);
                     mChildren.addFirst(child);
                 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4e25935..048affb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -707,8 +707,6 @@
 
     private final BoundsAnimationController mBoundsAnimationController;
 
-    SparseArray<Task> mTaskIdToTask = new SparseArray<>();
-
     /** All of the TaskStacks in the window manager, unordered. For an ordered list call
      * DisplayContent.getStacks(). */
     // TODO: Don't believe this is needed with the WindowContainer model.
@@ -912,7 +910,6 @@
     }
 
     private static WindowManagerService sInstance;
-
     static WindowManagerService getInstance() {
         return sInstance;
     }
@@ -2441,35 +2438,6 @@
         }
     }
 
-    public void addTask(int taskId, int stackId, int userId, Rect bounds,
-            Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
-            boolean toTop, boolean showForAllUsers) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "addTask()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                throw new IllegalArgumentException(
-                        "addTask: Attempt to add already existing task=" + task);
-            }
-
-            if (DEBUG_STACK) Slog.i(TAG_WM, "createTaskLocked: taskId=" + taskId
-                    + " stackId=" + stackId + " bounds=" + bounds);
-
-            final TaskStack stack = mStackIdToStack.get(stackId);
-            if (stack == null) {
-                throw new IllegalArgumentException("addTask: invalid stackId=" + stackId);
-            }
-            EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
-            task = new Task(taskId, stack, userId, this, bounds, overrideConfig, isOnTopLauncher,
-                    resizeMode, homeTask);
-            mTaskIdToTask.put(taskId, task);
-            stack.addTask(task, toTop, showForAllUsers);
-        }
-    }
-
     @Override
     public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
             IBinder freezeThisOneIfNeeded, int displayId) {
@@ -2851,50 +2819,6 @@
         }
     }
 
-    public void moveTaskToTop(int taskId) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(mWindowMap) {
-                final Task task = mTaskIdToTask.get(taskId);
-                if (task == null) {
-                    // Normal behavior, addAppToken will be called next and task will be created.
-                    return;
-                }
-                task.mStack.positionChildAt(POSITION_TOP, task, true /* includingParents */);
-
-                if (mAppTransition.isTransitionSet()) {
-                    task.setSendingToBottom(false);
-                }
-                final DisplayContent displayContent = task.getDisplayContent();
-                displayContent.layoutAndAssignWindowLayersIfNeeded();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    public void moveTaskToBottom(int taskId) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(mWindowMap) {
-                final Task task = mTaskIdToTask.get(taskId);
-                if (task == null) {
-                    Slog.e(TAG_WM, "moveTaskToBottom: taskId=" + taskId
-                            + " not found in mTaskIdToTask");
-                    return;
-                }
-                final TaskStack stack = task.mStack;
-                stack.positionChildAt(POSITION_BOTTOM, task, false /* includingParents */);
-                if (mAppTransition.isTransitionSet()) {
-                    task.setSendingToBottom(true);
-                }
-                stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
     boolean isStackVisibleLocked(int stackId) {
         final TaskStack stack = mStackIdToStack.get(stackId);
         return (stack != null && stack.isVisible());
@@ -3064,58 +2988,6 @@
         }
     }
 
-    public void removeTask(int taskId) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + taskId);
-                return;
-            }
-            task.removeIfPossible();
-        }
-    }
-
-    @Override
-    public void cancelTaskWindowTransition(int taskId) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                task.cancelTaskWindowTransition();
-            }
-        }
-    }
-
-    @Override
-    public void cancelTaskThumbnailTransition(int taskId) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                task.cancelTaskThumbnailTransition();
-            }
-        }
-    }
-
-    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
-        synchronized (mWindowMap) {
-            if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: moving taskId=" + taskId
-                    + " to stackId=" + stackId + " at " + (toTop ? "top" : "bottom"));
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: could not find taskId=" + taskId);
-                return;
-            }
-            TaskStack stack = mStackIdToStack.get(stackId);
-            if (stack == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: could not find stackId=" + stackId);
-                return;
-            }
-            task.moveTaskToStack(stack, toTop);
-            final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.setLayoutNeeded();
-            mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
     public void getStackDockedModeBounds(int stackId, Rect bounds, boolean ignoreVisibility) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
@@ -3191,69 +3063,6 @@
         }
     }
 
-    /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
-    public void positionTaskInStack(int taskId, int stackId, int position, Rect bounds,
-            Configuration overrideConfig) {
-        synchronized (mWindowMap) {
-            if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskInStack: positioning taskId=" + taskId
-                    + " in stackId=" + stackId + " at " + position);
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM,
-                        "positionTaskInStack: could not find taskId=" + taskId);
-                return;
-            }
-            TaskStack stack = mStackIdToStack.get(stackId);
-            if (stack == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM,
-                        "positionTaskInStack: could not find stackId=" + stackId);
-                return;
-            }
-            task.positionTaskInStack(stack, position, bounds, overrideConfig);
-            final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.setLayoutNeeded();
-            mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
-    /**
-     * Re-sizes the specified task and its containing windows.
-     * Returns a {@link Configuration} object that contains configurations settings
-     * that should be overridden due to the operation.
-     */
-    public void resizeTask(int taskId, Rect bounds, Configuration overrideConfig,
-            boolean relayout, boolean forced) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                throw new IllegalArgumentException("resizeTask: taskId " + taskId
-                        + " not found.");
-            }
-
-            if (task.resizeLocked(bounds, overrideConfig, forced) && relayout) {
-                task.getDisplayContent().setLayoutNeeded();
-                mWindowPlacerLocked.performSurfacePlacement();
-            }
-        }
-    }
-
-    /**
-     * Puts a specific task into docked drag resizing mode. See {@link DragResizeMode}.
-     *
-     * @param taskId The id of the task to put into drag resize mode.
-     * @param resizing Whether to put the task into drag resize mode.
-     */
-    public void setTaskDockedResizing(int taskId, boolean resizing) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                Slog.w(TAG, "setTaskDockedResizing: taskId " + taskId + " not found.");
-                return;
-            }
-            task.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
-        }
-    }
-
     /**
      * Starts deferring layout passes. Useful when doing multiple changes but to optimize
      * performance, only one layout pass should be done. This can be called multiple times, and
@@ -3274,24 +3083,6 @@
         }
     }
 
-    public void getTaskBounds(int taskId, Rect bounds) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                task.getBounds(bounds);
-                return;
-            }
-            bounds.setEmpty();
-        }
-    }
-
-    /** Return true if the input task id represents a valid window manager task. */
-    public boolean isValidTaskId(int taskId) {
-        synchronized (mWindowMap) {
-            return mTaskIdToTask.get(taskId) != null;
-        }
-    }
-
     /**
      * @return true if the activity contains windows that have
      *         {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set
@@ -7827,15 +7618,6 @@
         }
     }
 
-    public void setTaskResizeable(int taskId, int resizeMode) {
-        synchronized (mWindowMap) {
-            final Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                task.setResizeable(resizeMode);
-            }
-        }
-    }
-
     public void setForceResizableTasks(boolean forceResizableTasks) {
         synchronized (mWindowMap) {
             mForceResizableTasks = forceResizableTasks;