Merge "Move Configuration creation from Window Manager to Activity Manager."
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f86adfe..33c51ff 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -97,21 +97,21 @@
      * @param launchTaskBehind True if the token is been launched from behind.
      * @param taskBounds Bounds to use when creating a new Task with the input task Id if
      *                   the task doesn't exist yet.
-     * @return The configuration of the task if it was newly created. null otherwise.
+     * @param configuration Configuration that is being used with this task.
      */
-    Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+    void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            in Rect taskBounds);
+            in Rect taskBounds, in Configuration configuration);
     /**
      *
      * @param token The token we are adding to the input task Id.
      * @param taskId The Id of the task we are adding the token to.
      * @param taskBounds Bounds to use when creating a new Task with the input task Id if
      *                   the task doesn't exist yet.
-     * @return The configuration of the task if it was newly created. null otherwise.
+     * @param config Configuration that is being used with this task.
      */
-    Configuration setAppTask(IBinder token, int taskId, in Rect taskBounds);
+    void setAppTask(IBinder token, int taskId, in Rect taskBounds, in Configuration config);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f50df3a..37ddd4d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3975,8 +3975,7 @@
      * for whatever reason.  Ensures the HistoryRecord is updated with the
      * correct configuration and all other bookkeeping is handled.
      */
-    final boolean ensureActivityConfigurationLocked(ActivityRecord r,
-            int globalChanges) {
+    final boolean ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges) {
         if (mConfigWillChange) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                     "Skipping config check (will change): " + r);
@@ -4589,25 +4588,19 @@
 
     void addConfigOverride(ActivityRecord r, TaskRecord task) {
         final Rect bounds = task.getLaunchBounds();
-        final Configuration config =
-                mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
-                        r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                        (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
-                        r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
-                        bounds);
-        if (config != null) {
-            task.updateOverrideConfiguration(config, bounds);
-        }
+        final Configuration config = task.updateOverrideConfiguration(mStackId, bounds);
+        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
+                r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
+                bounds, config);
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
     private void setAppTask(ActivityRecord r, TaskRecord task) {
         final Rect bounds = task.getLaunchBounds();
-        final Configuration config =
-                mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds());
-        if (config != null) {
-            task.updateOverrideConfiguration(config, bounds);
-        }
+        final Configuration config = task.updateOverrideConfiguration(mStackId, bounds);
+        mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds(), config);
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c86056b..33e0ef8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -97,7 +97,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
-import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -334,6 +333,9 @@
     // temp. rect used during resize calculation so we don't need to create a new object each time.
     private final Rect tempRect = new Rect();
 
+    private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
+    private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -2917,19 +2919,19 @@
         ActivityRecord r = stack.topRunningActivityLocked(null);
         final boolean resizeTasks = r != null && r.task.mResizeable;
 
-        final IntArray changedTaskIds = new IntArray(stack.numTasks());
-        final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
-        stack.mFullscreen = mWindowManager.resizeStack(
-                stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs);
-        for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
-            final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
-            if (task == null) {
-                Slog.wtf(TAG, "Task in WindowManager, but not in ActivityManager???");
-                continue;
+        mTmpBounds.clear();
+        mTmpConfigs.clear();
+        if (resizeTasks) {
+            ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            for (int i = tasks.size() - 1; i >= 0; i--) {
+                TaskRecord task = tasks.get(i);
+                task.updateOverrideConfiguration(stackId, bounds);
+                mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+                mTmpBounds.put(task.taskId, task.mBounds);
             }
-            task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
         }
-
+        stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, resizeTasks, mTmpConfigs,
+                mTmpBounds);
         if (stack.mStackId == DOCKED_STACK_ID) {
             // Dock stack funness...Yay!
             if (stack.mFullscreen) {
@@ -3024,25 +3026,27 @@
             stackId = FREEFORM_WORKSPACE_STACK_ID;
         }
         if (stackId != task.stack.mStackId) {
-            final String reason = "resizeTask";
-            final ActivityStack stack =
-                    moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
+            moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
         }
 
-        final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
-        if (task.updateOverrideConfiguration(overrideConfig, bounds)) {
+        final Configuration overrideConfig =  task.updateOverrideConfiguration(stackId, bounds);
+        // This variable holds information whether the configuration didn't change in a signficant
+        // 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 (overrideConfig != null) {
             ActivityRecord r = task.topRunningActivityLocked(null);
             if (r != null) {
                 final ActivityStack stack = task.stack;
-                final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
-                // And we need to make sure at this point that all other activities
-                // are made visible with the correct configuration.
+                kept = stack.ensureActivityConfigurationLocked(r, 0);
+                // All other activities must be made visible with their correct configuration.
                 ensureActivitiesVisibleLocked(r, 0);
-                if (!updated) {
+                if (!kept) {
                     resumeTopActivitiesLocked(stack, null, null);
                 }
             }
         }
+        mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept);
     }
 
     ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 5c4fd13..735c06f 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -234,7 +235,7 @@
                 break;
             }
         }
-        task.setInitialBounds(proposal);
+        task.updateOverrideConfiguration(FREEFORM_WORKSPACE_STACK_ID, proposal);
     }
 
     private boolean shiftedToFar(Rect start, int shiftPolicy) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9cbaec5..12c7b86 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
@@ -52,6 +53,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
+import android.util.DisplayMetrics;
 import android.util.Slog;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
@@ -63,6 +65,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Objects;
 
 final class TaskRecord {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
@@ -106,6 +109,13 @@
 
     static final int INVALID_TASK_ID = -1;
 
+    // The height/width divide used when fitting a task within a bounds with method
+    // {@link #fitWithinBounds}.
+    // We always want the task to to be visible in the bounds without affecting its size when
+    // fitting. To make sure this is the case, we don't adjust the task left or top side pass
+    // the input bounds right or bottom side minus the width or height divided by this value.
+    private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
+
     final int taskId;       // 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.
@@ -218,6 +228,8 @@
 
     Configuration mOverrideConfig = Configuration.EMPTY;
 
+    private Rect mTmpRect = new Rect();
+
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
         mService = service;
@@ -271,8 +283,7 @@
             long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
             boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
             int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
-            int callingUid, String callingPackage, boolean resizeable, boolean privileged,
-            Rect bounds) {
+            int callingUid, String callingPackage, boolean resizeable, boolean privileged) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -309,7 +320,6 @@
         mCallingPackage = callingPackage;
         mResizeable = resizeable;
         mPrivileged = privileged;
-        mBounds = mLastNonFullscreenBounds = bounds;
     }
 
     void touchActiveTime() {
@@ -1163,7 +1173,8 @@
                 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
                 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
-                callingUid, callingPackage, resizeable, privileged, bounds);
+                callingUid, callingPackage, resizeable, privileged);
+        task.updateOverrideConfiguration(INVALID_STACK_ID, bounds);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             activities.get(activityNdx).task = task;
@@ -1173,25 +1184,51 @@
         return task;
     }
 
-    boolean updateOverrideConfiguration(Configuration newConfig, Rect bounds) {
+    /**
+     * Update task's override configuration based on the bounds.
+     * @return Update configuration or null if there is no change.
+     */
+    Configuration updateOverrideConfiguration(int stackId, Rect bounds) {
+        if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
+            // For freeform stack we don't adjust the size of the tasks to match that of the
+            // stack, but we do try to make sure the tasks are still contained with the
+            // bounds of the stack.
+            bounds = fitWithinBounds(bounds);
+        }
+        if (Objects.equals(mBounds, bounds)) {
+            return null;
+        }
         Configuration oldConfig = mOverrideConfig;
-        mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
-        // We override the configuration only when the task's dimensions are different from the
-        // display. In this manner, we know that if the override configuration is empty, the task
-        // is necessarily fullscreen.
-        mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
+
+        mFullscreen = bounds == null;
         if (mFullscreen) {
             if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) {
                 mLastNonFullscreenBounds = mBounds;
             }
             mBounds = null;
+            mOverrideConfig = Configuration.EMPTY;
         } else {
             mBounds = new Rect(bounds);
             if (stack.mStackId != DOCKED_STACK_ID) {
                 mLastNonFullscreenBounds = mBounds;
             }
+
+            final Configuration serviceConfig = mService.mConfiguration;
+            mOverrideConfig = new Configuration(serviceConfig);
+            // TODO(multidisplay): Update Dp to that of display stack is on.
+            final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+            mOverrideConfig.screenWidthDp =
+                    Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
+            mOverrideConfig.screenHeightDp =
+                    Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
+            mOverrideConfig.smallestScreenWidthDp =
+                    Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+            mOverrideConfig.orientation =
+                    (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
+                            ? Configuration.ORIENTATION_PORTRAIT
+                            : Configuration.ORIENTATION_LANDSCAPE;
         }
-        return !mOverrideConfig.equals(oldConfig);
+        return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
     }
 
     /** Returns the stack that should be used to launch this task. */
@@ -1225,12 +1262,39 @@
         return mLastNonFullscreenBounds;
     }
 
-    void setInitialBounds(Rect rect) {
-        if (mBounds == null) {
-            mBounds = new Rect();
+    /** Fits the tasks within the input bounds adjusting the task bounds as needed.
+     *  @param bounds Bounds to fit the task within. Nothing is done if null.
+     *  @return Returns final configuration after updating with the adjusted bounds.
+     *  */
+    Rect fitWithinBounds(Rect bounds) {
+        if (bounds == null || mBounds == null || bounds.contains(mBounds)) {
+            return bounds;
         }
-        mBounds.set(rect);
-        mLastNonFullscreenBounds = mBounds;
+        mTmpRect.set(mBounds);
+
+        if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
+            final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int horizontalDiff = bounds.left - mBounds.left;
+            if ((horizontalDiff < 0 && mBounds.left >= maxRight)
+                    || (mBounds.left + horizontalDiff >= maxRight)) {
+                horizontalDiff = maxRight - mBounds.left;
+            }
+            mTmpRect.left += horizontalDiff;
+            mTmpRect.right += horizontalDiff;
+        }
+
+        if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
+            final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int verticalDiff = bounds.top - mBounds.top;
+            if ((verticalDiff < 0 && mBounds.top >= maxBottom)
+                    || (mBounds.top + verticalDiff >= maxBottom)) {
+                verticalDiff = maxBottom - mBounds.top;
+            }
+            mTmpRect.top += verticalDiff;
+            mTmpRect.bottom += verticalDiff;
+        }
+
+        return mTmpRect;
     }
 
     void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 554af28..666d902 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -23,7 +23,6 @@
 
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -41,13 +40,6 @@
      * when no window animation is driving it. */
     private static final int DEFAULT_DIM_DURATION = 200;
 
-    // The amount we divide the height/width of the bounds we are trying to fit the task within
-    // when using the method {@link #fitWithinBounds}.
-    // We always want the task to to be visible in the bounds without affecting its size when
-    // fitting. To make sure this is the case, we don't adjust the task left or top side pass
-    // the input bounds right or bottom side minus the width or height divided by this value.
-    private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
-
     TaskStack mStack;
     final AppTokenList mAppTokens = new AppTokenList();
     final int mTaskId;
@@ -84,13 +76,13 @@
     // of creating a new object per fullscreen task on a display.
     private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();
 
-    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds) {
+    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+            Configuration config) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mService = service;
-        mOverrideConfig = Configuration.EMPTY;
-        setBounds(bounds);
+        setBounds(bounds, config);
     }
 
     DisplayContent getDisplayContent() {
@@ -172,43 +164,18 @@
         }
     }
 
-    /** Fits the tasks within the input bounds adjusting the task bounds as needed.
-     *  @param bounds Bounds to fit the task within. Nothing is done if null.
-     *  @return Returns true if the task bounds was adjusted in any way.
-     *  */
-    boolean fitWithinBounds(Rect bounds) {
-        if (bounds == null || bounds.contains(mBounds)) {
-            return false;
-        }
-        mTmpRect2.set(mBounds);
-
-        if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
-            final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int horizontalDiff = bounds.left - mBounds.left;
-            if ((horizontalDiff < 0 && mBounds.left >= maxRight)
-                    || (mBounds.left + horizontalDiff >= maxRight)) {
-                horizontalDiff = maxRight - mBounds.left;
-            }
-            mTmpRect2.left += horizontalDiff;
-            mTmpRect2.right += horizontalDiff;
-        }
-
-        if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
-            final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int verticalDiff = bounds.top - mBounds.top;
-            if ((verticalDiff < 0 && mBounds.top >= maxBottom)
-                    || (mBounds.top + verticalDiff >= maxBottom)) {
-                verticalDiff = maxBottom - mBounds.top;
-            }
-            mTmpRect2.top += verticalDiff;
-            mTmpRect2.bottom += verticalDiff;
-        }
-
-        return setBounds(mTmpRect2);
-    }
-
     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
-    boolean setBounds(Rect bounds) {
+    boolean setBounds(Rect bounds, Configuration config) {
+        if (config == null) {
+            config = Configuration.EMPTY;
+        }
+        if (bounds == null && !Configuration.EMPTY.equals(config)) {
+            throw new IllegalArgumentException("null bounds but non empty configuration: "
+                    + config);
+        }
+        if (bounds != null && Configuration.EMPTY.equals(config)) {
+            throw new IllegalArgumentException("non null bounds, but empty configuration");
+        }
         boolean oldFullscreen = mFullscreen;
         int rotation = Surface.ROTATION_0;
         final DisplayContent displayContent = mStack.getDisplayContent();
@@ -241,7 +208,7 @@
         mBounds.set(bounds);
         mRotation = rotation;
         updateDimLayer();
-        updateOverrideConfiguration();
+        mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
         return true;
     }
 
@@ -249,36 +216,12 @@
         out.set(mBounds);
     }
 
-    private void updateOverrideConfiguration() {
-        final Configuration serviceConfig = mService.mCurConfiguration;
-        if (mFullscreen) {
-            mOverrideConfig = Configuration.EMPTY;
-            return;
-        }
-
-        if (mOverrideConfig == Configuration.EMPTY) {
-            mOverrideConfig  = new Configuration();
-        }
-
-        // TODO(multidisplay): Update Dp to that of display stack is on.
-        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
-        mOverrideConfig.screenWidthDp =
-                Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
-        mOverrideConfig.screenHeightDp =
-                Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
-        mOverrideConfig.smallestScreenWidthDp =
-                Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
-        mOverrideConfig.orientation =
-                (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
-                        ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
-    }
-
     void updateDisplayInfo(final DisplayContent displayContent) {
         if (displayContent == null) {
             return;
         }
         if (mFullscreen) {
-            setBounds(null);
+            setBounds(null, Configuration.EMPTY);
             return;
         }
         final int newRotation = displayContent.getDisplayInfo().rotation;
@@ -313,7 +256,7 @@
                 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
                 break;
         }
-        setBounds(mTmpRect2);
+        setBounds(mTmpRect2, mOverrideConfig);
     }
 
     /** Updates the dim layer bounds, recreating it if needed. */
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 25a71d9..a7ef2f8 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -27,6 +27,7 @@
 import android.util.EventLog;
 import android.util.IntArray;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.DisplayInfo;
 
 import com.android.server.EventLogTags;
@@ -96,15 +97,15 @@
 
     /**
      * Set the bounds of the stack and its containing tasks.
-     * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+     * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
      * @param resizeTasks If true, the tasks within the stack will also be resized.
-     * @param changedTaskIds Output list of Ids of tasks that changed in bounds.
-     * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+     * @param configs Configuration for individual tasks, keyed by task id.
+     * @param taskBounds Bounds for individual tasks, keyed by task id.
      * @return True if the stack bounds was changed.
      * */
-    boolean setBounds(Rect bounds, boolean resizeTasks, IntArray changedTaskIds,
-            List<Configuration> newTaskConfigs) {
-        if (!setBounds(bounds)) {
+    boolean setBounds(Rect stackBounds, boolean resizeTasks, SparseArray<Configuration> configs,
+            SparseArray<Rect> taskBounds) {
+        if (!setBounds(stackBounds)) {
             return false;
         }
 
@@ -113,20 +114,17 @@
         }
 
         // Update bounds of containing tasks.
-        final Rect newBounds = mFullscreen ? null : mBounds;
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final Task task = mTasks.get(taskNdx);
-            if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                // For freeform stack we don't adjust the size of the tasks to match that of the
-                // stack, but we do try to make sure the tasks are still contained with the
-                // bounds of the stack.
-                if (task.fitWithinBounds(newBounds)) {
-                    changedTaskIds.add(task.mTaskId);
-                    newTaskConfigs.add(task.mOverrideConfig);
+            Configuration config = configs.get(task.mTaskId);
+            if (config != null) {
+                Rect bounds = taskBounds.get(task.mTaskId);
+                if (bounds == null) {
+                    bounds = stackBounds;
                 }
-            } else if (task.setBounds(newBounds)) {
-                changedTaskIds.add(task.mTaskId);
-                newTaskConfigs.add(task.mOverrideConfig);
+                task.setBounds(bounds, config);
+            } else {
+                Slog.wtf(TAG, "No config for task: " + task + ", is there a mismatch with AM?");
             }
         }
         return true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cf690a5..bf7d1e7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3041,8 +3041,8 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    private Task createTaskLocked(
-            int taskId, int stackId, int userId, AppWindowToken atoken, Rect bounds) {
+    private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken,
+            Rect bounds, Configuration config) {
         if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
                 + " atoken=" + atoken + " bounds=" + bounds);
         final TaskStack stack = mStackIdToStack.get(stackId);
@@ -3050,17 +3050,17 @@
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
         EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
-        Task task = new Task(taskId, stack, userId, this, bounds);
+        Task task = new Task(taskId, stack, userId, this, bounds, config);
         mTaskIdToTask.put(taskId, task);
         stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
         return task;
     }
 
     @Override
-    public Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            Rect taskBounds) {
+            Rect taskBounds, Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3084,7 +3084,7 @@
             AppWindowToken atoken = findAppWindowToken(token.asBinder());
             if (atoken != null) {
                 Slog.w(TAG, "Attempted to add existing app token: " + token);
-                return null;
+                return;
             }
             atoken = new AppWindowToken(this, token, voiceInteraction);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
@@ -3098,10 +3098,8 @@
                     + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
             Task task = mTaskIdToTask.get(taskId);
-            Configuration outConfig = null;
             if (task == null) {
-                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds);
-                outConfig = task.mOverrideConfig;
+                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
             }
             task.addAppToken(addPos, atoken);
 
@@ -3110,13 +3108,11 @@
             // Application tokens start out hidden.
             atoken.hidden = true;
             atoken.hiddenRequested = true;
-
-            return outConfig;
         }
     }
 
     @Override
-    public Configuration setAppTask(IBinder token, int taskId, Rect taskBounds) {
+    public void setAppTask(IBinder token, int taskId, Rect taskBounds, Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppTask()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3126,20 +3122,18 @@
             final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
                 Slog.w(TAG, "Attempted to set task id of non-existing app token: " + token);
-                return null;
+                return;
             }
             final Task oldTask = atoken.mTask;
             oldTask.removeAppToken(atoken);
 
             Task newTask = mTaskIdToTask.get(taskId);
-            Configuration outConfig = null;
             if (newTask == null) {
                 newTask = createTaskLocked(
-                        taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds);
-                outConfig = newTask.mOverrideConfig;
+                        taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds,
+                        config);
             }
             newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
-            return outConfig;
         }
     }
 
@@ -4599,19 +4593,19 @@
      * @param stackId Id of stack to resize.
      * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
      * @param resizeTasks If true, the tasks within the stack will also be resized.
-     * @param changedTaskIds Output list of Ids of tasks that changed in bounds due to resize.
-     * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+     * @param configs Configurations for tasks in the resized stack, keyed by task id.
+     * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
      * @return True if the stack is now fullscreen.
      * */
     public boolean resizeStack(int stackId, Rect bounds, boolean resizeTasks,
-            IntArray changedTaskIds, List<Configuration> newTaskConfigs) {
+            SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
             if (stack == null) {
                 throw new IllegalArgumentException("resizeStack: stackId " + stackId
                         + " not found.");
             }
-            if (stack.setBounds(bounds, resizeTasks, changedTaskIds, newTaskConfigs)) {
+            if (stack.setBounds(bounds, resizeTasks, configs, taskBounds)) {
                 stack.resizeWindows();
                 stack.getDisplayContent().layoutNeeded = true;
                 performLayoutAndPlaceSurfacesLocked();
@@ -4648,19 +4642,20 @@
      * Returns a {@link Configuration} object that contains configurations settings
      * that should be overridden due to the operation.
      */
-    public Configuration resizeTask(int taskId, Rect bounds) {
+    public void resizeTask(int taskId, Rect bounds, Configuration configuration, boolean relayout) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
                 throw new IllegalArgumentException("resizeTask: taskId " + taskId
                         + " not found.");
             }
-            if (task.setBounds(bounds)) {
+            if (task.setBounds(bounds, configuration)) {
                 task.resizeWindows();
-                task.getDisplayContent().layoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
+                if (relayout) {
+                    task.getDisplayContent().layoutNeeded = true;
+                    performLayoutAndPlaceSurfacesLocked();
+                }
             }
-            return new Configuration(task.mOverrideConfig);
         }
     }
 
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 6177784..95f676e 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -32,7 +32,7 @@
  */
 public class WindowManagerPermissionTests extends TestCase {
     IWindowManager mWm;
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -51,7 +51,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.resumeKeyDispatching(null);
             fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as"
@@ -61,7 +61,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setEventDispatching(true);
             fail("IWindowManager.setEventDispatching did not throw SecurityException as"
@@ -71,7 +71,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.addWindowToken(null, 0);
             fail("IWindowManager.addWindowToken did not throw SecurityException as"
@@ -81,7 +81,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.removeWindowToken(null);
             fail("IWindowManager.removeWindowToken did not throw SecurityException as"
@@ -91,9 +91,10 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
-            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null);
+            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
+                    Configuration.EMPTY);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -101,9 +102,9 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
-            mWm.setAppTask(null, 0, null);
+            mWm.setAppTask(null, 0, null, null);
             fail("IWindowManager.setAppGroupId did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -111,7 +112,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.updateOrientationFromAppTokens(new Configuration(), null);
             fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
@@ -121,7 +122,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppOrientation(null, 0);
             mWm.addWindowToken(null, 0);
@@ -132,7 +133,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setFocusedApp(null, false);
             fail("IWindowManager.setFocusedApp did not throw SecurityException as"
@@ -142,7 +143,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.prepareAppTransition(0, false);
             fail("IWindowManager.prepareAppTransition did not throw SecurityException as"
@@ -152,7 +153,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.executeAppTransition();
             fail("IWindowManager.executeAppTransition did not throw SecurityException as"
@@ -162,7 +163,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
             fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
@@ -172,7 +173,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppWillBeHidden(null);
             fail("IWindowManager.setAppWillBeHidden did not throw SecurityException as"
@@ -182,7 +183,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppVisibility(null, false);
             fail("IWindowManager.setAppVisibility did not throw SecurityException as"
@@ -192,7 +193,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.startAppFreezingScreen(null, 0);
             fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as"
@@ -202,7 +203,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.stopAppFreezingScreen(null, false);
             fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as"
@@ -212,7 +213,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.removeAppToken(null);
             fail("IWindowManager.removeAppToken did not throw SecurityException as"
@@ -236,7 +237,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.reenableKeyguard(token);
             fail("IWindowManager.reenableKeyguard did not throw SecurityException as"
@@ -246,7 +247,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.exitKeyguardSecurely(null);
             fail("IWindowManager.exitKeyguardSecurely did not throw SecurityException as"
@@ -257,7 +258,7 @@
             fail("Unexpected remote exception");
         }
     }
-        
+
     @SmallTest
     public void testSET_ANIMATION_SCALE() {
         try {
@@ -269,7 +270,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAnimationScales(new float[1]);
             fail("IWindowManager.setAnimationScales did not throw SecurityException as"
@@ -280,7 +281,7 @@
             fail("Unexpected remote exception");
         }
     }
-    
+
     @SmallTest
     public void testSET_ORIENTATION() {
         try {