Merge "Remove AppWindowContainerController and AppWindowContainerListener (39/n)"
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 61168ec..eec22d5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -18,7 +18,17 @@
 
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
+import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
+import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.app.ActivityOptions.ANIM_NONE;
+import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
+import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
+import static android.app.ActivityOptions.ANIM_SCALE_UP;
 import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
+import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
+import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
+import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
+import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
 import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.AppOpsManager.MODE_ALLOWED;
@@ -63,6 +73,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.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
 import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
 import static android.content.res.Configuration.EMPTY;
@@ -111,12 +122,18 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
-import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+import static com.android.server.wm.ActivityTaskManagerService
+        .RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
 import static com.android.server.wm.IdentifierProto.USER_ID;
 import static com.android.server.wm.TaskPersister.DEBUG;
 import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -147,6 +164,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Build;
@@ -167,11 +185,14 @@
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
+import android.view.AppTransitionAnimationSpec;
+import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IApplicationToken;
 import android.view.RemoteAnimationDefinition;
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.util.XmlUtils;
@@ -200,7 +221,7 @@
 /**
  * An entry in the history stack, representing an activity.
  */
-final class ActivityRecord extends ConfigurationContainer implements AppWindowContainerListener {
+final class ActivityRecord extends ConfigurationContainer {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
@@ -225,7 +246,9 @@
 
     final ActivityTaskManagerService service; // owner
     final IApplicationToken.Stub appToken; // window manager token
-    AppWindowContainerController mWindowContainerController;
+    // TODO: Remove after unification
+    AppWindowToken mAppWindowToken;
+
     final ActivityInfo info; // all about me
     // TODO: This is duplicated state already contained in info.applicationInfo - remove
     ApplicationInfo appInfo; // information about activity's app
@@ -770,10 +793,16 @@
     }
 
     /**
-     * See {@link AppWindowContainerController#setWillCloseOrEnterPip(boolean)}
+     * Notifies AWT that this app is waiting to pause in order to determine if it will enter PIP.
+     * This information helps AWT know that the app is in the process of pausing before it gets the
+     * signal on the WM side.
      */
     void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
-        getWindowContainerController().setWillCloseOrEnterPip(willCloseOrEnterPip);
+        if (mAppWindowToken == null) {
+            return;
+        }
+
+        mAppWindowToken.setWillCloseOrEnterPip(willCloseOrEnterPip);
     }
 
     static class Token extends IApplicationToken.Stub {
@@ -993,13 +1022,9 @@
         return hasProcess() && app.hasThread();
     }
 
-    AppWindowContainerController getWindowContainerController() {
-        return mWindowContainerController;
-    }
-
-    void createWindowContainer() {
-        if (mWindowContainerController != null) {
-            throw new IllegalArgumentException("Window container=" + mWindowContainerController
+    void createAppWindowToken() {
+        if (mAppWindowToken != null) {
+            throw new IllegalArgumentException("App Window Token=" + mAppWindowToken
                     + " already created for r=" + this);
         }
 
@@ -1012,12 +1037,31 @@
         // Make sure override configuration is up-to-date before using to create window controller.
         updateOverrideConfiguration();
 
-        mWindowContainerController = new AppWindowContainerController(taskController, appToken,
-                realActivity, 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,
-                ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
+        // TODO: remove after unification
+        mAppWindowToken = service.mWindowManager.mRoot.getAppWindowToken(appToken.asBinder());
+        if (mAppWindowToken != null) {
+            // TODO: Should this throw an exception instead?
+            Slog.w(TAG, "Attempted to add existing app token: " + appToken);
+        } else {
+            final Task container = taskController.mContainer;
+            if (container == null) {
+                throw new IllegalArgumentException("AppWindowContainerController: invalid "
+                        + " controller=" + taskController);
+            }
+            mAppWindowToken = createAppWindow(service.mWindowManager, appToken,
+                    task.voiceSession != null, container.getDisplayContent(),
+                    ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this)
+                            * 1000000L, fullscreen,
+                    (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, appInfo.targetSdkVersion,
+                    info.screenOrientation, mRotationAnimationHint, info.configChanges,
+                    mLaunchTaskBehind, isAlwaysFocusable());
+            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) {
+                Slog.v(TAG, "addAppToken: "
+                        + mAppWindowToken + " controller=" + taskController + " at "
+                        + Integer.MAX_VALUE);
+            }
+            container.addChild(mAppWindowToken, Integer.MAX_VALUE /* add on top */);
+        }
 
         task.addActivityToTop(this);
 
@@ -1028,17 +1072,49 @@
         mLastReportedPictureInPictureMode = inPinnedWindowingMode();
     }
 
+    boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
+            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
+            IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
+            boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
+        if (DEBUG_STARTING_WINDOW) {
+            Slog.v(TAG, "setAppStartingWindow: token=" + appToken
+                    + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
+                    + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
+                    + " allowTaskSnapshot=" + allowTaskSnapshot);
+        }
+        if (mAppWindowToken == null) {
+            Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + appToken);
+            return false;
+        }
+        return mAppWindowToken.addStartingWindow(pkg, theme, compatInfo, nonLocalizedLabel,
+                labelRes, icon, logo, windowFlags, transferFrom, newTask, taskSwitch,
+                processRunning, allowTaskSnapshot, activityCreated, fromRecents);
+    }
+
+    // TODO: Remove after unification
+    @VisibleForTesting
+    AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
+            boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
+            boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
+            int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+            boolean alwaysFocusable) {
+        return new AppWindowToken(service, token, realActivity, voiceInteraction, dc,
+                inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
+                rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
+                this);
+    }
+
     void removeWindowContainer() {
-        // Do not try to remove a window container if we have already removed it.
-        if (mWindowContainerController == null) {
+        final DisplayContent dc = service.mWindowManager.mRoot.getDisplayContent(
+                getDisplayId());
+        if (dc == null) {
+            Slog.w(TAG, "removeWindowContainer: Attempted to remove token: "
+                    + appToken + " from non-existing displayId=" + getDisplayId());
             return;
         }
-
         // Resume key dispatching if it is currently paused before we remove the container.
         resumeKeyDispatchingLocked();
-
-        mWindowContainerController.removeContainer(getDisplayId());
-        mWindowContainerController = null;
+        dc.removeAppToken(appToken.asBinder());
     }
 
     /**
@@ -1046,6 +1122,10 @@
      * should ensure that the {@param newTask} is not already the parent of this activity.
      */
     void reparent(TaskRecord newTask, int position, String reason) {
+        if (mAppWindowToken == null) {
+            Slog.w(TAG, "reparent: Attempted to reparent non-existing app token: " + appToken);
+            return;
+        }
         final TaskRecord prevTask = task;
         if (prevTask == newTask) {
             throw new IllegalArgumentException(reason + ": task=" + newTask
@@ -1061,8 +1141,7 @@
                     + " r=" + this + " (" + prevTask.getStackId() + ")");
         }
 
-        // Must reparent first in window manager
-        mWindowContainerController.reparent(newTask.getWindowContainerController(), position);
+        mAppWindowToken.reparent(newTask.getWindowContainerController(), position);
 
         // Reparenting prevents informing the parent stack of activity removal in the case that
         // the new stack has the same parent. we must manually signal here if this is not the case.
@@ -1492,7 +1571,7 @@
     void applyOptionsLocked() {
         if (pendingOptions != null
                 && pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) {
-            mWindowContainerController.applyOptionsLocked(pendingOptions, intent);
+            applyOptionsLocked(pendingOptions, intent);
             if (task == null) {
                 clearOptionsLocked(false /* withAbort */);
             } else {
@@ -1502,6 +1581,104 @@
         }
     }
 
+    /**
+     * Apply override app transition base on options & animation type.
+     */
+    void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) {
+        final int animationType = pendingOptions.getAnimationType();
+        final DisplayContent displayContent = mAppWindowToken.getDisplayContent();
+        switch (animationType) {
+            case ANIM_CUSTOM:
+                displayContent.mAppTransition.overridePendingAppTransition(
+                        pendingOptions.getPackageName(),
+                        pendingOptions.getCustomEnterResId(),
+                        pendingOptions.getCustomExitResId(),
+                        pendingOptions.getOnAnimationStartListener());
+                break;
+            case ANIM_CLIP_REVEAL:
+                displayContent.mAppTransition.overridePendingAppTransitionClipReveal(
+                        pendingOptions.getStartX(), pendingOptions.getStartY(),
+                        pendingOptions.getWidth(), pendingOptions.getHeight());
+                if (intent.getSourceBounds() == null) {
+                    intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+                            pendingOptions.getStartY(),
+                            pendingOptions.getStartX() + pendingOptions.getWidth(),
+                            pendingOptions.getStartY() + pendingOptions.getHeight()));
+                }
+                break;
+            case ANIM_SCALE_UP:
+                displayContent.mAppTransition.overridePendingAppTransitionScaleUp(
+                        pendingOptions.getStartX(), pendingOptions.getStartY(),
+                        pendingOptions.getWidth(), pendingOptions.getHeight());
+                if (intent.getSourceBounds() == null) {
+                    intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+                            pendingOptions.getStartY(),
+                            pendingOptions.getStartX() + pendingOptions.getWidth(),
+                            pendingOptions.getStartY() + pendingOptions.getHeight()));
+                }
+                break;
+            case ANIM_THUMBNAIL_SCALE_UP:
+            case ANIM_THUMBNAIL_SCALE_DOWN:
+                final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP);
+                final GraphicBuffer buffer = pendingOptions.getThumbnail();
+                displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer,
+                        pendingOptions.getStartX(), pendingOptions.getStartY(),
+                        pendingOptions.getOnAnimationStartListener(),
+                        scaleUp);
+                if (intent.getSourceBounds() == null && buffer != null) {
+                    intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+                            pendingOptions.getStartY(),
+                            pendingOptions.getStartX() + buffer.getWidth(),
+                            pendingOptions.getStartY() + buffer.getHeight()));
+                }
+                break;
+            case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
+            case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
+                final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
+                final IAppTransitionAnimationSpecsFuture specsFuture =
+                        pendingOptions.getSpecsFuture();
+                if (specsFuture != null) {
+                    // TODO(multidisplay): Shouldn't be really used anymore from next CL.
+                    displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture(
+                            specsFuture, pendingOptions.getOnAnimationStartListener(),
+                            animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
+                } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
+                        && specs != null) {
+                    displayContent.mAppTransition.overridePendingAppTransitionMultiThumb(
+                            specs, pendingOptions.getOnAnimationStartListener(),
+                            pendingOptions.getAnimationFinishedListener(), false);
+                } else {
+                    displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb(
+                            pendingOptions.getThumbnail(),
+                            pendingOptions.getStartX(), pendingOptions.getStartY(),
+                            pendingOptions.getWidth(), pendingOptions.getHeight(),
+                            pendingOptions.getOnAnimationStartListener(),
+                            (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP));
+                    if (intent.getSourceBounds() == null) {
+                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+                                pendingOptions.getStartY(),
+                                pendingOptions.getStartX() + pendingOptions.getWidth(),
+                                pendingOptions.getStartY() + pendingOptions.getHeight()));
+                    }
+                }
+                break;
+            case ANIM_OPEN_CROSS_PROFILE_APPS:
+                displayContent.mAppTransition
+                        .overridePendingAppTransitionStartCrossProfileApps();
+                break;
+            case ANIM_REMOTE_ANIMATION:
+                // TODO(multidisplay): Will pass displayId and adjust dependencies from next CL.
+                displayContent.mAppTransition.overridePendingAppTransitionRemote(
+                        pendingOptions.getRemoteAnimationAdapter());
+                break;
+            case ANIM_NONE:
+                break;
+            default:
+                Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
+                break;
+        }
+    }
+
     ActivityOptions getOptionsForTargetActivityLocked() {
         return pendingOptions != null ? pendingOptions.forTargetActivity() : null;
     }
@@ -1534,8 +1711,11 @@
         if (!keysPaused) {
             keysPaused = true;
 
-            if (mWindowContainerController != null) {
-                mWindowContainerController.pauseKeyDispatching();
+            // TODO: remove the check after unification with AppWindowToken. The DC check is not
+            // needed after no mock mAppWindowToken in tests.
+            if (mAppWindowToken != null && mAppWindowToken.getDisplayContent() != null) {
+                mAppWindowToken.getDisplayContent().getInputMonitor().pauseDispatchingLw(
+                        mAppWindowToken);
             }
         }
     }
@@ -1544,8 +1724,11 @@
         if (keysPaused) {
             keysPaused = false;
 
-            if (mWindowContainerController != null) {
-                mWindowContainerController.resumeKeyDispatching();
+            // TODO: remove the check after unification with AppWindowToken. The DC check is not
+            // needed after no mock mAppWindowToken in tests.
+            if (mAppWindowToken != null && mAppWindowToken.getDisplayContent() != null) {
+                mAppWindowToken.getDisplayContent().getInputMonitor().resumeDispatchingLw(
+                        mAppWindowToken);
             }
         }
     }
@@ -1567,11 +1750,16 @@
     }
 
     void setVisibility(boolean visible) {
-        mWindowContainerController.setVisibility(visible, mDeferHidingClient);
+        if (mAppWindowToken == null) {
+            Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
+                    + appToken);
+            return;
+        }
+        mAppWindowToken.setVisibility(visible, mDeferHidingClient);
         mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
     }
 
-    // TODO: Look into merging with #setVisibility()
+    // TODO: Look into merging with #commitVisibility()
     void setVisible(boolean newVisible) {
         visible = newVisible;
         mDeferHidingClient = !visible && mDeferHidingClient;
@@ -1601,7 +1789,12 @@
         // an indication that the Surface will eventually be destroyed.
         // This however isn't necessarily true if we are going to sleep.
         if (state == STOPPING && !isSleeping()) {
-            mWindowContainerController.notifyAppStopping();
+            if (mAppWindowToken == null) {
+                Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: "
+                        + appToken);
+                return;
+            }
+            mAppWindowToken.detachChildren();
         }
     }
 
@@ -1639,7 +1832,12 @@
     }
 
     void notifyAppResumed(boolean wasStopped) {
-        mWindowContainerController.notifyAppResumed(wasStopped);
+        if (mAppWindowToken == null) {
+            Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: "
+                    + appToken);
+            return;
+        }
+        mAppWindowToken.notifyAppResumed(wasStopped);
     }
 
     void notifyUnknownVisibilityLaunched() {
@@ -1647,7 +1845,10 @@
         // No display activities never add a window, so there is no point in waiting them for
         // relayout.
         if (!noDisplay) {
-            mWindowContainerController.notifyUnknownVisibilityLaunched();
+            if (mAppWindowToken != null) {
+                mAppWindowToken.getDisplayContent().mUnknownAppVisibilityController
+                        .notifyLaunched(mAppWindowToken);
+            }
         }
     }
 
@@ -1859,7 +2060,9 @@
             stopped = true;
             setState(STOPPED, "activityStoppedLocked");
 
-            mWindowContainerController.notifyAppStopped();
+            if (mAppWindowToken != null) {
+                mAppWindowToken.notifyAppStopped();
+            }
 
             if (finishing) {
                 clearOptionsLocked();
@@ -1920,14 +2123,33 @@
 
     public void startFreezingScreenLocked(WindowProcessController app, int configChanges) {
         if (mayFreezeScreenLocked(app)) {
-            mWindowContainerController.startFreezingScreen(configChanges);
+            if (mAppWindowToken == null) {
+                Slog.w(TAG_WM,
+                        "Attempted to freeze screen with non-existing app token: " + appToken);
+                return;
+            }
+
+            if (configChanges == 0 && mAppWindowToken.okToDisplay()) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + appToken);
+                return;
+            }
+
+            mAppWindowToken.startFreezingScreen();
         }
     }
 
     public void stopFreezingScreenLocked(boolean force) {
         if (force || frozenBeforeDestroy) {
             frozenBeforeDestroy = false;
-            mWindowContainerController.stopFreezingScreen(force);
+            if (mAppWindowToken == null) {
+                return;
+            }
+            if (DEBUG_ORIENTATION) {
+                Slog.v(TAG_WM, "Clear freezing of " + appToken + ": hidden="
+                        + mAppWindowToken.isHidden() + " freezing="
+                        + mAppWindowToken.isFreezingScreen());
+            }
+            mAppWindowToken.stopFreezingScreen(true, force);
         }
     }
 
@@ -1939,7 +2161,10 @@
                     info.windowsFullyDrawnDelayMs);
         }
     }
-    @Override
+
+    /**
+     * Called when the starting window for this container is drawn.
+     */
     public void onStartingWindowDrawn(long timestamp) {
         synchronized (service.mGlobalLock) {
             mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
@@ -1947,7 +2172,7 @@
         }
     }
 
-    @Override
+    /** Called when the windows associated app window container are drawn. */
     public void onWindowsDrawn(boolean drawn, long timestamp) {
         synchronized (service.mGlobalLock) {
             mDrawn = drawn;
@@ -1967,7 +2192,7 @@
         }
     }
 
-    @Override
+    /** Called when the windows associated app window container are visible. */
     public void onWindowsVisible() {
         synchronized (service.mGlobalLock) {
             mStackSupervisor.reportActivityVisibleLocked(this);
@@ -2001,7 +2226,7 @@
         }
     }
 
-    @Override
+    /** Called when the windows associated app window container are no longer visible. */
     public void onWindowsGone() {
         synchronized (service.mGlobalLock) {
             if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
@@ -2009,7 +2234,14 @@
         }
     }
 
-    @Override
+    /**
+     * Called when the key dispatching to a window associated with the app window container
+     * timed-out.
+     *
+     * @param reason The reason for the key dispatching time out.
+     * @param windowPid The pid of the window key dispatching timed out on.
+     * @return True if input dispatching should be aborted.
+     */
     public boolean keyDispatchingTimedOut(String reason, int windowPid) {
         ActivityRecord anrActivity;
         WindowProcessController anrApp;
@@ -2185,7 +2417,7 @@
 
     void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
             boolean fromRecents) {
-        if (mWindowContainerController == null) {
+        if (mAppWindowToken == null) {
             return;
         }
         if (mTaskOverlay) {
@@ -2200,7 +2432,7 @@
 
         final CompatibilityInfo compatInfo =
                 service.compatibilityInfoForPackageLocked(info.applicationInfo);
-        final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
+        final boolean shown = addStartingWindow(packageName, theme,
                 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                 prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
                 allowTaskSnapshot(),
@@ -2215,12 +2447,12 @@
         if (mStartingWindowState == STARTING_WINDOW_SHOWN && behindFullscreenActivity) {
             if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
             mStartingWindowState = STARTING_WINDOW_REMOVED;
-            mWindowContainerController.removeStartingWindow();
+            mAppWindowToken.removeStartingWindow();
         }
     }
 
     int getRequestedOrientation() {
-        return mWindowContainerController.getOrientation();
+        return getOrientation();
     }
 
     void setRequestedOrientation(int requestedOrientation) {
@@ -2228,7 +2460,7 @@
         final Configuration displayConfig =
                 mRootActivityContainer.getDisplayOverrideConfiguration(displayId);
 
-        final Configuration config = mWindowContainerController.setOrientation(requestedOrientation,
+        final Configuration config = setOrientation(requestedOrientation,
                 displayId, displayConfig, mayFreezeScreenLocked(app));
         if (config != null) {
             frozenBeforeDestroy = true;
@@ -2241,8 +2473,36 @@
                 task.taskId, requestedOrientation);
     }
 
+    Configuration setOrientation(int requestedOrientation, int displayId,
+            Configuration displayConfig, boolean freezeScreenIfNeeded) {
+        if (mAppWindowToken == null) {
+            Slog.w(TAG_WM,
+                    "Attempted to set orientation of non-existing app token: " + appToken);
+            return null;
+        }
+
+        mAppWindowToken.setOrientation(requestedOrientation);
+
+        final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
+        return service.mWindowManager.updateOrientationFromAppTokens(displayConfig, binder,
+                displayId);
+    }
+
+    int getOrientation() {
+        if (mAppWindowToken == null) {
+            return SCREEN_ORIENTATION_UNSPECIFIED;
+        }
+
+        return mAppWindowToken.getOrientationIgnoreVisibility();
+    }
+
     void setDisablePreviewScreenshots(boolean disable) {
-        mWindowContainerController.setDisablePreviewScreenshots(disable);
+        if (mAppWindowToken == null) {
+            Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
+                    + " token: " + appToken);
+            return;
+        }
+        mAppWindowToken.setDisablePreviewScreenshots(disable);
     }
 
     /**
@@ -2290,8 +2550,8 @@
 
     /** Returns true if the configuration is compatible with this activity. */
     boolean isConfigurationCompatible(Configuration config) {
-        final int orientation = mWindowContainerController != null
-                ? mWindowContainerController.getOrientation() : info.screenOrientation;
+        final int orientation = mAppWindowToken != null
+                ? getOrientation() : info.screenOrientation;
         if (isFixedOrientationPortrait(orientation)
                 && config.orientation != ORIENTATION_PORTRAIT) {
             return false;
@@ -2920,7 +3180,12 @@
     }
 
     void registerRemoteAnimations(RemoteAnimationDefinition definition) {
-        mWindowContainerController.registerRemoteAnimations(definition);
+        if (mAppWindowToken == null) {
+            Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app"
+                    + " token: " + appToken);
+            return;
+        }
+        mAppWindowToken.registerRemoteAnimations(definition);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index f49c689..9fbeaf8 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -3034,7 +3034,7 @@
                     if (!startIt) {
                         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                                 + task, new RuntimeException("here").fillInStackTrace());
-                        r.createWindowContainer();
+                        r.createAppWindowToken();
                         ActivityOptions.abort(options);
                         return;
                     }
@@ -3064,9 +3064,10 @@
         // TODO: Need to investigate if it is okay for the controller to already be created by the
         // time we get to this point. I think it is, but need to double check.
         // Use test in b/34179495 to trace the call path.
-        if (r.getWindowContainerController() == null) {
-            r.createWindowContainer();
+        if (r.mAppWindowToken == null) {
+            r.createAppWindowToken();
         }
+
         task.setFrontOfTask();
 
         if (!isHomeOrRecentsStack() || numActivities() > 0) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a71f5f3..3162ee3 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1877,7 +1877,7 @@
                 "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
         for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-            activities.get(activityNdx).createWindowContainer();
+            activities.get(activityNdx).createAppWindowToken();
         }
         return true;
     }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 32a6f74..bf00ffb 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -305,7 +305,7 @@
             AppWindowToken wtoken = openingApps.valueAt(i);
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
 
-            if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)) {
+            if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
                 // This token isn't going to be animating. Add it to the list of tokens to
                 // be notified of app transition complete since the notification will not be
                 // sent be the app window animator.
@@ -341,7 +341,7 @@
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
             // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
             //       animating?
-            wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
+            wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
             wtoken.updateReportedVisibilityLocked();
             // Force the allDrawn flag, because we want to start
             // this guy's animations regardless of whether it's
@@ -350,9 +350,8 @@
             wtoken.deferClearAllDrawn = false;
             // Ensure that apps that are mid-starting are also scheduled to have their
             // starting windows removed after the animation is complete
-            if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit
-                    && wtoken.getController() != null) {
-                wtoken.getController().removeStartingWindow();
+            if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
+                wtoken.removeStartingWindow();
             }
 
             if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
deleted file mode 100644
index 7fdea10..0000000
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ /dev/null
@@ -1,912 +0,0 @@
-/*
- * 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 static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
-import static android.app.ActivityOptions.ANIM_CUSTOM;
-import static android.app.ActivityOptions.ANIM_NONE;
-import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
-import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
-import static android.app.ActivityOptions.ANIM_SCALE_UP;
-import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
-import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
-import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
-import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
-import static android.view.WindowManager.TRANSIT_UNSET;
-
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.app.ActivityManager.TaskSnapshot;
-import android.app.ActivityOptions;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.res.CompatibilityInfo;
-import android.content.res.Configuration;
-import android.graphics.GraphicBuffer;
-import android.graphics.Rect;
-import android.os.Debug;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Slog;
-import android.view.AppTransitionAnimationSpec;
-import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IApplicationToken;
-import android.view.RemoteAnimationDefinition;
-import android.view.WindowManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.AttributeCache;
-import com.android.server.policy.WindowManagerPolicy.StartingSurface;
-
-/**
- * Controller for the app window token container. This is created by activity manager to link
- * activity records to the app window token container they use in window manager.
- *
- * Test class: {@link AppWindowContainerControllerTests}
- */
-public class AppWindowContainerController
-        extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
-
-    private static final int STARTING_WINDOW_TYPE_NONE = 0;
-    private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
-    private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
-
-    private final IApplicationToken mToken;
-    private final Handler mHandler;
-
-    private final class H extends Handler {
-        public static final int NOTIFY_WINDOWS_DRAWN = 1;
-        public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2;
-        public static final int NOTIFY_WINDOWS_NOTDRAWN = 3;
-
-        public H(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case NOTIFY_WINDOWS_DRAWN:
-                    if (mListener == null) {
-                        return;
-                    }
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
-                            + AppWindowContainerController.this.mToken);
-                    mListener.onWindowsDrawn(true /* drawn */, msg.getWhen());
-                    break;
-                case NOTIFY_STARTING_WINDOW_DRAWN:
-                    if (mListener == null) {
-                        return;
-                    }
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting starting window drawn in "
-                            + AppWindowContainerController.this.mToken);
-                    mListener.onStartingWindowDrawn(msg.getWhen());
-                    break;
-                case NOTIFY_WINDOWS_NOTDRAWN:
-                    if (mListener == null) {
-                        return;
-                    }
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting not drawn in "
-                            + AppWindowContainerController.this.mToken);
-                    mListener.onWindowsDrawn(false /* drawn */, msg.getWhen());
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-
-    private final Runnable mOnWindowsVisible = () -> {
-        if (mListener == null) {
-            return;
-        }
-        if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
-                + AppWindowContainerController.this.mToken);
-        mListener.onWindowsVisible();
-    };
-
-    private final Runnable mOnWindowsGone = () -> {
-        if (mListener == null) {
-            return;
-        }
-        if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
-                + AppWindowContainerController.this.mToken);
-        mListener.onWindowsGone();
-    };
-
-    private final Runnable mAddStartingWindow = new Runnable() {
-
-        @Override
-        public void run() {
-            final StartingData startingData;
-            final AppWindowToken container;
-
-            synchronized (mGlobalLock) {
-                if (mContainer == null) {
-                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
-                            + " add starting window");
-                    return;
-                }
-
-                // There can only be one adding request, silly caller!
-                mService.mAnimationHandler.removeCallbacks(this);
-
-                startingData = mContainer.startingData;
-                container = mContainer;
-            }
-
-            if (startingData == null) {
-                // Animation has been canceled... do nothing.
-                if (DEBUG_STARTING_WINDOW)
-                    Slog.v(TAG_WM, "startingData was nulled out before handling"
-                            + " mAddStartingWindow: " + mContainer);
-                return;
-            }
-
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
-                    + AppWindowContainerController.this + ": startingData="
-                    + container.startingData);
-
-            StartingSurface surface = null;
-            try {
-                surface = startingData.createStartingSurface(container);
-            } catch (Exception e) {
-                Slog.w(TAG_WM, "Exception when adding starting window", e);
-            }
-            if (surface != null) {
-                boolean abort = false;
-                synchronized (mGlobalLock) {
-                    // If the window was successfully added, then
-                    // we need to remove it.
-                    if (container.removed || container.startingData == null) {
-                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                                "Aborted starting " + container
-                                        + ": removed=" + container.removed
-                                        + " startingData=" + container.startingData);
-                        container.startingWindow = null;
-                        container.startingData = null;
-                        abort = true;
-                    } else {
-                        container.startingSurface = surface;
-                    }
-                    if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
-                            "Added starting " + mContainer
-                                    + ": startingWindow="
-                                    + container.startingWindow + " startingView="
-                                    + container.startingSurface);
-                }
-                if (abort) {
-                    surface.remove();
-                }
-            } else if (DEBUG_STARTING_WINDOW) {
-                Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
-            }
-        }
-    };
-
-    public AppWindowContainerController(TaskWindowContainerController taskController,
-            IApplicationToken token, ComponentName activityComponent,
-            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(taskController, token, activityComponent, listener, index, requestedOrientation,
-                fullscreen, showForAllUsers, configChanges, voiceInteraction, launchTaskBehind,
-                alwaysFocusable, targetSdkVersion, rotationAnimationHint,
-                inputDispatchingTimeoutNanos, WindowManagerService.getInstance());
-    }
-
-    public AppWindowContainerController(TaskWindowContainerController taskController,
-            IApplicationToken token, ComponentName activityComponent,
-            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) {
-        super(listener, service);
-        mHandler = new H(service.mH.getLooper());
-        mToken = token;
-        synchronized (mGlobalLock) {
-            AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
-            if (atoken != null) {
-                // TODO: Should this throw an exception instead?
-                Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
-                return;
-            }
-
-            final Task task = taskController.mContainer;
-            if (task == null) {
-                throw new IllegalArgumentException("AppWindowContainerController: invalid "
-                        + " controller=" + taskController);
-            }
-
-            atoken = createAppWindow(mService, token, activityComponent, voiceInteraction,
-                    task.getDisplayContent(), inputDispatchingTimeoutNanos, fullscreen,
-                    showForAllUsers, targetSdkVersion, requestedOrientation, rotationAnimationHint,
-                    configChanges, launchTaskBehind, alwaysFocusable, this);
-            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
-                    + " controller=" + taskController + " at " + index);
-            task.addChild(atoken, index);
-        }
-    }
-
-    @VisibleForTesting
-    AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
-            ComponentName component, boolean voiceInteraction, DisplayContent dc,
-            long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
-            int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
-            boolean launchTaskBehind, boolean alwaysFocusable,
-            AppWindowContainerController controller) {
-        return new AppWindowToken(service, token, component, voiceInteraction, dc,
-                inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
-                rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
-                controller);
-    }
-
-    public void removeContainer(int displayId) {
-        synchronized (mGlobalLock) {
-            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();
-        }
-    }
-
-    @Override
-    public void removeContainer() {
-        throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
-    }
-
-    public void reparent(TaskWindowContainerController taskController, int position) {
-        synchronized (mGlobalLock) {
-            if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
-                    + " to task=" + taskController + " at " + position);
-            if (mContainer == null) {
-                if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
-                        "reparent: could not find app token=" + mToken);
-                return;
-            }
-            final Task task = taskController.mContainer;
-            if (task == null) {
-                throw new IllegalArgumentException("reparent: could not find task="
-                        + taskController);
-            }
-            mContainer.reparent(task, position);
-            mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-        }
-    }
-
-    public Configuration setOrientation(int requestedOrientation, int displayId,
-            Configuration displayConfig, boolean freezeScreenIfNeeded) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM,
-                        "Attempted to set orientation of non-existing app token: " + mToken);
-                return null;
-            }
-
-            mContainer.setOrientation(requestedOrientation);
-
-            final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
-            return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
-
-        }
-    }
-
-    public int getOrientation() {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                return SCREEN_ORIENTATION_UNSPECIFIED;
-            }
-
-            return mContainer.getOrientationIgnoreVisibility();
-        }
-    }
-
-    public void setDisablePreviewScreenshots(boolean disable) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
-                        + " token: " + mToken);
-                return;
-            }
-            mContainer.setDisablePreviewScreenshots(disable);
-        }
-    }
-
-    public void setVisibility(boolean visible, boolean deferHidingClient) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
-                        + mToken);
-                return;
-            }
-
-            final AppWindowToken wtoken = mContainer;
-            final AppTransition appTransition = mContainer.getDisplayContent().mAppTransition;
-
-            // Don't set visibility to false if we were already not visible. This prevents WM from
-            // adding the app to the closing app list which doesn't make sense for something that is
-            // already not visible. However, set visibility to true even if we are already visible.
-            // This makes sure the app is added to the opening apps list so that the right
-            // transition can be selected.
-            // TODO: Probably a good idea to separate the concept of opening/closing apps from the
-            // concept of setting visibility...
-            if (!visible && wtoken.hiddenRequested) {
-
-                if (!deferHidingClient && wtoken.mDeferHidingClient) {
-                    // We previously deferred telling the client to hide itself when visibility was
-                    // initially set to false. Now we would like it to hide, so go ahead and set it.
-                    wtoken.mDeferHidingClient = deferHidingClient;
-                    wtoken.setClientHidden(true);
-                }
-                return;
-            }
-
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
-                    + mToken + ", visible=" + visible + "): " + appTransition
-                    + " hidden=" + wtoken.isHidden() + " hiddenRequested="
-                    + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
-
-            final DisplayContent displayContent = mContainer.getDisplayContent();
-            displayContent.mOpeningApps.remove(wtoken);
-            displayContent.mClosingApps.remove(wtoken);
-            wtoken.waitingToShow = false;
-            wtoken.hiddenRequested = !visible;
-            wtoken.mDeferHidingClient = deferHidingClient;
-
-            if (!visible) {
-                // If the app is dead while it was visible, we kept its dead window on screen.
-                // Now that the app is going invisible, we can remove it. It will be restarted
-                // if made visible again.
-                wtoken.removeDeadWindows();
-            } else {
-                if (!appTransition.isTransitionSet()
-                        && appTransition.isReady()) {
-                    // Add the app mOpeningApps if transition is unset but ready. This means
-                    // we're doing a screen freeze, and the unfreeze will wait for all opening
-                    // apps to be ready.
-                    displayContent.mOpeningApps.add(wtoken);
-                }
-                wtoken.startingMoved = false;
-                // If the token is currently hidden (should be the common case), or has been
-                // stopped, then we need to set up to wait for its windows to be ready.
-                if (wtoken.isHidden() || wtoken.mAppStopped) {
-                    wtoken.clearAllDrawn();
-
-                    // If the app was already visible, don't reset the waitingToShow state.
-                    if (wtoken.isHidden()) {
-                        wtoken.waitingToShow = true;
-                    }
-                }
-
-                // In the case where we are making an app visible but holding off for a transition,
-                // we still need to tell the client to make its windows visible so they get drawn.
-                // Otherwise, we will wait on performing the transition until all windows have been
-                // drawn, they never will be, and we are sad.
-                wtoken.setClientHidden(false);
-
-                wtoken.requestUpdateWallpaperIfNeeded();
-
-                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
-                wtoken.mAppStopped = false;
-
-                mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded();
-            }
-
-            // If we are preparing an app transition, then delay changing
-            // the visibility of this token until we execute that transition.
-            if (wtoken.okToAnimate() && appTransition.isTransitionSet()) {
-                wtoken.inPendingTransaction = true;
-                if (visible) {
-                    displayContent.mOpeningApps.add(wtoken);
-                    wtoken.mEnteringAnimation = true;
-                } else {
-                    displayContent.mClosingApps.add(wtoken);
-                    wtoken.mEnteringAnimation = false;
-                }
-                if (appTransition.getAppTransition()
-                        == WindowManager.TRANSIT_TASK_OPEN_BEHIND) {
-                    // We're launchingBehind, add the launching activity to mOpeningApps.
-                    final WindowState win = mContainer.getDisplayContent().findFocusedWindow();
-                    if (win != null) {
-                        final AppWindowToken focusedToken = win.mAppToken;
-                        if (focusedToken != null) {
-                            if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
-                                    + " adding " + focusedToken + " to mOpeningApps");
-                            // Force animation to be loaded.
-                            focusedToken.setHidden(true);
-                            displayContent.mOpeningApps.add(focusedToken);
-                        }
-                    }
-                }
-                return;
-            }
-
-            wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
-            wtoken.updateReportedVisibilityLocked();
-        }
-    }
-
-    /**
-     * Notifies that we launched an app that might be visible or not visible depending on what kind
-     * of Keyguard flags it's going to set on its windows.
-     */
-    public void notifyUnknownVisibilityLaunched() {
-        synchronized (mGlobalLock) {
-            if (mContainer != null) {
-                mContainer.getDisplayContent().mUnknownAppVisibilityController.notifyLaunched(
-                        mContainer);
-            }
-        }
-    }
-
-    public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
-            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
-            IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
-            boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
-        synchronized (mGlobalLock) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
-                    + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
-                    + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
-                    + " allowTaskSnapshot=" + allowTaskSnapshot);
-
-            if (mContainer == null) {
-                Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
-                return false;
-            }
-
-            // If the display is frozen, we won't do anything until the actual window is
-            // displayed so there is no reason to put in the starting window.
-            if (!mContainer.okToDisplay()) {
-                return false;
-            }
-
-            if (mContainer.startingData != null) {
-                return false;
-            }
-
-            final WindowState mainWin = mContainer.findMainWindow();
-            if (mainWin != null && mainWin.mWinAnimator.getShown()) {
-                // App already has a visible window...why would you want a starting window?
-                return false;
-            }
-
-            final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
-                    mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
-                    false /* restoreFromDisk */, false /* reducedResolution */);
-            final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
-                    allowTaskSnapshot, activityCreated, fromRecents, snapshot);
-
-            if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
-                return createSnapshot(snapshot);
-            }
-
-            // If this is a translucent window, then don't show a starting window -- the current
-            // effect (a full-screen opaque starting window that fades away to the real contents
-            // when it is ready) does not work for this.
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
-                    + Integer.toHexString(theme));
-            if (theme != 0) {
-                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
-                        com.android.internal.R.styleable.Window, mService.mCurrentUserId);
-                if (ent == null) {
-                    // Whoops!  App doesn't exist. Um. Okay. We'll just pretend like we didn't
-                    // see that.
-                    return false;
-                }
-                final boolean windowIsTranslucent = ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowIsTranslucent, false);
-                final boolean windowIsFloating = ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowIsFloating, false);
-                final boolean windowShowWallpaper = ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowShowWallpaper, false);
-                final boolean windowDisableStarting = ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowDisablePreview, false);
-                if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
-                        + " Floating=" + windowIsFloating
-                        + " ShowWallpaper=" + windowShowWallpaper);
-                if (windowIsTranslucent) {
-                    return false;
-                }
-                if (windowIsFloating || windowDisableStarting) {
-                    return false;
-                }
-                if (windowShowWallpaper) {
-                    if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
-                            == null) {
-                        // If this theme is requesting a wallpaper, and the wallpaper
-                        // is not currently visible, then this effectively serves as
-                        // an opaque window and our starting window transition animation
-                        // can still work.  We just need to make sure the starting window
-                        // is also showing the wallpaper.
-                        windowFlags |= FLAG_SHOW_WALLPAPER;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-
-            if (mContainer.transferStartingWindow(transferFrom)) {
-                return true;
-            }
-
-            // There is no existing starting window, and we don't want to create a splash screen, so
-            // that's it!
-            if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
-                return false;
-            }
-
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
-            mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
-                    compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
-                    mContainer.getMergedOverrideConfiguration());
-            scheduleAddStartingWindow();
-        }
-        return true;
-    }
-
-    private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
-            boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
-            TaskSnapshot snapshot) {
-        if (mContainer.getDisplayContent().mAppTransition.getAppTransition()
-                == TRANSIT_DOCK_TASK_FROM_RECENTS) {
-            // TODO(b/34099271): Remove this statement to add back the starting window and figure
-            // out why it causes flickering, the starting window appears over the thumbnail while
-            // the docked from recents transition occurs
-            return STARTING_WINDOW_TYPE_NONE;
-        } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
-            return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
-        } else if (taskSwitch && allowTaskSnapshot) {
-            return snapshot == null ? STARTING_WINDOW_TYPE_NONE
-                    : snapshotOrientationSameAsTask(snapshot) || fromRecents
-                            ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
-        } else {
-            return STARTING_WINDOW_TYPE_NONE;
-        }
-    }
-
-    void scheduleAddStartingWindow() {
-        // Note: we really want to do sendMessageAtFrontOfQueue() because we
-        // want to process the message ASAP, before any other queued
-        // messages.
-        if (!mService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
-            mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
-        }
-    }
-
-    private boolean createSnapshot(TaskSnapshot snapshot) {
-        if (snapshot == null) {
-            return false;
-        }
-
-        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
-        mContainer.startingData = new SnapshotStartingData(mService, snapshot);
-        scheduleAddStartingWindow();
-        return true;
-    }
-
-    private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {
-        if (snapshot == null) {
-            return false;
-        }
-        return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();
-    }
-
-    public void removeStartingWindow() {
-        synchronized (mGlobalLock) {
-            if (mContainer.startingWindow == null) {
-                if (mContainer.startingData != null) {
-                    // Starting window has not been added yet, but it is scheduled to be added.
-                    // Go ahead and cancel the request.
-                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                            "Clearing startingData for token=" + mContainer);
-                    mContainer.startingData = null;
-                }
-                return;
-            }
-
-            final StartingSurface surface;
-            if (mContainer.startingData != null) {
-                surface = mContainer.startingSurface;
-                mContainer.startingData = null;
-                mContainer.startingSurface = null;
-                mContainer.startingWindow = null;
-                mContainer.startingDisplayed = false;
-                if (surface == null) {
-                    if (DEBUG_STARTING_WINDOW) {
-                        Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
-                                + "remove");
-                    }
-                    return;
-                }
-            } else {
-                if (DEBUG_STARTING_WINDOW) {
-                    Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
-                            + mContainer);
-                }
-                return;
-            }
-
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
-                    + " startingWindow=" + mContainer.startingWindow
-                    + " startingView=" + mContainer.startingSurface
-                    + " Callers=" + Debug.getCallers(5));
-
-            // Use the same thread to remove the window as we used to add it, as otherwise we end up
-            // with things in the view hierarchy being called from different threads.
-            mService.mAnimationHandler.post(() -> {
-                if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
-                try {
-                    surface.remove();
-                } catch (Exception e) {
-                    Slog.w(TAG_WM, "Exception when removing starting window", e);
-                }
-            });
-        }
-    }
-
-    public void pauseKeyDispatching() {
-        synchronized (mGlobalLock) {
-            if (mContainer != null) {
-                mContainer.getDisplayContent().getInputMonitor().pauseDispatchingLw(mContainer);
-            }
-        }
-    }
-
-    public void resumeKeyDispatching() {
-        synchronized (mGlobalLock) {
-            if (mContainer != null) {
-                mContainer.getDisplayContent().getInputMonitor().resumeDispatchingLw(mContainer);
-            }
-        }
-    }
-
-    public void notifyAppResumed(boolean wasStopped) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
-                return;
-            }
-            mContainer.notifyAppResumed(wasStopped);
-        }
-    }
-
-    public void notifyAppStopping() {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: "
-                        + mToken);
-                return;
-            }
-            mContainer.detachChildren();
-        }
-    }
-
-    public void notifyAppStopped() {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
-                        + mToken);
-                return;
-            }
-            mContainer.notifyAppStopped();
-        }
-    }
-
-    public void startFreezingScreen(int configChanges) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM,
-                        "Attempted to freeze screen with non-existing app token: " + mContainer);
-                return;
-            }
-
-            if (configChanges == 0 && mContainer.okToDisplay()) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
-                return;
-            }
-
-            mContainer.startFreezingScreen();
-        }
-    }
-
-    public void stopFreezingScreen(boolean force) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                return;
-            }
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
-                    + mContainer.isHidden() + " freezing=" + mContainer.isFreezingScreen());
-            mContainer.stopFreezingScreen(true, force);
-        }
-    }
-
-    public void registerRemoteAnimations(RemoteAnimationDefinition definition) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app"
-                        + " token: " + mToken);
-                return;
-            }
-            mContainer.registerRemoteAnimations(definition);
-        }
-    }
-
-    void reportStartingWindowDrawn() {
-        mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
-    }
-
-    void reportWindowsDrawn() {
-        mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
-    }
-
-    void reportWindowsNotDrawn() {
-        mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_NOTDRAWN));
-    }
-
-    void reportWindowsVisible() {
-        mHandler.post(mOnWindowsVisible);
-    }
-
-    void reportWindowsGone() {
-        mHandler.post(mOnWindowsGone);
-    }
-
-    /** Calls directly into activity manager so window manager lock shouldn't held. */
-    boolean keyDispatchingTimedOut(String reason, int windowPid) {
-        return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
-    }
-
-    /**
-     * Apply override app transition base on options & animation type.
-     */
-    public void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) {
-        synchronized (mGlobalLock) {
-            final int animationType = pendingOptions.getAnimationType();
-            final DisplayContent displayContent = mContainer.getDisplayContent();
-            switch (animationType) {
-                case ANIM_CUSTOM:
-                    displayContent.mAppTransition.overridePendingAppTransition(
-                            pendingOptions.getPackageName(),
-                            pendingOptions.getCustomEnterResId(),
-                            pendingOptions.getCustomExitResId(),
-                            pendingOptions.getOnAnimationStartListener());
-                    break;
-                case ANIM_CLIP_REVEAL:
-                    displayContent.mAppTransition.overridePendingAppTransitionClipReveal(
-                            pendingOptions.getStartX(), pendingOptions.getStartY(),
-                            pendingOptions.getWidth(), pendingOptions.getHeight());
-                    if (intent.getSourceBounds() == null) {
-                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
-                                pendingOptions.getStartY(),
-                                pendingOptions.getStartX() + pendingOptions.getWidth(),
-                                pendingOptions.getStartY() + pendingOptions.getHeight()));
-                    }
-                    break;
-                case ANIM_SCALE_UP:
-                    displayContent.mAppTransition.overridePendingAppTransitionScaleUp(
-                            pendingOptions.getStartX(), pendingOptions.getStartY(),
-                            pendingOptions.getWidth(), pendingOptions.getHeight());
-                    if (intent.getSourceBounds() == null) {
-                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
-                                pendingOptions.getStartY(),
-                                pendingOptions.getStartX() + pendingOptions.getWidth(),
-                                pendingOptions.getStartY() + pendingOptions.getHeight()));
-                    }
-                    break;
-                case ANIM_THUMBNAIL_SCALE_UP:
-                case ANIM_THUMBNAIL_SCALE_DOWN:
-                    final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP);
-                    final GraphicBuffer buffer = pendingOptions.getThumbnail();
-                    displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer,
-                            pendingOptions.getStartX(), pendingOptions.getStartY(),
-                            pendingOptions.getOnAnimationStartListener(),
-                            scaleUp);
-                    if (intent.getSourceBounds() == null && buffer != null) {
-                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
-                                pendingOptions.getStartY(),
-                                pendingOptions.getStartX() + buffer.getWidth(),
-                                pendingOptions.getStartY() + buffer.getHeight()));
-                    }
-                    break;
-                case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
-                case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
-                    final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
-                    final IAppTransitionAnimationSpecsFuture specsFuture =
-                            pendingOptions.getSpecsFuture();
-                    if (specsFuture != null) {
-                        displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture(
-                                specsFuture, pendingOptions.getOnAnimationStartListener(),
-                                animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
-                    } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
-                            && specs != null) {
-                        displayContent.mAppTransition.overridePendingAppTransitionMultiThumb(
-                                specs, pendingOptions.getOnAnimationStartListener(),
-                                pendingOptions.getAnimationFinishedListener(), false);
-                    } else {
-                        displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb(
-                                pendingOptions.getThumbnail(),
-                                pendingOptions.getStartX(), pendingOptions.getStartY(),
-                                pendingOptions.getWidth(), pendingOptions.getHeight(),
-                                pendingOptions.getOnAnimationStartListener(),
-                                (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP));
-                        if (intent.getSourceBounds() == null) {
-                            intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
-                                    pendingOptions.getStartY(),
-                                    pendingOptions.getStartX() + pendingOptions.getWidth(),
-                                    pendingOptions.getStartY() + pendingOptions.getHeight()));
-                        }
-                    }
-                    break;
-                case ANIM_OPEN_CROSS_PROFILE_APPS:
-                    displayContent.mAppTransition
-                            .overridePendingAppTransitionStartCrossProfileApps();
-                    break;
-                case ANIM_REMOTE_ANIMATION:
-                    displayContent.mAppTransition.overridePendingAppTransitionRemote(
-                            pendingOptions.getRemoteAnimationAdapter());
-                    break;
-                case ANIM_NONE:
-                    break;
-                default:
-                    Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Notifies AWT that this app is waiting to pause in order to determine if it will enter PIP.
-     * This information helps AWT know that the app is in the process of pausing before it gets the
-     * signal on the WM side.
-     */
-    public void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                return;
-            }
-
-            mContainer.setWillCloseOrEnterPip(willCloseOrEnterPip);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "AppWindowContainerController{"
-                + " token=" + mToken
-                + " mContainer=" + mContainer
-                + " mListener=" + mListener
-                + "}";
-    }
-}
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerListener.java b/services/core/java/com/android/server/wm/AppWindowContainerListener.java
deleted file mode 100644
index ad27669..0000000
--- a/services/core/java/com/android/server/wm/AppWindowContainerListener.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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;
-
-/** Interface used by the creator of the controller to listen to changes with the container. */
-public interface AppWindowContainerListener extends WindowContainerListener {
-    /** Called when the windows associated app window container drawn state changes. */
-    void onWindowsDrawn(boolean drawn, long timestamp);
-    /** Called when the windows associated app window container are visible. */
-    void onWindowsVisible();
-    /** Called when the windows associated app window container are no longer visible. */
-    void onWindowsGone();
-
-    /**
-     * Called when the starting window for this container is drawn.
-     */
-    void onStartingWindowDrawn(long timestamp);
-
-    /**
-     * Called when the key dispatching to a window associated with the app window container
-     * timed-out.
-     *
-     * @param reason The reason for the key dispatching time out.
-     * @param windowPid The pid of the window key dispatching timed out on.
-     * @return True if input dispatching should be aborted.
-     */
-    boolean keyDispatchingTimedOut(String reason, int windowPid);
-}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 6d402f2..a7c9a46 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -28,10 +28,12 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
 import static android.view.WindowManager.TRANSIT_UNSET;
 import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
 
@@ -81,7 +83,9 @@
 
 import android.annotation.CallSuper;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.content.ComponentName;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.GraphicBuffer;
 import android.graphics.Point;
@@ -90,6 +94,7 @@
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.Trace;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
@@ -106,6 +111,8 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
+import com.android.server.AttributeCache;
+import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 import com.android.server.wm.WindowManagerService.H;
 
@@ -121,7 +128,8 @@
  * Version of WindowToken that is specifically for a particular application (or
  * really activity) that is displaying windows.
  */
-class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener {
+class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener,
+        ConfigurationContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
 
     /**
@@ -226,6 +234,9 @@
 
     private Task mLastParent;
 
+    // TODO: Remove after unification
+    ActivityRecord mActivityRecord;
+
     /**
      * See {@link #canTurnScreenOn()}
      */
@@ -273,14 +284,20 @@
     /** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */
     boolean mNeedsAnimationBoundsLayer;
 
+    private static final int STARTING_WINDOW_TYPE_NONE = 0;
+    private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
+    private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
+
     AppWindowToken(WindowManagerService service, IApplicationToken token,
             ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
             long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
             int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
             boolean launchTaskBehind, boolean alwaysFocusable,
-            AppWindowContainerController controller) {
+            ActivityRecord activityRecord) {
         this(service, token, activityComponent, voiceInteraction, dc, fullscreen);
-        setController(controller);
+        // TODO: remove after unification
+        mActivityRecord = activityRecord;
+        mActivityRecord.registerConfigurationChangeListener(this);
         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
         mShowForAllUsers = showForAllUsers;
         mTargetSdk = targetSdk;
@@ -320,9 +337,7 @@
             // it from behind the starting window, so there is no need for it to also be doing its
             // own stuff.
             win.cancelAnimation();
-            if (getController() != null) {
-                getController().removeStartingWindow();
-            }
+            removeStartingWindow();
         }
         updateReportedVisibilityLocked();
     }
@@ -360,16 +375,9 @@
         }
         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
                 + numInteresting + " visible=" + numVisible);
-        final AppWindowContainerController controller = getController();
         if (nowDrawn != reportedDrawn) {
-            if (nowDrawn) {
-                if (controller != null) {
-                    controller.reportWindowsDrawn();
-                }
-            } else {
-                if (controller != null) {
-                    controller.reportWindowsNotDrawn();
-                }
+            if (mActivityRecord != null) {
+                mActivityRecord.onWindowsDrawn(nowDrawn, SystemClock.uptimeMillis());
             }
             reportedDrawn = nowDrawn;
         }
@@ -377,16 +385,36 @@
             if (DEBUG_VISIBILITY) Slog.v(TAG,
                     "Visibility changed in " + this + ": vis=" + nowVisible);
             reportedVisible = nowVisible;
-            if (controller != null) {
+            if (mActivityRecord != null) {
                 if (nowVisible) {
-                    controller.reportWindowsVisible();
+                    onWindowsVisible();
                 } else {
-                    controller.reportWindowsGone();
+                    onWindowsGone();
                 }
             }
         }
     }
 
+    private void onWindowsGone() {
+        if (mActivityRecord == null) {
+            return;
+        }
+        if (DEBUG_VISIBILITY) {
+            Slog.v(TAG_WM, "Reporting gone in " + mActivityRecord.appToken);
+        }
+        mActivityRecord.onWindowsGone();
+    }
+
+    private void onWindowsVisible() {
+        if (mActivityRecord == null) {
+            return;
+        }
+        if (DEBUG_VISIBILITY) {
+            Slog.v(TAG_WM, "Reporting visible in " + mActivityRecord.appToken);
+        }
+        mActivityRecord.onWindowsVisible();
+    }
+
     boolean isClientHidden() {
         return mClientHidden;
     }
@@ -401,7 +429,116 @@
         sendAppVisibilityToClients();
     }
 
-    boolean setVisibility(WindowManager.LayoutParams lp,
+    void setVisibility(boolean visible, boolean deferHidingClient) {
+        final AppTransition appTransition = getDisplayContent().mAppTransition;
+
+        // Don't set visibility to false if we were already not visible. This prevents WM from
+        // adding the app to the closing app list which doesn't make sense for something that is
+        // already not visible. However, set visibility to true even if we are already visible.
+        // This makes sure the app is added to the opening apps list so that the right
+        // transition can be selected.
+        // TODO: Probably a good idea to separate the concept of opening/closing apps from the
+        // concept of setting visibility...
+        if (!visible && hiddenRequested) {
+
+            if (!deferHidingClient && mDeferHidingClient) {
+                // We previously deferred telling the client to hide itself when visibility was
+                // initially set to false. Now we would like it to hide, so go ahead and set it.
+                mDeferHidingClient = deferHidingClient;
+                setClientHidden(true);
+            }
+            return;
+        }
+
+        if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
+            Slog.v(TAG_WM, "setAppVisibility("
+                    + appToken + ", visible=" + visible + "): " + appTransition
+                    + " hidden=" + isHidden() + " hiddenRequested="
+                    + hiddenRequested + " Callers=" + Debug.getCallers(6));
+        }
+
+        final DisplayContent displayContent = getDisplayContent();
+        displayContent.mOpeningApps.remove(this);
+        displayContent.mClosingApps.remove(this);
+        waitingToShow = false;
+        hiddenRequested = !visible;
+        mDeferHidingClient = deferHidingClient;
+
+        if (!visible) {
+            // If the app is dead while it was visible, we kept its dead window on screen.
+            // Now that the app is going invisible, we can remove it. It will be restarted
+            // if made visible again.
+            removeDeadWindows();
+        } else {
+            if (!appTransition.isTransitionSet()
+                    && appTransition.isReady()) {
+                // Add the app mOpeningApps if transition is unset but ready. This means
+                // we're doing a screen freeze, and the unfreeze will wait for all opening
+                // apps to be ready.
+                displayContent.mOpeningApps.add(this);
+            }
+            startingMoved = false;
+            // If the token is currently hidden (should be the common case), or has been
+            // stopped, then we need to set up to wait for its windows to be ready.
+            if (isHidden() || mAppStopped) {
+                clearAllDrawn();
+
+                // If the app was already visible, don't reset the waitingToShow state.
+                if (isHidden()) {
+                    waitingToShow = true;
+                }
+            }
+
+            // In the case where we are making an app visible but holding off for a transition,
+            // we still need to tell the client to make its windows visible so they get drawn.
+            // Otherwise, we will wait on performing the transition until all windows have been
+            // drawn, they never will be, and we are sad.
+            setClientHidden(false);
+
+            requestUpdateWallpaperIfNeeded();
+
+            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + this);
+            mAppStopped = false;
+
+            transferStartingWindowFromHiddenAboveTokenIfNeeded();
+        }
+
+        // If we are preparing an app transition, then delay changing
+        // the visibility of this token until we execute that transition.
+        if (okToAnimate() && appTransition.isTransitionSet()) {
+            inPendingTransaction = true;
+            if (visible) {
+                displayContent.mOpeningApps.add(this);
+                mEnteringAnimation = true;
+            } else {
+                displayContent.mClosingApps.add(this);
+                mEnteringAnimation = false;
+            }
+            if (appTransition.getAppTransition()
+                    == WindowManager.TRANSIT_TASK_OPEN_BEHIND) {
+                // We're launchingBehind, add the launching activity to mOpeningApps.
+                final WindowState win = getDisplayContent().findFocusedWindow();
+                if (win != null) {
+                    final AppWindowToken focusedToken = win.mAppToken;
+                    if (focusedToken != null) {
+                        if (DEBUG_APP_TRANSITIONS) {
+                            Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
+                                    + " adding " + focusedToken + " to mOpeningApps");
+                        }
+                        // Force animation to be loaded.
+                        focusedToken.setHidden(true);
+                        displayContent.mOpeningApps.add(focusedToken);
+                    }
+                }
+            }
+            return;
+        }
+
+        commitVisibility(null, visible, TRANSIT_UNSET, true, mVoiceInteraction);
+        updateReportedVisibilityLocked();
+    }
+
+    boolean commitVisibility(WindowManager.LayoutParams lp,
             boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
 
         boolean delayed = false;
@@ -461,8 +598,10 @@
                 forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true);
             }
 
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this
-                    + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested);
+            if (DEBUG_APP_TRANSITIONS) {
+                Slog.v(TAG_WM, "commitVisibility: " + this
+                        + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested);
+            }
 
             if (changed) {
                 getDisplayContent().getInputMonitor().setUpdateInputWindowsNeededLw();
@@ -499,10 +638,9 @@
                 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
             }
 
-            // If we're becoming visible, immediately change client visibility as well although it
-            // usually gets changed in AppWindowContainerController.setVisibility already. However,
-            // there seem to be some edge cases where we change our visibility but client visibility
-            // never gets updated.
+            // If we're becoming visible, immediately change client visibility as well. there seem
+            // to be some edge cases where we change our visibility but client visibility never gets
+            // updated.
             // If we're becoming invisible, update the client visibility if we are not running an
             // animation. Otherwise, we'll update client visibility in onAnimationFinished.
             if (visible || !isReallyAnimating()) {
@@ -596,11 +734,6 @@
         return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable;
     }
 
-    AppWindowContainerController getController() {
-        final WindowContainerController controller = super.getController();
-        return controller != null ? (AppWindowContainerController) controller : null;
-    }
-
     @Override
     boolean isVisible() {
         // If the app token isn't hidden then it is considered visible and there is no need to check
@@ -637,7 +770,7 @@
 
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
 
-        boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
+        boolean delayed = commitVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
 
         getDisplayContent().mOpeningApps.remove(this);
         getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
@@ -656,8 +789,8 @@
         if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
                 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
 
-        if (startingData != null && getController() != null) {
-            getController().removeStartingWindow();
+        if (startingData != null) {
+            removeStartingWindow();
         }
 
         // If this window was animating, then we need to ensure that the app transition notifies
@@ -768,9 +901,7 @@
         mAppStopped = true;
         destroySurfaces();
         // Remove any starting window that was added for this app if they are still around.
-        if (getController() != null) {
-            getController().removeStartingWindow();
-        }
+        removeStartingWindow();
     }
 
     void clearAllDrawn() {
@@ -826,9 +957,7 @@
         // TODO: Something smells about the code below...Is there a better way?
         if (startingWindow == win) {
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
-            if (getController() != null) {
-                getController().removeStartingWindow();
-            }
+            removeStartingWindow();
         } else if (mChildren.size() == 0) {
             // If this is the last window and we had requested a starting transition window,
             // well there is no point now.
@@ -845,9 +974,7 @@
             // we need to get rid of the starting transition.
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
                     + win);
-            if (getController() != null) {
-                getController().removeStartingWindow();
-            }
+            removeStartingWindow();
         }
     }
 
@@ -1021,6 +1148,10 @@
 
     @Override
     void removeChild(WindowState child) {
+        if (!mChildren.contains(child)) {
+            // This can be true when testing.
+            return;
+        }
         super.removeChild(child);
         checkKeyguardFlagsChanged();
         updateLetterboxSurface(child);
@@ -1042,6 +1173,20 @@
         }
     }
 
+    void reparent(TaskWindowContainerController taskController, int position) {
+        if (DEBUG_ADD_REMOVE) {
+            Slog.i(TAG_WM, "reparent: moving app token=" + this
+                    + " to task=" + taskController + " at " + position);
+        }
+        final Task task = taskController.mContainer;
+        if (task == null) {
+            throw new IllegalArgumentException("reparent: could not find task="
+                    + taskController);
+        }
+        reparent(task, position);
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+    }
+
     void reparent(Task task, int position) {
         final Task currentTask = getTask();
         if (task == currentTask) {
@@ -1300,9 +1445,7 @@
             startingData = fromToken.startingData;
             fromToken.startingData = null;
             fromToken.startingMoved = true;
-            if (getController() != null) {
-                getController().scheduleAddStartingWindow();
-            }
+            scheduleAddStartingWindow();
             return true;
         }
 
@@ -1471,6 +1614,10 @@
         }
     }
 
+    boolean keyDispatchingTimedOut(String reason, int windowPid) {
+        return mActivityRecord != null && mActivityRecord.keyDispatchingTimedOut(reason, windowPid);
+    }
+
     /**
      * Updated this app token tracking states for interesting and drawn windows based on the window.
      *
@@ -1533,8 +1680,8 @@
                     }
                 }
             } else if (w.isDrawnLw()) {
-                if (getController() != null) {
-                    getController().reportStartingWindowDrawn();
+                if (mActivityRecord != null) {
+                    mActivityRecord.onStartingWindowDrawn(SystemClock.uptimeMillis());
                 }
                 startingDisplayed = true;
             }
@@ -1601,6 +1748,266 @@
         return this;
     }
 
+    boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
+            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
+            IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
+            boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
+        // If the display is frozen, we won't do anything until the actual window is
+        // displayed so there is no reason to put in the starting window.
+        if (!okToDisplay()) {
+            return false;
+        }
+
+        if (startingData != null) {
+            return false;
+        }
+
+        final WindowState mainWin = findMainWindow();
+        if (mainWin != null && mainWin.mWinAnimator.getShown()) {
+            // App already has a visible window...why would you want a starting window?
+            return false;
+        }
+
+        final ActivityManager.TaskSnapshot snapshot =
+                mService.mTaskSnapshotController.getSnapshot(
+                        getTask().mTaskId, getTask().mUserId,
+                        false /* restoreFromDisk */, false /* reducedResolution */);
+        final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
+                allowTaskSnapshot, activityCreated, fromRecents, snapshot);
+
+        if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
+            return createSnapshot(snapshot);
+        }
+
+        // If this is a translucent window, then don't show a starting window -- the current
+        // effect (a full-screen opaque starting window that fades away to the real contents
+        // when it is ready) does not work for this.
+        if (DEBUG_STARTING_WINDOW) {
+            Slog.v(TAG, "Checking theme of starting window: 0x" + Integer.toHexString(theme));
+        }
+        if (theme != 0) {
+            AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
+                    com.android.internal.R.styleable.Window,
+                    mService.mCurrentUserId);
+            if (ent == null) {
+                // Whoops!  App doesn't exist. Um. Okay. We'll just pretend like we didn't
+                // see that.
+                return false;
+            }
+            final boolean windowIsTranslucent = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+            final boolean windowIsFloating = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowIsFloating, false);
+            final boolean windowShowWallpaper = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowShowWallpaper, false);
+            final boolean windowDisableStarting = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowDisablePreview, false);
+            if (DEBUG_STARTING_WINDOW) {
+                Slog.v(TAG, "Translucent=" + windowIsTranslucent
+                        + " Floating=" + windowIsFloating
+                        + " ShowWallpaper=" + windowShowWallpaper);
+            }
+            if (windowIsTranslucent) {
+                return false;
+            }
+            if (windowIsFloating || windowDisableStarting) {
+                return false;
+            }
+            if (windowShowWallpaper) {
+                if (getDisplayContent().mWallpaperController
+                        .getWallpaperTarget() == null) {
+                    // If this theme is requesting a wallpaper, and the wallpaper
+                    // is not currently visible, then this effectively serves as
+                    // an opaque window and our starting window transition animation
+                    // can still work.  We just need to make sure the starting window
+                    // is also showing the wallpaper.
+                    windowFlags |= FLAG_SHOW_WALLPAPER;
+                } else {
+                    return false;
+                }
+            }
+
+            if (transferStartingWindow(transferFrom)) {
+                return true;
+            }
+
+            // There is no existing starting window, and we don't want to create a splash screen, so
+            // that's it!
+            if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
+                return false;
+            }
+
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
+            startingData = new SplashScreenStartingData(mService, pkg,
+                    theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
+                    getMergedOverrideConfiguration());
+            scheduleAddStartingWindow();
+        }
+        return true;
+    }
+
+
+    private boolean createSnapshot(ActivityManager.TaskSnapshot snapshot) {
+        if (snapshot == null) {
+            return false;
+        }
+
+        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
+        startingData = new SnapshotStartingData(mService, snapshot);
+        scheduleAddStartingWindow();
+        return true;
+    }
+
+    void scheduleAddStartingWindow() {
+        // Note: we really want to do sendMessageAtFrontOfQueue() because we
+        // want to process the message ASAP, before any other queued
+        // messages.
+        if (!mService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING");
+            mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
+        }
+    }
+
+    private final Runnable mAddStartingWindow = new Runnable() {
+
+        @Override
+        public void run() {
+            synchronized (mService.mGlobalLock) {
+                // There can only be one adding request, silly caller!
+                mService.mAnimationHandler.removeCallbacks(this);
+            }
+
+            if (startingData == null) {
+                // Animation has been canceled... do nothing.
+                if (DEBUG_STARTING_WINDOW) {
+                    Slog.v(TAG, "startingData was nulled out before handling"
+                            + " mAddStartingWindow: " + AppWindowToken.this);
+                }
+                return;
+            }
+
+            if (DEBUG_STARTING_WINDOW) {
+                Slog.v(TAG, "Add starting " + this + ": startingData=" + startingData);
+            }
+
+            WindowManagerPolicy.StartingSurface surface = null;
+            try {
+                surface = startingData.createStartingSurface(AppWindowToken.this);
+            } catch (Exception e) {
+                Slog.w(TAG, "Exception when adding starting window", e);
+            }
+            if (surface != null) {
+                boolean abort = false;
+                synchronized (mService.mGlobalLock) {
+                    // If the window was successfully added, then
+                    // we need to remove it.
+                    if (removed || startingData == null) {
+                        if (DEBUG_STARTING_WINDOW) {
+                            Slog.v(TAG, "Aborted starting " + AppWindowToken.this
+                                    + ": removed=" + removed + " startingData=" + startingData);
+                        }
+                        startingWindow = null;
+                        startingData = null;
+                        abort = true;
+                    } else {
+                        startingSurface = surface;
+                    }
+                    if (DEBUG_STARTING_WINDOW && !abort) {
+                        Slog.v(TAG, "Added starting " + AppWindowToken.this + ": startingWindow="
+                                + startingWindow + " startingView=" + startingSurface);
+                    }
+                }
+                if (abort) {
+                    surface.remove();
+                }
+            } else if (DEBUG_STARTING_WINDOW) {
+                Slog.v(TAG, "Surface returned was null: " + AppWindowToken.this);
+            }
+        }
+    };
+
+    private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
+            boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
+            ActivityManager.TaskSnapshot snapshot) {
+        if (getDisplayContent().mAppTransition.getAppTransition()
+                == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+            // TODO(b/34099271): Remove this statement to add back the starting window and figure
+            // out why it causes flickering, the starting window appears over the thumbnail while
+            // the docked from recents transition occurs
+            return STARTING_WINDOW_TYPE_NONE;
+        } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+            return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+        } else if (taskSwitch && allowTaskSnapshot) {
+            return snapshot == null ? STARTING_WINDOW_TYPE_NONE
+                    : snapshotOrientationSameAsTask(snapshot) || fromRecents
+                            ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+        } else {
+            return STARTING_WINDOW_TYPE_NONE;
+        }
+    }
+
+
+    private boolean snapshotOrientationSameAsTask(ActivityManager.TaskSnapshot snapshot) {
+        if (snapshot == null) {
+            return false;
+        }
+        return getTask().getConfiguration().orientation == snapshot.getOrientation();
+    }
+
+    void removeStartingWindow() {
+        if (startingWindow == null) {
+            if (startingData != null) {
+                // Starting window has not been added yet, but it is scheduled to be added.
+                // Go ahead and cancel the request.
+                if (DEBUG_STARTING_WINDOW) {
+                    Slog.v(TAG_WM, "Clearing startingData for token=" + this);
+                }
+                startingData = null;
+            }
+            return;
+        }
+
+        final WindowManagerPolicy.StartingSurface surface;
+        if (startingData != null) {
+            surface = startingSurface;
+            startingData = null;
+            startingSurface = null;
+            startingWindow = null;
+            startingDisplayed = false;
+            if (surface == null) {
+                if (DEBUG_STARTING_WINDOW) {
+                    Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
+                            + "remove");
+                }
+                return;
+            }
+        } else {
+            if (DEBUG_STARTING_WINDOW) {
+                Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
+                        + this);
+            }
+            return;
+        }
+
+        if (DEBUG_STARTING_WINDOW) {
+            Slog.v(TAG_WM, "Schedule remove starting " + this
+                    + " startingWindow=" + startingWindow
+                    + " startingView=" + startingSurface
+                    + " Callers=" + Debug.getCallers(5));
+        }
+
+        // Use the same thread to remove the window as we used to add it, as otherwise we end up
+        // with things in the view hierarchy being called from different threads.
+        mService.mAnimationHandler.post(() -> {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
+            try {
+                surface.remove();
+            } catch (Exception e) {
+                Slog.w(TAG_WM, "Exception when removing starting window", e);
+            }
+        });
+    }
+
     @Override
     boolean fillsParent() {
         return mFillsParent;
@@ -2215,9 +2622,6 @@
         if (mPendingRelaunchCount != 0) {
             pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
         }
-        if (getController() != null) {
-            pw.print(prefix); pw.print("controller="); pw.println(getController());
-        }
         if (mRemovingFromDisplay) {
             pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
         }
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 9435539..639ed02 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -6,21 +6,16 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-import android.app.ActivityManager;
 import android.os.Debug;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.util.Slog;
+import android.view.InputApplicationHandle;
 import android.view.KeyEvent;
 import android.view.WindowManager;
 
-import android.view.InputApplicationHandle;
 import com.android.server.input.InputManagerService;
-import android.view.InputWindowHandle;
-import android.view.InputChannel;
 
 import java.io.PrintWriter;
-import java.util.HashMap;
 
 final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
     private final WindowManagerService mService;
@@ -112,9 +107,7 @@
         if (appWindowToken != null && appWindowToken.appToken != null) {
             // Notify the activity manager about the timeout and let it decide whether
             // to abort dispatching or keep waiting.
-            final AppWindowContainerController controller = appWindowToken.getController();
-            final boolean abort = controller != null
-                    && controller.keyDispatchingTimedOut(reason,
+            final boolean abort = appWindowToken.keyDispatchingTimedOut(reason,
                     (windowState != null) ? windowState.mSession.mPid : -1);
             if (!abort) {
                 // The activity manager declined to abort dispatching.
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index fd9120a..7f90f1b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -495,9 +495,8 @@
                     if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
                             "RECOVER DESTROY", false);
                     winAnimator.destroySurface();
-                    if (winAnimator.mWin.mAppToken != null
-                            && winAnimator.mWin.mAppToken.getController() != null) {
-                        winAnimator.mWin.mAppToken.getController().removeStartingWindow();
+                    if (winAnimator.mWin.mAppToken != null) {
+                        winAnimator.mWin.mAppToken.removeStartingWindow();
                     }
                 }
 
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index a28b875..8a3dbad 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -1182,7 +1182,7 @@
         mActivities.add(newTop);
 
         // Make sure window manager is aware of the position change.
-        mWindowContainerController.positionChildAtTop(newTop.mWindowContainerController);
+        mWindowContainerController.positionChildAtTop(newTop.mAppWindowToken);
         updateEffectiveIntent();
 
         setFrontOfTask();
@@ -1264,12 +1264,10 @@
             mService.notifyTaskPersisterLocked(this, false);
         }
 
-        // Sync. with window manager
-        final AppWindowContainerController appController = r.getWindowContainerController();
-        if (appController != null) {
+        if (r.mAppWindowToken != null) {
             // Only attempt to move in WM if the child has a controller. It is possible we haven't
             // created controller for the activity we are starting yet.
-            mWindowContainerController.positionChildAt(appController, index);
+            mWindowContainerController.positionChildAt(r.mAppWindowToken, index);
         }
 
         // Make sure the list of display UID whitelists is updated
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index 59b2055..ec64d2e 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -16,6 +16,14 @@
 
 package com.android.server.wm;
 
+import static com.android.server.EventLogTags.WM_TASK_CREATED;
+import static com.android.server.wm.ConfigurationContainer.BOUNDS_CHANGE_NONE;
+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;
+
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Rect;
@@ -24,18 +32,11 @@
 import android.os.Message;
 import android.util.EventLog;
 import android.util.Slog;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.ref.WeakReference;
 
-import static com.android.server.EventLogTags.WM_TASK_CREATED;
-import static com.android.server.wm.ConfigurationContainer.BOUNDS_CHANGE_NONE;
-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.
@@ -103,16 +104,15 @@
         }
     }
 
-    public void positionChildAtTop(AppWindowContainerController childController) {
-        positionChildAt(childController, POSITION_TOP);
+    void positionChildAtTop(AppWindowToken aToken) {
+        positionChildAt(aToken, POSITION_TOP);
     }
 
-    public void positionChildAt(AppWindowContainerController childController, int position) {
+    void positionChildAt(AppWindowToken aToken, int position) {
         synchronized (mService.mGlobalLock) {
-            final AppWindowToken aToken = childController.mContainer;
             if (aToken == null) {
                 Slog.w(TAG_WM,
-                        "Attempted to position of non-existing app : " + childController);
+                        "Attempted to position of non-existing app");
                 return;
             }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
index f12619c..19d18ca 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
@@ -35,7 +35,6 @@
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
-import android.view.IApplicationToken;
 
 import androidx.test.filters.SmallTest;
 
@@ -111,16 +110,9 @@
         final WindowTestUtils.TestAppWindowToken token2 = createTestAppWindowToken(dc2,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
 
-        // Set TestAppWindowContainerController & assign first app token state to be good to go.
-        final WindowTestUtils.TestAppWindowContainerController controller1 =
-                createAppWindowController(dc1, token1.appToken);
-        final WindowTestUtils.TestAppWindowContainerController controller2 =
-                createAppWindowController(dc1, token2.appToken);
-        controller1.setContainer(token1);
         token1.allDrawn = true;
         token1.startingDisplayed = true;
         token1.startingMoved = true;
-        controller2.setContainer(token2);
 
         // Simulate activity resume / finish flows to prepare app transition & set visibility,
         // make sure transition is set as expected for each display.
@@ -132,8 +124,8 @@
         assertEquals(TRANSIT_ACTIVITY_CLOSE, dc2.mAppTransition.getAppTransition());
         // One activity window is visible for resuming & the other activity window is invisible
         // for finishing in different display.
-        controller1.setVisibility(true, false);
-        controller2.setVisibility(false, false);
+        token1.setVisibility(true, false);
+        token2.setVisibility(false, false);
 
         // Make sure each display is in animating stage.
         assertTrue(dc1.mOpeningApps.size() > 0);
@@ -174,16 +166,4 @@
         assertFalse(dc1.mOpeningApps.contains(token1));
     }
 
-    private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
-            DisplayContent dc, IApplicationToken token) {
-        return createAppWindowController(
-                new WindowTestUtils.TestTaskWindowContainerController(
-                        createStackControllerOnDisplay(dc)), token);
-    }
-
-    private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
-            WindowTestUtils.TestTaskWindowContainerController taskController,
-            IApplicationToken token) {
-        return new WindowTestUtils.TestAppWindowContainerController(taskController, token);
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
deleted file mode 100644
index 415b5d9..0000000
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2017 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 static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.res.Configuration.EMPTY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-
-import com.android.server.wm.WindowTestUtils.TestTaskWindowContainerController;
-
-import org.junit.Test;
-
-/**
- * Test class for {@link AppWindowContainerController}.
- *
- * atest FrameworksServicesTests:AppWindowContainerControllerTests
- */
-@FlakyTest(bugId = 74078662)
-@SmallTest
-@Presubmit
-public class AppWindowContainerControllerTests extends WindowTestsBase {
-
-    private final String mPackageName = getInstrumentation().getTargetContext().getPackageName();
-
-    @Test
-    public void testRemoveContainer() {
-        final WindowTestUtils.TestAppWindowContainerController controller =
-                createAppWindowController();
-
-        // Assert token was added to display.
-        assertNotNull(mDisplayContent.getWindowToken(controller.mToken.asBinder()));
-        // Assert that the container was created and linked.
-        assertNotNull(controller.mContainer);
-
-        controller.removeContainer(mDisplayContent.getDisplayId());
-
-        // Assert token was remove from display.
-        assertNull(mDisplayContent.getWindowToken(controller.mToken.asBinder()));
-        // Assert that the container was removed.
-        assertNull(controller.mContainer);
-    }
-
-    @Test
-    public void testSetOrientation() {
-        final WindowTestUtils.TestAppWindowContainerController controller =
-                createAppWindowController();
-
-        // Assert orientation is unspecified to start.
-        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());
-
-        controller.setOrientation(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getDisplayId(),
-                EMPTY /* displayConfig */, false /* freezeScreenIfNeeded */);
-        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, controller.getOrientation());
-
-        controller.removeContainer(mDisplayContent.getDisplayId());
-        // Assert orientation is unspecified to after container is removed.
-        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());
-
-        // Reset display frozen state
-        mWm.mDisplayFrozen = false;
-    }
-
-    private void assertHasStartingWindow(AppWindowToken atoken) {
-        assertNotNull(atoken.startingSurface);
-        assertNotNull(atoken.startingData);
-        assertNotNull(atoken.startingWindow);
-    }
-
-    private void assertNoStartingWindow(AppWindowToken atoken) {
-        assertNull(atoken.startingSurface);
-        assertNull(atoken.startingWindow);
-        assertNull(atoken.startingData);
-        atoken.forAllWindows(windowState -> {
-            assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING);
-        }, true);
-    }
-
-    @Test
-    public void testCreateRemoveStartingWindow() {
-        final WindowTestUtils.TestAppWindowContainerController controller =
-                createAppWindowController();
-        controller.addStartingWindow(mPackageName,
-                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                false, false);
-        waitUntilHandlersIdle();
-        final AppWindowToken atoken = controller.getAppWindowToken(mDisplayContent);
-        assertHasStartingWindow(atoken);
-        controller.removeStartingWindow();
-        waitUntilHandlersIdle();
-        assertNoStartingWindow(atoken);
-    }
-
-    @Test
-    public void testAddRemoveRace() {
-        // There was once a race condition between adding and removing starting windows
-        for (int i = 0; i < 1000; i++) {
-            final WindowTestUtils.TestAppWindowContainerController controller =
-                    createAppWindowController();
-            controller.addStartingWindow(mPackageName,
-                    android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                    false, false);
-            controller.removeStartingWindow();
-            waitUntilHandlersIdle();
-            assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
-
-            controller.getAppWindowToken(
-                    mDisplayContent).getParent().getParent().removeImmediately();
-        }
-    }
-
-    @Test
-    public void testTransferStartingWindow() {
-        final WindowTestUtils.TestAppWindowContainerController controller1 =
-                createAppWindowController();
-        final WindowTestUtils.TestAppWindowContainerController controller2 =
-                createAppWindowController();
-        controller1.addStartingWindow(mPackageName,
-                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                false, false);
-        waitUntilHandlersIdle();
-        controller2.addStartingWindow(mPackageName,
-                android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
-                true, true, false, true, false, false);
-        waitUntilHandlersIdle();
-        assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent));
-        assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent));
-    }
-
-    @Test
-    public void testTransferStartingWindowWhileCreating() {
-        final WindowTestUtils.TestAppWindowContainerController controller1 =
-                createAppWindowController();
-        final WindowTestUtils.TestAppWindowContainerController controller2 =
-                createAppWindowController();
-        ((TestWindowManagerPolicy) mWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> {
-
-            // Surprise, ...! Transfer window in the middle of the creation flow.
-            controller2.addStartingWindow(mPackageName,
-                    android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
-                    true, true, false, true, false, false);
-        });
-        controller1.addStartingWindow(mPackageName,
-                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                false, false);
-        waitUntilHandlersIdle();
-        assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent));
-        assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent));
-    }
-
-    @Test
-    public void testTryTransferStartingWindowFromHiddenAboveToken() {
-
-        // Add two tasks on top of each other.
-        TestTaskWindowContainerController taskController =
-                new WindowTestUtils.TestTaskWindowContainerController(this);
-        final WindowTestUtils.TestAppWindowContainerController controllerTop =
-                createAppWindowController(taskController);
-        final WindowTestUtils.TestAppWindowContainerController controllerBottom =
-                createAppWindowController(taskController);
-
-        // Add a starting window.
-        controllerTop.addStartingWindow(mPackageName,
-                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
-                false, false);
-        waitUntilHandlersIdle();
-
-        // Make the top one invisible, and try transfering the starting window from the top to the
-        // bottom one.
-        controllerTop.setVisibility(false, false);
-        controllerBottom.mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded();
-
-        // Assert that the bottom window now has the starting window.
-        assertNoStartingWindow(controllerTop.getAppWindowToken(mDisplayContent));
-        assertHasStartingWindow(controllerBottom.getAppWindowToken(mDisplayContent));
-    }
-
-    @Test
-    public void testReparent() {
-        final StackWindowController stackController =
-            createStackControllerOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTaskWindowContainerController taskController1 =
-                new WindowTestUtils.TestTaskWindowContainerController(stackController);
-        final WindowTestUtils.TestAppWindowContainerController appWindowController1 =
-                createAppWindowController(taskController1);
-        final WindowTestUtils.TestTaskWindowContainerController taskController2 =
-                new WindowTestUtils.TestTaskWindowContainerController(stackController);
-        final WindowTestUtils.TestAppWindowContainerController appWindowController2 =
-                createAppWindowController(taskController2);
-        final WindowTestUtils.TestTaskWindowContainerController taskController3 =
-                new WindowTestUtils.TestTaskWindowContainerController(stackController);
-
-        try {
-            appWindowController1.reparent(taskController1, 0);
-            fail("Should not be able to reparent to the same parent");
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-
-        try {
-            taskController3.setContainer(null);
-            appWindowController1.reparent(taskController3, 0);
-            fail("Should not be able to reparent to a task that doesn't have a container");
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-
-        // Reparent the app window and ensure that it is moved
-        appWindowController1.reparent(taskController2, 0);
-        assertEquals(taskController2.mContainer, appWindowController1.mContainer.getParent());
-        assertEquals(0, ((WindowTestUtils.TestAppWindowToken) appWindowController1.mContainer)
-                .positionInParent());
-        assertEquals(1, ((WindowTestUtils.TestAppWindowToken) appWindowController2.mContainer)
-                .positionInParent());
-    }
-
-    private WindowTestUtils.TestAppWindowContainerController createAppWindowController() {
-        return createAppWindowController(
-                new WindowTestUtils.TestTaskWindowContainerController(this));
-    }
-
-    private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
-            WindowTestUtils.TestTaskWindowContainerController taskController) {
-        return new WindowTestUtils.TestAppWindowContainerController(taskController);
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 552390d..99abbf7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.content.ActivityInfoProto.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
@@ -31,8 +32,11 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.TRANSIT_UNSET;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -66,6 +70,8 @@
     Task mTask;
     WindowTestUtils.TestAppWindowToken mToken;
 
+    private final String mPackageName = getInstrumentation().getTargetContext().getPackageName();
+
     @Before
     public void setUp() throws Exception {
         mStack = createTaskStackOnDisplay(mDisplayContent);
@@ -251,7 +257,7 @@
                 "closingWindow");
         closingWindow.mAnimatingExit = true;
         closingWindow.mRemoveOnExit = true;
-        closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+        closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
                 true /* performLayout */, false /* isVoiceInteraction */);
 
         // We pretended that we were running an exit animation, but that should have been cleared up
@@ -261,6 +267,124 @@
     }
 
     @Test
+    public void testSetOrientation() {
+        // Assert orientation is unspecified to start.
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mToken.getOrientation());
+
+        mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation());
+
+        mDisplayContent.removeAppToken(mToken.token);
+        // Assert orientation is unset to after container is removed.
+        assertEquals(SCREEN_ORIENTATION_UNSET, mToken.getOrientation());
+
+        // Reset display frozen state
+        mWm.mDisplayFrozen = false;
+    }
+
+    @Test
+    public void testCreateRemoveStartingWindow() {
+        mToken.addStartingWindow(mPackageName,
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+                false, false);
+        waitUntilHandlersIdle();
+        assertHasStartingWindow(mToken);
+        mToken.removeStartingWindow();
+        waitUntilHandlersIdle();
+        assertNoStartingWindow(mToken);
+    }
+
+    @Test
+    public void testAddRemoveRace() {
+        // There was once a race condition between adding and removing starting windows
+        for (int i = 0; i < 1000; i++) {
+            final WindowTestUtils.TestAppWindowToken appToken = createIsolatedTestAppWindowToken();
+
+            appToken.addStartingWindow(mPackageName,
+                    android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+                    false, false);
+            appToken.removeStartingWindow();
+            waitUntilHandlersIdle();
+            assertNoStartingWindow(appToken);
+
+            appToken.getParent().getParent().removeImmediately();
+        }
+    }
+
+    @Test
+    public void testTransferStartingWindow() {
+        final WindowTestUtils.TestAppWindowToken token1 = createIsolatedTestAppWindowToken();
+        final WindowTestUtils.TestAppWindowToken token2 = createIsolatedTestAppWindowToken();
+        token1.addStartingWindow(mPackageName,
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+                false, false);
+        waitUntilHandlersIdle();
+        token2.addStartingWindow(mPackageName,
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, token1.appToken.asBinder(),
+                true, true, false, true, false, false);
+        waitUntilHandlersIdle();
+        assertNoStartingWindow(token1);
+        assertHasStartingWindow(token2);
+    }
+
+    @Test
+    public void testTransferStartingWindowWhileCreating() {
+        final WindowTestUtils.TestAppWindowToken token1 = createIsolatedTestAppWindowToken();
+        final WindowTestUtils.TestAppWindowToken token2 = createIsolatedTestAppWindowToken();
+        ((TestWindowManagerPolicy) token1.mService.mPolicy).setRunnableWhenAddingSplashScreen(
+                () -> {
+                    // Surprise, ...! Transfer window in the middle of the creation flow.
+                    token2.addStartingWindow(mPackageName,
+                            android.R.style.Theme, null, "Test", 0, 0, 0, 0,
+                            token1.appToken.asBinder(), true, true, false,
+                            true, false, false);
+                });
+        token1.addStartingWindow(mPackageName,
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+                false, false);
+        waitUntilHandlersIdle();
+        assertNoStartingWindow(token1);
+        assertHasStartingWindow(token2);
+    }
+
+    private WindowTestUtils.TestAppWindowToken createIsolatedTestAppWindowToken() {
+        final TaskStack taskStack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(taskStack, 0 /* userId */);
+        return createTestAppWindowTokenForGivenTask(task);
+    }
+
+    private WindowTestUtils.TestAppWindowToken createTestAppWindowTokenForGivenTask(Task task) {
+        final WindowTestUtils.TestAppWindowToken appToken =
+                WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+        task.addChild(appToken, 0);
+        waitUntilHandlersIdle();
+        return appToken;
+    }
+
+    @Test
+    public void testTryTransferStartingWindowFromHiddenAboveToken() {
+        // Add two tasks on top of each other.
+        final WindowTestUtils.TestAppWindowToken tokenTop = createIsolatedTestAppWindowToken();
+        final WindowTestUtils.TestAppWindowToken tokenBottom =
+                createTestAppWindowTokenForGivenTask(tokenTop.getTask());
+
+        // Add a starting window.
+        tokenTop.addStartingWindow(mPackageName,
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+                false, false);
+        waitUntilHandlersIdle();
+
+        // Make the top one invisible, and try transferring the starting window from the top to the
+        // bottom one.
+        tokenTop.setVisibility(false, false);
+        tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded();
+
+        // Assert that the bottom window now has the starting window.
+        assertNoStartingWindow(tokenTop);
+        assertHasStartingWindow(tokenBottom);
+    }
+
+    @Test
     public void testTransitionAnimationPositionAndBounds() {
         final Rect stackBounds = new Rect(
                 0/* left */, 0 /* top */, 1000 /* right */, 1000 /* bottom */);
@@ -285,4 +409,19 @@
         assertEquals(expectedY, outPosition.y);
         assertEquals(expectedBounds, outBounds);
     }
+
+    private void assertHasStartingWindow(AppWindowToken atoken) {
+        assertNotNull(atoken.startingSurface);
+        assertNotNull(atoken.startingData);
+        assertNotNull(atoken.startingWindow);
+    }
+
+    private void assertNoStartingWindow(AppWindowToken atoken) {
+        assertNull(atoken.startingSurface);
+        assertNull(atoken.startingWindow);
+        assertNull(atoken.startingData);
+        atoken.forAllWindows(windowState -> {
+            assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING);
+        }, true);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index d2c0765..792e8a6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -48,7 +48,7 @@
     public void testGetClosingApps_closing() {
         final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
                 "closingWindow");
-        closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+        closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
                 true /* performLayout */, false /* isVoiceInteraction */);
         final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
         closingApps.add(closingWindow.mAppToken);
@@ -64,9 +64,9 @@
                 "closingWindow");
         final WindowState openingWindow = createAppWindow(closingWindow.getTask(),
                 FIRST_APPLICATION_WINDOW, "openingWindow");
-        closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+        closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
                 true /* performLayout */, false /* isVoiceInteraction */);
-        openingWindow.mAppToken.setVisibility(null, true /* visible */, TRANSIT_UNSET,
+        openingWindow.mAppToken.commitVisibility(null, true /* visible */, TRANSIT_UNSET,
                 true /* performLayout */, false /* isVoiceInteraction */);
         final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
         closingApps.add(closingWindow.mAppToken);
@@ -79,7 +79,7 @@
     public void testGetClosingApps_skipClosingAppsSnapshotTasks() {
         final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
                 "closingWindow");
-        closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+        closingWindow.mAppToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
                 true /* performLayout */, false /* isVoiceInteraction */);
         final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
         closingApps.add(closingWindow.mAppToken);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
index 1af79e4..bbf508d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -17,8 +17,6 @@
 package com.android.server.wm;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.platform.test.annotations.Presubmit;
@@ -37,6 +35,7 @@
 @Presubmit
 public class TaskWindowContainerControllerTests extends WindowTestsBase {
 
+    /* Comment out due to removal of AppWindowContainerController
     @Test
     public void testRemoveContainer() {
         final WindowTestUtils.TestTaskWindowContainerController taskController =
@@ -49,7 +48,9 @@
         assertNull(taskController.mContainer);
         assertNull(appController.mContainer);
     }
+    */
 
+    /* Comment out due to removal of AppWindowContainerController
     @Test
     public void testRemoveContainer_deferRemoval() {
         final WindowTestUtils.TestTaskWindowContainerController taskController =
@@ -74,6 +75,7 @@
         assertNull(appController.mContainer);
         assertNull(app.getController());
     }
+    */
 
     @Test
     public void testReparent() {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 60c0459..2e47c35 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -18,7 +18,6 @@
 
 import static android.app.AppOpsManager.OP_NONE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -116,12 +115,11 @@
                 ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
                 long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
                 int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
-                boolean launchTaskBehind, boolean alwaysFocusable,
-                AppWindowContainerController controller) {
+                boolean launchTaskBehind, boolean alwaysFocusable, ActivityRecord activityRecord) {
             super(service, token, activityComponent, voiceInteraction, dc,
                     inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
                     orientation, rotationAnimationHint, configChanges, launchTaskBehind,
-                    alwaysFocusable, controller);
+                    alwaysFocusable, activityRecord);
         }
 
         int getWindowsCount() {
@@ -275,45 +273,6 @@
         }
     }
 
-    public static class TestAppWindowContainerController extends AppWindowContainerController {
-
-        final IApplicationToken mToken;
-
-        TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
-            this(taskController, new TestIApplicationToken());
-        }
-
-        TestAppWindowContainerController(TestTaskWindowContainerController taskController,
-                IApplicationToken token) {
-            super(taskController, token, new ComponentName("", "") /* activityComponent */,
-                    null /* listener */, 0 /* index */, SCREEN_ORIENTATION_UNSPECIFIED,
-                    true /* fullscreen */, true /* showForAllUsers */, 0 /* configChanges */,
-                    false /* voiceInteraction */, false /* launchTaskBehind */,
-                    false /* alwaysFocusable */, 0 /* targetSdkVersion */,
-                    0 /* rotationAnimationHint */, 0 /* inputDispatchingTimeoutNanos */,
-                    taskController.mService);
-            mToken = token;
-        }
-
-        @Override
-        AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
-                ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
-                long inputDispatchingTimeoutNanos,
-                boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
-                int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
-                boolean alwaysFocusable, AppWindowContainerController controller) {
-            return new TestAppWindowToken(service, token, activityComponent, voiceInteraction, dc,
-                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
-                    orientation,
-                    rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
-                    controller);
-        }
-
-        AppWindowToken getAppWindowToken(DisplayContent dc) {
-            return (AppWindowToken) dc.getWindowToken(mToken.asBinder());
-        }
-    }
-
     public static class TestIApplicationToken implements IApplicationToken {
 
         private final Binder mBinder = new Binder();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b15b8c1..b6f1817 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -29,10 +29,9 @@
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
 
-import static junit.framework.TestCase.assertNotNull;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 4fc73bc..bad7776 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -233,7 +233,7 @@
                     aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
                     0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
                     mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
-            activity.mWindowContainerController = mock(AppWindowContainerController.class);
+            activity.mAppWindowToken = mock(AppWindowToken.class);
 
             if (mTaskRecord != null) {
                 mTaskRecord.addActivityToTop(activity);
@@ -245,6 +245,7 @@
                     mock(WindowProcessListener.class));
             wpc.setThread(mock(IApplicationThread.class));
             activity.setProcess(wpc);
+            activity.service.mWindowManager.mRoot = mock(RootWindowContainer.class);
             return activity;
         }
     }