Support for WindowContainer controllers and listeners

- WindowContainerController class allows a component outside window manager
to create a window container and communicate directly with it to make
changes. For example, the ActivityRecord class in activity manager uses the
AppWindowContainerController class to create and communicate with
AppWindowToken window container class which is its counterpart on the window
manager side.
- WindowContainerListener interface allows a component outside WM to get
notified of changes to a window container. For example, the ActivityRecord
class in AM implements the AppWindowContainerListener interface to get
notified of changes to the AppWindowToken container.

Bug: 30060889
Test: Existing tests pass and manual testing.
Test: bit FrameworksServicesTests:com.android.server.wm.WindowContainerControllerTests
Test: bit FrameworksServicesTests:com.android.server.wm.WindowContainerTests
Change-Id: I2896bfa46a80b227052528c7da8cf4e56beab4bc
diff --git a/core/java/android/view/IApplicationToken.aidl b/core/java/android/view/IApplicationToken.aidl
index 633b40f..b01c0ef 100644
--- a/core/java/android/view/IApplicationToken.aidl
+++ b/core/java/android/view/IApplicationToken.aidl
@@ -20,10 +20,5 @@
 /** {@hide} */
 interface IApplicationToken
 {
-    void windowsDrawn();
-    void windowsVisible();
-    void windowsGone();
-    boolean keyDispatchingTimedOut(String reason);
-    long getKeyDispatchingTimeout();
 }
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 21875fe..8611d69 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -83,41 +83,9 @@
     void setOverscan(int displayId, int left, int top, int right, int bottom);
 
     // These can only be called when holding the MANAGE_APP_TOKENS permission.
-    void pauseKeyDispatching(IBinder token);
-    void resumeKeyDispatching(IBinder token);
     void setEventDispatching(boolean enabled);
     void addWindowToken(IBinder token, int type, int displayId);
     void removeWindowToken(IBinder token, int displayId);
-    /**
-     * Creates the object representation for the application token in the window manager and adds it
-     * to the specified task Id.
-     *
-     * @param addPos The position to add the token to in the task.
-     * @param token The token to add.
-     * @param taskId The Id of the task we are adding the token to.
-     * @param requestedOrientation Orientation to use.
-     * @param fullscreen True if the application token is fullscreen.
-     * @param showWhenLocked True if the application token should be shown when locked.
-     * @param configChanges Input configuration changes.
-     * @param voiceInteraction True if the token is in voice interaction mode.
-     * @param launchTaskBehind True if the token is been launched from behind.
-     * @param alwaysFocusable True if the app windows are always focusable regardless of the stack
-     *                        they are in.
-     * @param targetSdkVersion The application's target SDK version
-     */
-    void addAppToken(int addPos, IApplicationToken token, int taskId, int requestedOrientation,
-            boolean fullscreen, boolean showWhenLocked, int configChanges, boolean voiceInteraction,
-            boolean launchTaskBehind, boolean alwaysFocusable, int targetSdkVersion,
-            int rotationAnimationHint);
-    /**
-     * Adds an already existing application token on the window manager side to the input task id.
-     *
-     * @param token The token we are adding to the input task Id.
-     * @param taskId The Id of the task we are adding the token to.
-     */
-    void addAppToTask(IBinder token, int taskId);
-    void setAppOrientation(IApplicationToken token, int requestedOrientation);
-    int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
     void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
     int getPendingAppTransition();
@@ -154,20 +122,6 @@
             boolean scaleUp);
     void executeAppTransition();
 
-    /**
-     * Called to set the starting window for the input token and returns true if the starting
-     * window was set for the token.
-     */
-    boolean setAppStartingWindow(IBinder token, String pkg, int theme,
-            in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
-            int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
-    void setAppVisibility(IBinder token, boolean visible);
-    void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface);
-    void notifyAppStopped(IBinder token);
-    void startAppFreezingScreen(IBinder token, int configChanges);
-    void stopAppFreezingScreen(IBinder token, boolean force);
-    void removeAppToken(IBinder token, int displayId);
-
     /** Used by system ui to report that recents has shown itself. */
     void endProlongedAnimations();
 
@@ -315,15 +269,6 @@
     boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver);
 
     /**
-     * Create a screenshot of the applications currently displayed.
-     *
-     * @param frameScale the scale to apply to the frame, only used when width = -1 and
-     *                   height = -1
-     */
-    Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight,
-            float frameScale);
-
-    /**
      * Called by the status bar to notify Views of changes to System UI visiblity.
      */
     oneway void statusBarVisibilityChanged(int visibility);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6625846..9643976 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4737,7 +4737,7 @@
             if (r == null) {
                 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
             }
-            return mWindowManager.getAppOrientation(r.appToken);
+            return r.getRequestedOrientation();
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ef19700..0e4ab96 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -21,17 +21,26 @@
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
+import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.os.Build.VERSION_CODES.HONEYCOMB;
+import static android.os.Process.SYSTEM_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -92,6 +101,8 @@
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+import com.android.server.wm.AppWindowContainerController;
+import com.android.server.wm.AppWindowContainerListener;
 
 import java.io.File;
 import java.io.IOException;
@@ -110,7 +121,7 @@
 /**
  * An entry in the history stack, representing an activity.
  */
-final class ActivityRecord {
+final class ActivityRecord implements AppWindowContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
@@ -135,6 +146,7 @@
 
     final ActivityManagerService service; // owner
     final IApplicationToken.Stub appToken; // window manager token
+    AppWindowContainerController mWindowContainerController;
     final ActivityInfo info; // all about me
     final ApplicationInfo appInfo; // information about activity's app
     final int launchedFromUid; // always the uid who started the activity.
@@ -150,7 +162,7 @@
     final boolean stateNotNeeded; // As per ActivityInfo.flags
     boolean fullscreen; // covers the full screen?
     final boolean noDisplay;  // activity is not displayed?
-    final boolean componentSpecified;  // did caller specify an explicit component?
+    private final boolean componentSpecified;  // did caller specify an explicit component?
     final boolean rootVoiceInteraction;  // was this the root activity of a voice interaction?
 
     static final int APPLICATION_ACTIVITY_TYPE = 0;
@@ -158,18 +170,18 @@
     static final int RECENTS_ACTIVITY_TYPE = 2;
     int mActivityType;
 
-    CharSequence nonLocalizedLabel;  // the label information from the package mgr.
-    int labelRes;           // the label information from the package mgr.
-    int icon;               // resource identifier of activity's icon.
-    int logo;               // resource identifier of activity's logo.
-    int theme;              // resource identifier of activity's theme.
-    int realTheme;          // actual theme resource we will use, never 0.
-    int windowFlags;        // custom window flags for preview window.
+    private CharSequence nonLocalizedLabel;  // the label information from the package mgr.
+    private int labelRes;           // the label information from the package mgr.
+    private int icon;               // resource identifier of activity's icon.
+    private int logo;               // resource identifier of activity's logo.
+    private int theme;              // resource identifier of activity's theme.
+    private int realTheme;          // actual theme resource we will use, never 0.
+    private int windowFlags;        // custom window flags for preview window.
     TaskRecord task;        // the task this is in.
-    long createTime = System.currentTimeMillis();
+    private long createTime = System.currentTimeMillis();
     long displayStartTime;  // when we started launching this activity
     long fullyDrawnStartTime; // when we started launching this activity
-    long startTime;         // last time this activity was started
+    private long startTime;         // last time this activity was started
     long lastVisibleTime;   // last time this activity became visible
     long cpuTimeAtResume;   // the cpu time of host process at the time of resuming activity
     long pauseTime;         // last time we started pausing the activity
@@ -542,70 +554,9 @@
 
     static class Token extends IApplicationToken.Stub {
         private final WeakReference<ActivityRecord> weakActivity;
-        private final ActivityManagerService mService;
 
-        Token(ActivityRecord activity, ActivityManagerService service) {
+        Token(ActivityRecord activity) {
             weakActivity = new WeakReference<>(activity);
-            mService = service;
-        }
-
-        @Override
-        public void windowsDrawn() {
-            synchronized (mService) {
-                ActivityRecord r = tokenToActivityRecordLocked(this);
-                if (r != null) {
-                    r.windowsDrawnLocked();
-                }
-            }
-        }
-
-        @Override
-        public void windowsVisible() {
-            synchronized (mService) {
-                ActivityRecord r = tokenToActivityRecordLocked(this);
-                if (r != null) {
-                    r.windowsVisibleLocked();
-                }
-            }
-        }
-
-        @Override
-        public void windowsGone() {
-            synchronized (mService) {
-                ActivityRecord r = tokenToActivityRecordLocked(this);
-                if (r != null) {
-                    if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
-                    r.nowVisible = false;
-                }
-            }
-        }
-
-        @Override
-        public boolean keyDispatchingTimedOut(String reason) {
-            ActivityRecord r;
-            ActivityRecord anrActivity;
-            ProcessRecord anrApp;
-            synchronized (mService) {
-                r = tokenToActivityRecordLocked(this);
-                if (r == null) {
-                    return false;
-                }
-                anrActivity = r.getWaitingHistoryRecordLocked();
-                anrApp = r.app;
-            }
-            return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
-        }
-
-        @Override
-        public long getKeyDispatchingTimeout() {
-            synchronized (mService) {
-                ActivityRecord r = tokenToActivityRecordLocked(this);
-                if (r == null) {
-                    return 0;
-                }
-                r = r.getWaitingHistoryRecordLocked();
-                return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
-            }
         }
 
         private static ActivityRecord tokenToActivityRecordLocked(Token token) {
@@ -652,7 +603,7 @@
             ActivityStackSupervisor supervisor,
             ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
         service = _service;
-        appToken = new Token(this, service);
+        appToken = new Token(this);
         info = aInfo;
         launchedFromUid = _launchedFromUid;
         launchedFromPackage = _launchedFromPackage;
@@ -700,97 +651,110 @@
             }
         }
 
-        // This starts out true, since the initial state of an activity
-        // is that we have everything, and we shouldn't never consider it
-        // lacking in state to be removed if it dies.
+        // This starts out true, since the initial state of an activity is that we have everything,
+        // and we shouldn't never consider it lacking in state to be removed if it dies.
         haveState = true;
 
-        if (aInfo != null) {
-            // If the class name in the intent doesn't match that of the target, this is
-            // probably an alias. We have to create a new ComponentName object to keep track
-            // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
-            if (aInfo.targetActivity == null
-                    || (aInfo.targetActivity.equals(_intent.getComponent().getClassName())
-                    && (aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
-                    || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP))) {
-                realActivity = _intent.getComponent();
-            } else {
-                realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity);
-            }
-            taskAffinity = aInfo.taskAffinity;
-            stateNotNeeded = (aInfo.flags&
-                    ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
-            appInfo = aInfo.applicationInfo;
-            nonLocalizedLabel = aInfo.nonLocalizedLabel;
-            labelRes = aInfo.labelRes;
-            if (nonLocalizedLabel == null && labelRes == 0) {
-                ApplicationInfo app = aInfo.applicationInfo;
-                nonLocalizedLabel = app.nonLocalizedLabel;
-                labelRes = app.labelRes;
-            }
-            icon = aInfo.getIconResource();
-            logo = aInfo.getLogoResource();
-            theme = aInfo.getThemeResource();
-            realTheme = theme;
-            if (realTheme == 0) {
-                realTheme = aInfo.applicationInfo.targetSdkVersion
-                        < Build.VERSION_CODES.HONEYCOMB
-                        ? android.R.style.Theme
-                        : android.R.style.Theme_Holo;
-            }
-            if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
-                windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED;
-            }
-            if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
-                    && _caller != null
-                    && (aInfo.applicationInfo.uid == Process.SYSTEM_UID
-                            || aInfo.applicationInfo.uid == _caller.info.uid)) {
-                processName = _caller.processName;
-            } else {
-                processName = aInfo.processName;
-            }
-
-            if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            }
-
-            packageName = aInfo.applicationInfo.packageName;
-            launchMode = aInfo.launchMode;
-
-            AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
-                    realTheme, com.android.internal.R.styleable.Window, userId);
-            final boolean translucent = ent != null && (ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowIsTranslucent, false)
-                    || (!ent.array.hasValue(
-                            com.android.internal.R.styleable.Window_windowIsTranslucent)
-                            && ent.array.getBoolean(
-                                    com.android.internal.R.styleable.Window_windowSwipeToDismiss,
-                                            false)));
-            fullscreen = ent != null && !ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowIsFloating, false)
-                    && !translucent;
-            noDisplay = ent != null && ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowNoDisplay, false);
-
-            setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord);
-
-            immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
-
-            requestedVrComponent = (aInfo.requestedVrComponent == null) ?
-                    null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
+        // If the class name in the intent doesn't match that of the target, this is
+        // probably an alias. We have to create a new ComponentName object to keep track
+        // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
+        if (aInfo.targetActivity == null
+                || (aInfo.targetActivity.equals(_intent.getComponent().getClassName())
+                && (aInfo.launchMode == LAUNCH_MULTIPLE
+                || aInfo.launchMode == LAUNCH_SINGLE_TOP))) {
+            realActivity = _intent.getComponent();
         } else {
-            realActivity = null;
-            taskAffinity = null;
-            stateNotNeeded = false;
-            appInfo = null;
-            processName = null;
-            packageName = null;
-            fullscreen = true;
-            noDisplay = false;
-            mActivityType = APPLICATION_ACTIVITY_TYPE;
-            immersive = false;
-            requestedVrComponent  = null;
+            realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity);
         }
+        taskAffinity = aInfo.taskAffinity;
+        stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
+        appInfo = aInfo.applicationInfo;
+        nonLocalizedLabel = aInfo.nonLocalizedLabel;
+        labelRes = aInfo.labelRes;
+        if (nonLocalizedLabel == null && labelRes == 0) {
+            ApplicationInfo app = aInfo.applicationInfo;
+            nonLocalizedLabel = app.nonLocalizedLabel;
+            labelRes = app.labelRes;
+        }
+        icon = aInfo.getIconResource();
+        logo = aInfo.getLogoResource();
+        theme = aInfo.getThemeResource();
+        realTheme = theme;
+        if (realTheme == 0) {
+            realTheme = aInfo.applicationInfo.targetSdkVersion < HONEYCOMB
+                    ? android.R.style.Theme : android.R.style.Theme_Holo;
+        }
+        if ((aInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+            windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        }
+        if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null
+                && (aInfo.applicationInfo.uid == SYSTEM_UID
+                    || aInfo.applicationInfo.uid == _caller.info.uid)) {
+            processName = _caller.processName;
+        } else {
+            processName = aInfo.processName;
+        }
+
+        if ((aInfo.flags & FLAG_EXCLUDE_FROM_RECENTS) != 0) {
+            intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        }
+
+        packageName = aInfo.applicationInfo.packageName;
+        launchMode = aInfo.launchMode;
+
+        AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
+                realTheme, com.android.internal.R.styleable.Window, userId);
+        final boolean translucent = ent != null && (ent.array.getBoolean(
+                com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+                || (!ent.array.hasValue(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent)
+                        && ent.array.getBoolean(
+                                com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+                                        false)));
+        fullscreen = ent != null && !ent.array.getBoolean(
+                com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
+        noDisplay = ent != null && ent.array.getBoolean(
+                com.android.internal.R.styleable.Window_windowNoDisplay, false);
+
+        setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord);
+
+        immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0;
+
+        requestedVrComponent = (aInfo.requestedVrComponent == null) ?
+                null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
+    }
+
+    void createWindowContainer() {
+        if (mWindowContainerController != null) {
+            throw new IllegalArgumentException("Window container=" + mWindowContainerController
+                    + " already created for r=" + this);
+
+        }
+
+        inHistory = true;
+
+        task.updateOverrideConfigurationFromLaunchBounds();
+
+        mWindowContainerController = new AppWindowContainerController(appToken, this, task.taskId,
+                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,
+                ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
+
+        task.addActivityToTop(this);
+
+        onOverrideConfigurationSent();
+    }
+
+    void removeWindowContainer() {
+        mWindowContainerController.removeContainer(getDisplayId());
+    }
+
+    // TODO: Remove once task record is converted to use controller in which case we can use
+    // positionChildAt()
+    void positionWindowContainerAt(int index) {
+        mWindowContainerController.positionAt(task.taskId, index);
     }
 
     private boolean isHomeIntent(Intent intent) {
@@ -890,12 +854,6 @@
         return true;
     }
 
-    void putInHistory() {
-        if (!inHistory) {
-            inHistory = true;
-        }
-    }
-
     void takeFromHistory() {
         if (inHistory) {
             inHistory = false;
@@ -931,7 +889,7 @@
         return (info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY ||
                 info.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS) &&
                 (intent == null ||
-                        (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
+                        (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
     }
 
     boolean isFocusable() {
@@ -1222,14 +1180,14 @@
     void pauseKeyDispatchingLocked() {
         if (!keysPaused) {
             keysPaused = true;
-            service.mWindowManager.pauseKeyDispatching(appToken);
+            mWindowContainerController.pauseKeyDispatching();
         }
     }
 
     void resumeKeyDispatchingLocked() {
         if (keysPaused) {
             keysPaused = false;
-            service.mWindowManager.resumeKeyDispatching(appToken);
+            mWindowContainerController.resumeKeyDispatching();
         }
     }
 
@@ -1277,7 +1235,7 @@
             return null;
         }
 
-        final float scale;
+        float scale = 0;
         if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
 
         // When this flag is set, we currently take the fullscreen screenshot of the activity but
@@ -1288,17 +1246,21 @@
             scale = service.mFullscreenThumbnailScale;
         }
 
-        return service.mWindowManager.screenshotApplications(appToken, DEFAULT_DISPLAY, w, h,
-                scale);
+        return mWindowContainerController.screenshotApplications(getDisplayId(), w, h, scale);
     }
 
+    void setVisibility(boolean visible) {
+        mWindowContainerController.setVisibility(visible);
+    }
+
+    // TODO: Look into merging with #setVisibility()
     void setVisible(boolean newVisible) {
         visible = newVisible;
         if (!visible && mUpdateTaskThumbnailWhenHidden) {
             updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
             mUpdateTaskThumbnailWhenHidden = false;
         }
-        service.mWindowManager.setAppVisibility(appToken, visible);
+        mWindowContainerController.setVisibility(visible);
         final ArrayList<ActivityContainer> containers = mChildContainers;
         for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
             final ActivityContainer container = containers.get(containerNdx);
@@ -1307,6 +1269,14 @@
         mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
     }
 
+    void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
+        mWindowContainerController.notifyAppResumed(wasStopped, allowSavedSurface);
+    }
+
+    void notifyUnknownVisibilityLaunched() {
+        mWindowContainerController.notifyUnknownVisibilityLaunched();
+    }
+
     /**
      * @return true if the input activity should be made visible, ignoring any effect Keyguard
      * might have on the visibility
@@ -1458,6 +1428,7 @@
             service.notifyTaskPersisterLocked(task, false);
         }
         if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle);
+
         if (newIcicle != null) {
             // If icicle is null, this is happening due to a timeout, so we haven't really saved
             // the state.
@@ -1472,7 +1443,7 @@
             stopped = true;
             state = ActivityState.STOPPED;
 
-            service.mWindowManager.notifyAppStopped(appToken);
+            mWindowContainerController.notifyAppStopped();
 
             if (stack.getVisibleBehindActivity() == this) {
                 mStackSupervisor.requestVisibleBehindLocked(this, false /* visible */);
@@ -1536,14 +1507,14 @@
 
     public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
         if (mayFreezeScreenLocked(app)) {
-            service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
+            mWindowContainerController.startFreezingScreen(configChanges);
         }
     }
 
     public void stopFreezingScreenLocked(boolean force) {
         if (force || frozenBeforeDestroy) {
             frozenBeforeDestroy = false;
-            service.mWindowManager.stopAppFreezingScreen(appToken, force);
+            mWindowContainerController.stopFreezingScreen(force);
         }
     }
 
@@ -1617,48 +1588,73 @@
         stack.mLaunchStartTime = 0;
     }
 
-    void windowsDrawnLocked() {
-        mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
-        if (displayStartTime != 0) {
-            reportLaunchTimeLocked(SystemClock.uptimeMillis());
-        }
-        mStackSupervisor.sendWaitingVisibleReportLocked(this);
-        startTime = 0;
-        finishLaunchTickingLocked();
-        if (task != null) {
-            task.hasBeenVisible = true;
-        }
-    }
-
-    void windowsVisibleLocked() {
-        mStackSupervisor.reportActivityVisibleLocked(this);
-        if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
-        if (!nowVisible) {
-            nowVisible = true;
-            lastVisibleTime = SystemClock.uptimeMillis();
-            if (!idle) {
-                // Instead of doing the full stop routine here, let's just hide any activities
-                // we now can, and let them stop when the normal idle happens.
-                mStackSupervisor.processStoppingActivitiesLocked(false);
-            } else {
-                // If this activity was already idle, then we now need to make sure we perform
-                // the full stop of any activities that are waiting to do so. This is because
-                // we won't do that while they are still waiting for this one to become visible.
-                final int size = mStackSupervisor.mWaitingVisibleActivities.size();
-                if (size > 0) {
-                    for (int i = 0; i < size; i++) {
-                        ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
-                        if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
-                    }
-                    mStackSupervisor.mWaitingVisibleActivities.clear();
-                    mStackSupervisor.scheduleIdleLocked();
-                }
+    @Override
+    public void onWindowsDrawn() {
+        synchronized (service) {
+            mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
+            if (displayStartTime != 0) {
+                reportLaunchTimeLocked(SystemClock.uptimeMillis());
             }
-            service.scheduleAppGcsLocked();
+            mStackSupervisor.sendWaitingVisibleReportLocked(this);
+            startTime = 0;
+            finishLaunchTickingLocked();
+            if (task != null) {
+                task.hasBeenVisible = true;
+            }
         }
     }
 
-    ActivityRecord getWaitingHistoryRecordLocked() {
+    @Override
+    public void onWindowsVisible() {
+        synchronized (service) {
+            mStackSupervisor.reportActivityVisibleLocked(this);
+            if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
+            if (!nowVisible) {
+                nowVisible = true;
+                lastVisibleTime = SystemClock.uptimeMillis();
+                if (!idle) {
+                    // Instead of doing the full stop routine here, let's just hide any activities
+                    // we now can, and let them stop when the normal idle happens.
+                    mStackSupervisor.processStoppingActivitiesLocked(false);
+                } else {
+                    // If this activity was already idle, then we now need to make sure we perform
+                    // the full stop of any activities that are waiting to do so. This is because
+                    // we won't do that while they are still waiting for this one to become visible.
+                    final int size = mStackSupervisor.mWaitingVisibleActivities.size();
+                    if (size > 0) {
+                        for (int i = 0; i < size; i++) {
+                            ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
+                            if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
+                        }
+                        mStackSupervisor.mWaitingVisibleActivities.clear();
+                        mStackSupervisor.scheduleIdleLocked();
+                    }
+                }
+                service.scheduleAppGcsLocked();
+            }
+        }
+    }
+
+    @Override
+    public void onWindowsGone() {
+        synchronized (service) {
+            if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
+            nowVisible = false;
+        }
+    }
+
+    @Override
+    public boolean keyDispatchingTimedOut(String reason) {
+        ActivityRecord anrActivity;
+        ProcessRecord anrApp;
+        synchronized (service) {
+            anrActivity = getWaitingHistoryRecordLocked();
+            anrApp = app;
+        }
+        return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
+    }
+
+    private ActivityRecord getWaitingHistoryRecordLocked() {
         // First find the real culprit...  if this activity is waiting for
         // another activity to start or has stopped, then the key dispatching
         // timeout should not be caused by this.
@@ -1800,25 +1796,40 @@
     void showStartingWindow(ActivityRecord prev, boolean createIfNeeded) {
         final CompatibilityInfo compatInfo =
                 service.compatibilityInfoForPackageLocked(info.applicationInfo);
-        final boolean shown = service.mWindowManager.setAppStartingWindow(
-                appToken, packageName, theme, compatInfo, nonLocalizedLabel, labelRes, icon,
-                logo, windowFlags, prev != null ? prev.appToken : null, createIfNeeded);
+        final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
+                compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
+                prev != null ? prev.appToken : null, createIfNeeded);
         if (shown) {
             mStartingWindowState = STARTING_WINDOW_SHOWN;
         }
     }
 
+    void removeOrphanedStartingWindow(boolean behindFullscreenActivity) {
+        if (state == ActivityState.INITIALIZING
+                && mStartingWindowState == STARTING_WINDOW_SHOWN
+                && behindFullscreenActivity) {
+            if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
+            mStartingWindowState = STARTING_WINDOW_REMOVED;
+            mWindowContainerController.removeStartingWindow();
+        }
+    }
+
+    int getRequestedOrientation() {
+        return mWindowContainerController.getOrientation();
+    }
+
     void setRequestedOrientation(int requestedOrientation) {
         if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) {
             // Fixed screen orientation isn't supported when activities aren't in full screen mode.
             return;
         }
 
-        service.mWindowManager.setAppOrientation(appToken, requestedOrientation);
         final int displayId = getDisplayId();
-        final Configuration config = service.mWindowManager.updateOrientationFromAppTokens(
-                mStackSupervisor.getDisplayOverrideConfiguration(displayId),
-                mayFreezeScreenLocked(app) ? appToken : null, displayId);
+        final Configuration displayConfig =
+                mStackSupervisor.getDisplayOverrideConfiguration(displayId);
+
+        final Configuration config = mWindowContainerController.setOrientation(requestedOrientation,
+                displayId, displayConfig, mayFreezeScreenLocked(app));
         if (config != null) {
             frozenBeforeDestroy = true;
             if (!service.updateDisplayOverrideConfigurationLocked(config, this,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index beeadac..ddef339 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -61,8 +61,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
-import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -2046,15 +2044,7 @@
                     continue;
                 }
 
-                if (r.state == ActivityState.INITIALIZING
-                        && r.mStartingWindowState == STARTING_WINDOW_SHOWN
-                        && behindFullscreenActivity) {
-                    if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY,
-                            "Found orphaned starting window " + r);
-                    r.mStartingWindowState = STARTING_WINDOW_REMOVED;
-                    mWindowManager.removeAppStartingWindow(r.appToken);
-                }
-
+                r.removeOrphanedStartingWindow(behindFullscreenActivity);
                 behindFullscreenActivity |= r.fullscreen;
             }
         }
@@ -2287,7 +2277,7 @@
                 // previous should actually be hidden depending on whether the
                 // new one is found to be full-screen or not.
                 if (prev.finishing) {
-                    mWindowManager.setAppVisibility(prev.appToken, false);
+                    prev.setVisibility(false);
                     if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                             "Not waiting for visible to hide: " + prev + ", waitingVisible="
                             + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
@@ -2329,7 +2319,7 @@
                             ? TRANSIT_ACTIVITY_CLOSE
                             : TRANSIT_TASK_CLOSE, false);
                 }
-                mWindowManager.setAppVisibility(prev.appToken, false);
+                prev.setVisibility(false);
             } else {
                 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                         "Prepare open transition: prev=" + prev);
@@ -2384,7 +2374,7 @@
 
             // This activity is now becoming visible.
             if (!next.visible || next.stopped || lastActivityTranslucent) {
-                mWindowManager.setAppVisibility(next.appToken, true);
+                next.setVisibility(true);
             }
 
             // schedule launch ticks to collect information about slow apps.
@@ -2433,7 +2423,7 @@
                     mStackSupervisor.scheduleResumeTopActivities();
                 }
                 if (!next.visible || next.stopped) {
-                    mWindowManager.setAppVisibility(next.appToken, true);
+                    next.setVisibility(true);
                 }
                 next.completeResumeLocked();
                 if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2471,7 +2461,7 @@
 
                 // Well the app will no longer be stopped.
                 // Clear app token stopped state in window manager if needed.
-                mWindowManager.notifyAppResumed(next.appToken, next.stopped, allowSavedSurface);
+                next.notifyAppResumed(next.stopped, allowSavedSurface);
 
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
                         System.identityHashCode(next), next.task.taskId, next.shortComponentName);
@@ -2669,9 +2659,7 @@
                     if (!startIt) {
                         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                                 + task, new RuntimeException("here").fillInStackTrace());
-                        task.addActivityToTop(r);
-                        r.putInHistory();
-                        addConfigOverride(r, task);
+                        r.createWindowContainer();
                         ActivityOptions.abort(options);
                         return;
                     }
@@ -2682,12 +2670,10 @@
             }
         }
 
-        // Place a new activity at top of stack, so it is next to interact
-        // with the user.
+        // Place a new activity at top of stack, so it is next to interact with the user.
 
-        // If we are not placing the new activity frontmost, we do not want
-        // to deliver the onUserLeaving callback to the actual frontmost
-        // activity
+        // If we are not placing the new activity frontmost, we do not want to deliver the
+        // onUserLeaving callback to the actual frontmost activity
         if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
             mStackSupervisor.mUserLeaving = false;
             if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
@@ -2699,10 +2685,9 @@
         // Slot the activity into the history stack and proceed
         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
                 new RuntimeException("here").fillInStackTrace());
-        task.addActivityToTop(r);
+        r.createWindowContainer();
         task.setFrontOfTask();
 
-        r.putInHistory();
         if (!isHomeOrRecentsStack() || numActivities() > 0) {
             // We want to show the starting preview window if we are
             // switching to a new task, or the next activity's process is
@@ -2737,7 +2722,6 @@
                 mWindowManager.prepareAppTransition(transit, keepCurTransition);
                 mNoAnimActivities.remove(r);
             }
-            addConfigOverride(r, task);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -2756,7 +2740,7 @@
             if (r.mLaunchTaskBehind) {
                 // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
                 // tell WindowManager that r is visible even though it is at the back of the stack.
-                mWindowManager.setAppVisibility(r.appToken, true);
+                r.setVisibility(true);
                 ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
             } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
                 // Figure out if we are transitioning from another activity that is
@@ -2780,7 +2764,6 @@
         } else {
             // If this is the first activity, don't do any fancy animations,
             // because there is nothing for it to animate on top of.
-            addConfigOverride(r, task);
             ActivityOptions.abort(options);
         }
     }
@@ -2865,8 +2848,6 @@
                             + " out to new task " + target.task);
                 }
 
-                setAppTask(target, targetTask);
-
                 boolean noOptions = canMoveOptions;
                 final int start = replyChainEnd < 0 ? i : replyChainEnd;
                 for (int srcPos = start; srcPos >= i; --srcPos) {
@@ -2889,8 +2870,6 @@
                             "Pushing next activity " + p + " out to target's task " + target.task);
                     p.setTask(targetTask, null);
                     targetTask.addActivityAtBottom(p);
-
-                    setAppTask(p, targetTask);
                 }
 
                 mWindowManager.moveTaskToBottom(targetTask.taskId);
@@ -3028,7 +3007,6 @@
                                 + " callers=" + Debug.getCallers(3));
                         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
                                 + " from " + srcPos + " in to resetting task " + task);
-                        setAppTask(p, task);
                     }
                     mWindowManager.moveTaskToTop(taskId);
 
@@ -3223,7 +3201,7 @@
                 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                         "Stopping visible=" + r.visible + " for " + r);
                 if (!r.visible) {
-                    mWindowManager.setAppVisibility(r.appToken, false);
+                    r.setVisibility(false);
                 }
                 EventLogTags.writeAmStopActivity(
                         r.userId, System.identityHashCode(r), r.shortComponentName);
@@ -3457,7 +3435,7 @@
                 mWindowManager.prepareAppTransition(transit, false);
 
                 // Tell window manager to prepare for this one to be removed.
-                mWindowManager.setAppVisibility(r.appToken, false);
+                r.setVisibility(false);
 
                 if (mPausingActivity == null) {
                     if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
@@ -3475,7 +3453,7 @@
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
                 if (r.visible) {
                     mWindowManager.prepareAppTransition(transit, false);
-                    mWindowManager.setAppVisibility(r.appToken, false);
+                    r.setVisibility(false);
                     mWindowManager.executeAppTransition();
                     if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) {
                         mStackSupervisor.mWaitingVisibleActivities.add(r);
@@ -3782,7 +3760,7 @@
         r.state = ActivityState.DESTROYED;
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
         r.app = null;
-        mWindowManager.removeAppToken(r.appToken, r.getDisplayId());
+        r.removeWindowContainer();
         final TaskRecord task = r.task;
         if (task != null && task.removeActivity(r)) {
             if (DEBUG_STACK) Slog.i(TAG_STACK,
@@ -4981,17 +4959,6 @@
         }
     }
 
-    void addConfigOverride(ActivityRecord r, TaskRecord task) {
-        task.updateOverrideConfigurationFromLaunchBounds();
-        // TODO: VI deal with activity
-        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
-                r.task.taskId, r.info.screenOrientation, r.fullscreen,
-                (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.info.configChanges,
-                task.voiceSession != null, r.mLaunchTaskBehind, r.isAlwaysFocusable(),
-                r.appInfo.targetSdkVersion, r.mRotationAnimationHint);
-        r.onOverrideConfigurationSent();
-    }
-
     void moveToFrontAndResumeStateIfNeeded(
             ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
         if (!moveToFront) {
@@ -5030,7 +4997,6 @@
                 r.info, r.intent, null, null, true, r.mActivityType);
         r.setTask(task, null);
         task.addActivityToTop(r);
-        setAppTask(r, task);
         mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
         moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
         if (wasResumed) {
@@ -5038,12 +5004,6 @@
         }
     }
 
-    private void setAppTask(ActivityRecord r, TaskRecord task) {
-        task.updateOverrideConfigurationFromLaunchBounds();
-        mWindowManager.addAppToTask(r.appToken, task.taskId);
-        r.onOverrideConfigurationSent();
-    }
-
     public int getStackId() {
         return mStackId;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 028c571..8ab3ac3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -33,7 +33,6 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -179,8 +178,7 @@
 import java.util.Objects;
 import java.util.Set;
 
-public class ActivityStackSupervisor extends ConfigurationContainer
-        implements DisplayListener {
+public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
     private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -1204,7 +1202,7 @@
 
         if (andResume) {
             r.startFreezingScreenLocked(app, 0);
-            mWindowManager.setAppVisibility(r.appToken, true);
+            r.setVisibility(true);
 
             // schedule launch ticks to collect information about slow apps.
             r.startLaunchTickingLocked();
@@ -1227,7 +1225,7 @@
         }
 
         if (mKeyguardController.isKeyguardLocked()) {
-            mWindowManager.notifyUnknownAppVisibilityLaunched(r.appToken);
+            r.notifyUnknownVisibilityLaunched();
         }
 
         r.app = app;
@@ -2577,7 +2575,7 @@
                 "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
         for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-            stack.addConfigOverride(activities.get(activityNdx), task);
+            activities.get(activityNdx).createWindowContainer();
         }
         return true;
     }
@@ -3169,7 +3167,7 @@
         task.setLastThumbnailLocked(r.screenshotActivityLocked());
         mRecentTasks.addLocked(task);
         mService.mTaskChangeNotificationController.notifyTaskStackChanged();
-        mWindowManager.setAppVisibility(r.appToken, false);
+        r.setVisibility(false);
 
         // When launching tasks behind, update the last active time of the top task after the new
         // task has been shown briefly
@@ -3360,7 +3358,7 @@
                     // normal flow and hide it once we determine that it is
                     // hidden by the activities in front of it.
                     if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
-                    mWindowManager.setAppVisibility(s.appToken, false);
+                    s.setVisibility(false);
                 }
             }
             if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9e28068..a17cf3b 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -849,6 +849,11 @@
         if (r.isPersistable()) {
             mService.notifyTaskPersisterLocked(this, false);
         }
+
+        // Sync. with window manager
+        updateOverrideConfigurationFromLaunchBounds();
+        r.positionWindowContainerAt(index);
+        r.onOverrideConfigurationSent();
     }
 
     /** @return true if this was the last activity in the task */
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
new file mode 100644
index 0000000..35004c2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -0,0 +1,526 @@
+/*
+ * 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.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static com.android.server.wm.AppTransition.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_SCREENSHOT;
+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 static com.android.server.wm.WindowManagerService.H.ADD_STARTING;
+
+import android.graphics.Bitmap;
+import android.os.Trace;
+import com.android.server.AttributeCache;
+
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.Message;
+import android.util.Slog;
+import android.view.IApplicationToken;
+
+/**
+ * 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 final IApplicationToken mToken;
+
+    private final Runnable mOnWindowsDrawn = () -> {
+        if (mListener == null) {
+            return;
+        }
+        if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
+                + AppWindowContainerController.this.mToken);
+        mListener.onWindowsDrawn();
+    };
+
+    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();
+    };
+
+    public AppWindowContainerController(IApplicationToken token,
+            AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
+            boolean fullscreen, boolean showForAllUsers, int configChanges,
+            boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
+            int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
+        this(token, listener, taskId, index, requestedOrientation, fullscreen, showForAllUsers,
+                configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
+                targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
+                WindowManagerService.getInstance());
+    }
+
+    public AppWindowContainerController(IApplicationToken token,
+            AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
+            boolean fullscreen, boolean showForAllUsers, int configChanges,
+            boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
+            int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
+            WindowManagerService service) {
+        super(listener, service);
+        mToken = token;
+        synchronized(mWindowMap) {
+            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;
+            }
+
+            // TODO: Have the controller for the task passed in when task are changed to use
+            // controller.
+            final Task task = mService.mTaskIdToTask.get(taskId);
+            if (task == null) {
+                throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
+            }
+
+            atoken = new AppWindowToken(mService, token, 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
+                    + " task=" + taskId + " at " + index);
+            task.addChild(atoken, index);
+        }
+    }
+
+    public void removeContainer(int displayId) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(mWindowMap) {
+                final DisplayContent dc = mRoot.getDisplayContent(displayId);
+                if (dc == null) {
+                    Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
+                            + mToken + " from non-existing displayId=" + displayId);
+                    return;
+                }
+                dc.removeAppToken(mToken.asBinder());
+                super.removeContainer();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    // TODO: Move to task window controller when that is created and rename to positionChildAt()
+    public void positionAt(int taskId, int index) {
+        synchronized(mService.mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM,
+                        "Attempted to position of non-existing app token: " + mToken);
+                return;
+            }
+
+            // TODO: Should get the window container from this owner when the task owner stuff is
+            // hooked-up.
+            final Task task = mService.mTaskIdToTask.get(taskId);
+            if (task == null) {
+                throw new IllegalArgumentException("positionChildAt: invalid taskId=" + taskId);
+            }
+            task.addChild(mContainer, index);
+        }
+
+    }
+
+    public Configuration setOrientation(int requestedOrientation, int displayId,
+            Configuration displayConfig, boolean freezeScreenIfNeeded) {
+        synchronized(mWindowMap) {
+            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(mWindowMap) {
+            if (mContainer == null) {
+                return SCREEN_ORIENTATION_UNSPECIFIED;
+            }
+
+            return mContainer.getOrientationIgnoreVisibility();
+        }
+    }
+
+    public void setVisibility(boolean visible) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
+                        + mToken);
+                return;
+            }
+
+            final AppWindowToken wtoken = mContainer;
+
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
+                    + mToken + ", visible=" + visible + "): " + mService.mAppTransition
+                    + " hidden=" + wtoken.hidden + " hiddenRequested="
+                    + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
+
+            mService.mOpeningApps.remove(wtoken);
+            mService.mClosingApps.remove(wtoken);
+            wtoken.waitingToShow = false;
+            wtoken.hiddenRequested = !visible;
+
+            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();
+                wtoken.setVisibleBeforeClientHidden();
+            } else {
+                if (!mService.mAppTransition.isTransitionSet()
+                        && mService.mAppTransition.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.
+                    mService.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.hidden || wtoken.mAppStopped) {
+                    wtoken.clearAllDrawn();
+
+                    // If the app was already visible, don't reset the waitingToShow state.
+                    if (wtoken.hidden) {
+                        wtoken.waitingToShow = true;
+                    }
+
+                    if (wtoken.clientHidden) {
+                        // 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.clientHidden = false;
+                        wtoken.sendAppVisibilityToClients();
+                    }
+                }
+                wtoken.requestUpdateWallpaperIfNeeded();
+
+                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
+                wtoken.mAppStopped = false;
+            }
+
+            // If we are preparing an app transition, then delay changing
+            // the visibility of this token until we execute that transition.
+            if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
+                // A dummy animation is a placeholder animation which informs others that an
+                // animation is going on (in this case an application transition). If the animation
+                // was transferred from another application/animator, no dummy animator should be
+                // created since an animation is already in progress.
+                if (wtoken.mAppAnimator.usingTransferredAnimation
+                        && wtoken.mAppAnimator.animation == null) {
+                    Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
+                            + ", using null transferred animation!");
+                }
+                if (!wtoken.mAppAnimator.usingTransferredAnimation &&
+                        (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
+                    if (DEBUG_APP_TRANSITIONS) Slog.v(
+                            TAG_WM, "Setting dummy animation on: " + wtoken);
+                    wtoken.mAppAnimator.setDummyAnimation();
+                }
+                wtoken.inPendingTransaction = true;
+                if (visible) {
+                    mService.mOpeningApps.add(wtoken);
+                    wtoken.mEnteringAnimation = true;
+                } else {
+                    mService.mClosingApps.add(wtoken);
+                    wtoken.mEnteringAnimation = false;
+                }
+                if (mService.mAppTransition.getAppTransition()
+                        == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
+                    // We're launchingBehind, add the launching activity to mOpeningApps.
+                    final WindowState win =
+                            mService.getDefaultDisplayContentLocked().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.hidden = true;
+                            mService.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(mWindowMap) {
+            if (mContainer != null) {
+                mService.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 createIfNeeded) {
+        synchronized(mWindowMap) {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
+                    + " pkg=" + pkg + " transferFrom=" + transferFrom);
+
+            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 (!mService.okToDisplay()) {
+                return false;
+            }
+
+            if (mContainer.startingData != null) {
+                return false;
+            }
+
+            // 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 the caller doesn't
+            // want us to create one, so that's it!
+            if (!createIfNeeded) {
+                return false;
+            }
+
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
+            mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
+                    labelRes, icon, logo, windowFlags);
+            final Message m = mService.mH.obtainMessage(ADD_STARTING, mContainer);
+            // Note: we really want to do sendMessageAtFrontOfQueue() because we
+            // want to process the message ASAP, before any other queued
+            // messages.
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
+            mService.mH.sendMessageAtFrontOfQueue(m);
+        }
+        return true;
+    }
+
+    public void removeStartingWindow() {
+        synchronized (mWindowMap) {
+            mService.scheduleRemoveStartingWindowLocked(mContainer);
+        }
+    }
+
+    public void pauseKeyDispatching() {
+        synchronized (mWindowMap) {
+            if (mContainer != null) {
+                mService.mInputMonitor.pauseDispatchingLw(mContainer);
+            }
+        }
+    }
+
+    public void resumeKeyDispatching() {
+        synchronized (mWindowMap) {
+            if (mContainer != null) {
+                mService.mInputMonitor.resumeDispatchingLw(mContainer);
+            }
+        }
+    }
+
+    public void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
+                return;
+            }
+            mContainer.notifyAppResumed(wasStopped, allowSavedSurface);
+        }
+    }
+
+    public void notifyAppStopped() {
+        synchronized(mWindowMap) {
+            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(mWindowMap) {
+            if (configChanges == 0 && mService.okToDisplay()) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
+                return;
+            }
+
+            if (mContainer == null) {
+                Slog.w(TAG_WM,
+                        "Attempted to freeze screen with non-existing app token: " + mContainer);
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            mContainer.startFreezingScreen();
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    public void stopFreezingScreen(boolean force) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
+                    + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
+            mContainer.stopFreezingScreen(true, force);
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    /**
+     * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
+     * In portrait mode, it grabs the full screenshot.
+     *
+     * @param displayId the Display to take a screenshot of.
+     * @param width the width of the target bitmap
+     * @param height the height of the target bitmap
+     * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
+     */
+    public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
+            final DisplayContent dc;
+            synchronized(mWindowMap) {
+                dc = mRoot.getDisplayContentOrCreate(displayId);
+                if (dc == null) {
+                    if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
+                            + ": returning null. No Display for displayId=" + displayId);
+                    return null;
+                }
+            }
+            return dc.screenshotApplications(mToken.asBinder(), width, height,
+                    false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
+                    false /* wallpaperOnly */);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+
+    void reportWindowsDrawn() {
+        mService.mH.post(mOnWindowsDrawn);
+    }
+
+    void reportWindowsVisible() {
+        mService.mH.post(mOnWindowsVisible);
+    }
+
+    void reportWindowsGone() {
+        mService.mH.post(mOnWindowsGone);
+    }
+
+    /** Calls directly into activity manager so window manager lock shouldn't held. */
+    boolean keyDispatchingTimedOut(String reason) {
+        return mListener != null && mListener.keyDispatchingTimedOut(reason);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerListener.java b/services/core/java/com/android/server/wm/AppWindowContainerListener.java
new file mode 100644
index 0000000..12d4b2f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppWindowContainerListener.java
@@ -0,0 +1,32 @@
+/*
+ * 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 are drawn. */
+    void onWindowsDrawn();
+    /** 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 key dispatching to a window associated with the app window container
+     * timed-out.
+     */
+    boolean keyDispatchingTimedOut(String reason);
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 6147885..0a48758 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -47,7 +47,6 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 
-import android.content.pm.ActivityInfo;
 import android.os.Debug;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.input.InputApplicationHandle;
@@ -173,8 +172,10 @@
     AppWindowToken(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) {
+            int configChanges, boolean launchTaskBehind, boolean alwaysFocusable,
+            AppWindowContainerController controller) {
         this(service, token, voiceInteraction, dc);
+        setController(controller);
         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
         mFillsParent = fullscreen;
         mShowForAllUsers = showForAllUsers;
@@ -251,9 +252,12 @@
         }
         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
                 + numInteresting + " visible=" + numVisible);
+        final AppWindowContainerController controller = getController();
         if (nowDrawn != reportedDrawn) {
             if (nowDrawn) {
-                mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_DRAWN, this).sendToTarget();
+                if (controller != null) {
+                    controller.reportWindowsDrawn();
+                }
             }
             reportedDrawn = nowDrawn;
         }
@@ -261,8 +265,13 @@
             if (DEBUG_VISIBILITY) Slog.v(TAG,
                     "Visibility changed in " + this + ": vis=" + nowVisible);
             reportedVisible = nowVisible;
-            mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_WINDOWS,
-                    nowVisible ? 1 : 0, nowGone ? 1 : 0, this).sendToTarget();
+            if (controller != null) {
+                if (nowVisible) {
+                    controller.reportWindowsVisible();
+                } else {
+                    controller.reportWindowsGone();
+                }
+            }
         }
     }
 
@@ -399,6 +408,11 @@
         return StackId.canReceiveKeys(mTask.mStack.mStackId) || 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
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 3fbe36f..f754775 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -251,16 +251,14 @@
         }
 
         if (appWindowToken != null && appWindowToken.appToken != null) {
-            try {
-                // Notify the activity manager about the timeout and let it decide whether
-                // to abort dispatching or keep waiting.
-                boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason);
-                if (! abort) {
-                    // The activity manager declined to abort dispatching.
-                    // Wait a bit longer and timeout again later.
-                    return appWindowToken.mInputDispatchingTimeoutNanos;
-                }
-            } catch (RemoteException ex) {
+            // 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);
+            if (!abort) {
+                // The activity manager declined to abort dispatching.
+                // Wait a bit longer and timeout again later.
+                return appWindowToken.mInputDispatchingTimeoutNanos;
             }
         } else if (windowState != null) {
             try {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index c9bf4fa..0e6ecde 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -75,6 +75,9 @@
     private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
             new Pools.SynchronizedPool<>(3);
 
+    // The owner/creator for this container. No controller if null.
+    private WindowContainerController mController;
+
     final protected WindowContainer getParent() {
         return mParent;
     }
@@ -188,6 +191,10 @@
         if (mParent != null) {
             mParent.removeChild(this);
         }
+
+        if (mController != null) {
+            setController(null);
+        }
     }
 
     /**
@@ -662,6 +669,23 @@
         } while (current != null);
     }
 
+    WindowContainerController getController() {
+        return mController;
+    }
+
+    void setController(WindowContainerController controller) {
+        if (mController != null && controller != null) {
+            throw new IllegalArgumentException("Can't set controller=" + mController
+                    + " for container=" + this + " Already set to=" + mController);
+        }
+        if (controller != null) {
+            controller.setContainer(this);
+        } else if (mController != null) {
+            mController.setContainer(null);
+        }
+        mController = controller;
+    }
+
     /**
      * Dumps the names of this container children in the input print writer indenting each
      * level with the input prefix.
diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java
new file mode 100644
index 0000000..84ffc35
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowContainerController.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.os.IBinder;
+
+import java.util.HashMap;
+
+/**
+ * Class that allows the owner/creator of a {@link WindowContainer} to communicate directly with the
+ * container and make changes.
+ * Note that public calls (mostly in sub-classes) into this class are assumed to be originating from
+ * outside the window manager so the window manager lock is held and appropriate permissions are
+ * checked before calls are allowed to proceed.
+ *
+ * Test class: {@link WindowContainerControllerTests}
+ */
+class WindowContainerController<E extends WindowContainer, I extends WindowContainerListener> {
+
+    final WindowManagerService mService;
+    final RootWindowContainer mRoot;
+    final HashMap<IBinder, WindowState> mWindowMap;
+
+    // The window container this controller owns.
+    E mContainer;
+    // Interface for communicating changes back to the owner.
+    final I mListener;
+
+    WindowContainerController(I listener, WindowManagerService service) {
+        mListener = listener;
+        mService = service;
+        mRoot = mService != null ? mService.mRoot : null;
+        mWindowMap = mService != null ? mService.mWindowMap : null;
+    }
+
+    void setContainer(E container) {
+        if (mContainer != null && container != null) {
+            throw new IllegalArgumentException("Can't set container=" + container
+                    + " for controller=" + this + " Already set to=" + mContainer);
+        }
+        mContainer = container;
+    }
+
+    void removeContainer() {
+        // TODO: See if most uses cases should support removeIfPossible here.
+        //mContainer.removeIfPossible();
+        if (mContainer != null) {
+            mContainer.setController(null);
+            mContainer = null;
+        }
+    }
+
+    boolean checkCallingPermission(String permission, String func) {
+        return mService.checkCallingPermission(permission, func);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainerListener.java b/services/core/java/com/android/server/wm/WindowContainerListener.java
new file mode 100644
index 0000000..ab9d71a
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowContainerListener.java
@@ -0,0 +1,25 @@
+/*
+ * 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 owner/creator of the container to listen to changes with the container.
+ * @see WindowContainerController
+ */
+public interface WindowContainerListener {
+
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f6d3881e..d5aa01b6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -90,7 +90,6 @@
 import android.view.Gravity;
 import android.view.PointerIcon;
 import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IApplicationToken;
 import android.view.IDockedStackListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
@@ -133,7 +132,6 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
-import com.android.server.AttributeCache;
 import com.android.server.DisplayThread;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
@@ -228,7 +226,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-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.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -240,7 +237,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static java.lang.Integer.MAX_VALUE;
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
@@ -915,16 +911,19 @@
         void onAppFreezeTimeout();
     }
 
-    public static WindowManagerService main(final Context context,
-            final InputManagerService im,
-            final boolean haveInputMethods, final boolean showBootMsgs,
-            final boolean onlyCore, WindowManagerPolicy policy) {
-        final WindowManagerService[] holder = new WindowManagerService[1];
-        DisplayThread.getHandler().runWithScissors(() -> {
-            holder[0] = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
-                    onlyCore, policy);
-        }, 0);
-        return holder[0];
+    private static WindowManagerService sInstance;
+
+    static WindowManagerService getInstance() {
+        return sInstance;
+    }
+
+    public static WindowManagerService main(final Context context, final InputManagerService im,
+            final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
+            WindowManagerPolicy policy) {
+        DisplayThread.getHandler().runWithScissors(() ->
+                sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
+                        onlyCore, policy), 0);
+        return sInstance;
     }
 
     private void initPolicy() {
@@ -2369,7 +2368,7 @@
         return atoken.mAppAnimator.animation != null;
     }
 
-    private boolean checkCallingPermission(String permission, String func) {
+    boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
             return true;
@@ -2442,73 +2441,6 @@
         }
     }
 
-    @Override
-    public void addAppToken(int addPos, IApplicationToken token, int taskId,
-            int requestedOrientation, boolean fullscreen, boolean showForAllUsers,
-            int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            boolean alwaysFocusable, int targetSdkVersion, int rotationAnimationHint) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "addAppToken()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        // Get the dispatching timeout here while we are not holding any locks so that it
-        // can be cached by the AppWindowToken.  The timeout value is used later by the
-        // input dispatcher in code that does hold locks.  If we did not cache the value
-        // here we would run the chance of introducing a deadlock between the window manager
-        // (which holds locks while updating the input dispatcher state) and the activity manager
-        // (which holds locks while querying the application token).
-        long inputDispatchingTimeoutNanos;
-        try {
-            inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
-        } catch (RemoteException ex) {
-            Slog.w(TAG_WM, "Could not get dispatching timeout.", ex);
-            inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
-        }
-
-        synchronized(mWindowMap) {
-            AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder());
-            if (atoken != null) {
-                Slog.w(TAG_WM, "Attempted to add existing app token: " + token);
-                return;
-            }
-
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
-            }
-
-            atoken = new AppWindowToken(this, token, voiceInteraction, task.getDisplayContent(),
-                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
-                    requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
-                    alwaysFocusable);
-            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
-                    + " task=" + taskId + " at " + addPos);
-
-            task.addChild(atoken, addPos);
-        }
-    }
-
-    @Override
-    public void addAppToTask(IBinder token, int taskId) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppTask()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken atoken = mRoot.getAppWindowToken(token);
-            if (atoken == null) {
-                Slog.w(TAG_WM, "Attempted to set task id of non-existing app token: " + token);
-                return;
-            }
-
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                throw new IllegalArgumentException("setAppTask: invalid taskId=" + taskId);
-            }
-            task.addChild(atoken, MAX_VALUE /* at top */);
-        }
-    }
-
     public void addTask(int taskId, int stackId, int userId, Rect bounds,
             Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
             boolean toTop, boolean showForAllUsers) {
@@ -2675,35 +2607,6 @@
         }
     }
 
-    @Override
-    public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppOrientation()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder());
-            if (atoken == null) {
-                Slog.w(TAG_WM, "Attempted to set orientation of non-existing app token: " + token);
-                return;
-            }
-
-            atoken.setOrientation(requestedOrientation);
-        }
-    }
-
-    @Override
-    public int getAppOrientation(IApplicationToken token) {
-        synchronized(mWindowMap) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token.asBinder());
-            if (wtoken == null) {
-                return SCREEN_ORIENTATION_UNSPECIFIED;
-            }
-
-            return wtoken.getOrientationIgnoreVisibility();
-        }
-    }
-
     void setFocusTaskRegionLocked() {
         final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null;
         if (focusedTask != null) {
@@ -2912,113 +2815,6 @@
         }
     }
 
-    @Override
-    public boolean setAppStartingWindow(IBinder token, String pkg,
-            int theme, CompatibilityInfo compatInfo,
-            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
-            int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppStartingWindow()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(
-                    TAG_WM, "setAppStartingWindow: token=" + token + " pkg=" + pkg
-                    + " transferFrom=" + transferFrom);
-
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + token);
-                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 (!okToDisplay()) {
-                return false;
-            }
-
-            if (wtoken.startingData != null) {
-                return false;
-            }
-
-            // 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, 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 (wtoken.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 (wtoken.transferStartingWindow(transferFrom)) {
-                return true;
-            }
-
-            // There is no existing starting window, and the caller doesn't
-            // want us to create one, so that's it!
-            if (!createIfNeeded) {
-                return false;
-            }
-
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
-            wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
-                    labelRes, icon, logo, windowFlags);
-            Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
-            // Note: we really want to do sendMessageAtFrontOfQueue() because we
-            // want to process the message ASAP, before any other queued
-            // messages.
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
-            mH.sendMessageAtFrontOfQueue(m);
-        }
-        return true;
-    }
-
-    public void removeAppStartingWindow(IBinder token) {
-        synchronized (mWindowMap) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            scheduleRemoveStartingWindowLocked(wtoken);
-        }
-    }
-
     public void setAppFullscreen(IBinder token, boolean toOpaque) {
         synchronized (mWindowMap) {
             final AppWindowToken atoken = mRoot.getAppWindowToken(token);
@@ -3055,233 +2851,6 @@
         }
     }
 
-    @Override
-    public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppResumed()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token);
-                return;
-            }
-            wtoken.notifyAppResumed(wasStopped, allowSavedSurface);
-        }
-    }
-
-    @Override
-    public void notifyAppStopped(IBinder token) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppStopped()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken wtoken;
-            wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " + token);
-                return;
-            }
-            wtoken.notifyAppStopped();
-        }
-    }
-
-    @Override
-    public void setAppVisibility(IBinder token, boolean visible) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppVisibility()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        AppWindowToken wtoken;
-
-        synchronized(mWindowMap) {
-            wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
-                return;
-            }
-
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility(" +
-                    token + ", visible=" + visible + "): " + mAppTransition +
-                    " hidden=" + wtoken.hidden + " hiddenRequested=" +
-                    wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
-
-            mOpeningApps.remove(wtoken);
-            mClosingApps.remove(wtoken);
-            wtoken.waitingToShow = false;
-            wtoken.hiddenRequested = !visible;
-
-            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();
-                wtoken.setVisibleBeforeClientHidden();
-            } else if (visible) {
-                if (!mAppTransition.isTransitionSet() && mAppTransition.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.
-                    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.hidden || wtoken.mAppStopped) {
-                    wtoken.clearAllDrawn();
-
-                    // If the app was already visible, don't reset the waitingToShow state.
-                    if (wtoken.hidden) {
-                        wtoken.waitingToShow = true;
-                    }
-
-                    if (wtoken.clientHidden) {
-                        // 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.clientHidden = false;
-                        wtoken.sendAppVisibilityToClients();
-                    }
-                }
-                wtoken.requestUpdateWallpaperIfNeeded();
-
-                if (DEBUG_ADD_REMOVE) Slog.v(
-                        TAG_WM, "No longer Stopped: " + wtoken);
-                wtoken.mAppStopped = false;
-            }
-
-            // If we are preparing an app transition, then delay changing
-            // the visibility of this token until we execute that transition.
-            if (okToDisplay() && mAppTransition.isTransitionSet()) {
-                // A dummy animation is a placeholder animation which informs others that an
-                // animation is going on (in this case an application transition). If the animation
-                // was transferred from another application/animator, no dummy animator should be
-                // created since an animation is already in progress.
-                if (wtoken.mAppAnimator.usingTransferredAnimation
-                        && wtoken.mAppAnimator.animation == null) {
-                    Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
-                            + ", using null transfered animation!");
-                }
-                if (!wtoken.mAppAnimator.usingTransferredAnimation &&
-                        (!wtoken.startingDisplayed || mSkipAppTransitionAnimation)) {
-                    if (DEBUG_APP_TRANSITIONS) Slog.v(
-                            TAG_WM, "Setting dummy animation on: " + wtoken);
-                    wtoken.mAppAnimator.setDummyAnimation();
-                }
-                wtoken.inPendingTransaction = true;
-                if (visible) {
-                    mOpeningApps.add(wtoken);
-                    wtoken.mEnteringAnimation = true;
-                } else {
-                    mClosingApps.add(wtoken);
-                    wtoken.mEnteringAnimation = false;
-                }
-                if (mAppTransition.getAppTransition() == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
-                    // We're launchingBehind, add the launching activity to mOpeningApps.
-                    final WindowState win = getDefaultDisplayContentLocked().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.hidden = true;
-                            mOpeningApps.add(focusedToken);
-                        }
-                    }
-                }
-                return;
-            }
-
-            final long origId = Binder.clearCallingIdentity();
-            wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
-            wtoken.updateReportedVisibilityLocked();
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    /**
-     * 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 notifyUnknownAppVisibilityLaunched(IBinder token) {
-        synchronized(mWindowMap) {
-            AppWindowToken appWindow = mRoot.getAppWindowToken(token);
-            if (appWindow != null) {
-                mUnknownAppVisibilityController.notifyLaunched(appWindow);
-            }
-        }
-    }
-
-    @Override
-    public void startAppFreezingScreen(IBinder token, int configChanges) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            if (configChanges == 0 && okToDisplay()) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + token);
-                return;
-            }
-
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null || wtoken.appToken == null) {
-                Slog.w(TAG_WM, "Attempted to freeze screen with non-existing app token: " + wtoken);
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            wtoken.startFreezingScreen();
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
-    public void stopAppFreezingScreen(IBinder token, boolean force) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null || wtoken.appToken == null) {
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + token + ": hidden="
-                    + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
-            wtoken.stopFreezingScreen(true, force);
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
-    public void removeAppToken(IBinder binder, int displayId) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeAppToken()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(mWindowMap) {
-                final DisplayContent dc = mRoot.getDisplayContent(displayId);
-                if (dc == null) {
-                    Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: " + binder
-                            + " from non-existing displayId=" + displayId);
-                    return;
-                }
-                dc.removeAppToken(binder);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
     void scheduleRemoveStartingWindowLocked(AppWindowToken wtoken) {
         if (wtoken == null) {
             return;
@@ -4523,7 +4092,7 @@
         }
         try {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
-            return screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
+            return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
                     -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */,
                     Bitmap.Config.ARGB_8888, true /* wallpaperOnly */);
         } finally {
@@ -4544,7 +4113,7 @@
         }
 
         FgThread.getHandler().post(() -> {
-            Bitmap bm = screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY,
+            Bitmap bm = screenshotApplications(null /* appToken */, DEFAULT_DISPLAY,
                     -1 /* width */, -1 /* height */, true /* includeFullDisplay */,
                     1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */);
             try {
@@ -4563,37 +4132,12 @@
      * @param displayId the Display to take a screenshot of.
      * @param width the width of the target bitmap
      * @param height the height of the target bitmap
-     * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
-     */
-    @Override
-    public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height,
-            float frameScale) {
-        if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
-                "screenshotApplications()")) {
-            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
-        }
-        try {
-            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
-            return screenshotApplicationsInner(appToken, displayId, width, height, false,
-                    frameScale, Bitmap.Config.RGB_565, false);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-        }
-    }
-
-    /**
-     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
-     * In portrait mode, it grabs the full screenshot.
-     *
-     * @param displayId the Display to take a screenshot of.
-     * @param width the width of the target bitmap
-     * @param height the height of the target bitmap
      * @param includeFullDisplay true if the screen should not be cropped before capture
      * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
      * @param config of the output bitmap
      * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
      */
-    private Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width,
+    private Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
             int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config,
             boolean wallpaperOnly) {
         final DisplayContent displayContent;
@@ -5907,34 +5451,6 @@
     private boolean mEventDispatchingEnabled;
 
     @Override
-    public void pauseKeyDispatching(IBinder binder) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "pauseKeyDispatching()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized (mWindowMap) {
-            WindowToken token = mRoot.getAppWindowToken(binder);
-            if (token != null) {
-                mInputMonitor.pauseDispatchingLw(token);
-            }
-        }
-    }
-
-    @Override
-    public void resumeKeyDispatching(IBinder binder) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "resumeKeyDispatching()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized (mWindowMap) {
-            WindowToken token = mRoot.getAppWindowToken(binder);
-            if (token != null) {
-                mInputMonitor.resumeDispatchingLw(token);
-            }
-        }
-    }
-
-    @Override
     public void setEventDispatching(boolean enabled) {
         if (!checkCallingPermission(MANAGE_APP_TOKENS, "setEventDispatching()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -6065,8 +5581,6 @@
         public static final int ADD_STARTING = 5;
         public static final int REMOVE_STARTING = 6;
         public static final int FINISHED_STARTING = 7;
-        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
-        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
         public static final int WINDOW_FREEZE_TIMEOUT = 11;
 
         public static final int APP_TRANSITION_TIMEOUT = 13;
@@ -6328,37 +5842,6 @@
                     }
                 } break;
 
-                case REPORT_APPLICATION_TOKEN_DRAWN: {
-                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
-
-                    try {
-                        if (DEBUG_VISIBILITY) Slog.v(
-                                TAG_WM, "Reporting drawn in " + wtoken);
-                        wtoken.appToken.windowsDrawn();
-                    } catch (RemoteException ex) {
-                    }
-                } break;
-
-                case REPORT_APPLICATION_TOKEN_WINDOWS: {
-                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
-
-                    boolean nowVisible = msg.arg1 != 0;
-                    boolean nowGone = msg.arg2 != 0;
-
-                    try {
-                        if (DEBUG_VISIBILITY) Slog.v(
-                                TAG_WM, "Reporting visible in " + wtoken
-                                + " visible=" + nowVisible
-                                + " gone=" + nowGone);
-                        if (nowVisible) {
-                            wtoken.appToken.windowsVisible();
-                        } else {
-                            wtoken.appToken.windowsGone();
-                        }
-                    } catch (RemoteException ex) {
-                    }
-                } break;
-
                 case WINDOW_FREEZE_TIMEOUT: {
                     // TODO(multidisplay): Can non-default displays rotate?
                     synchronized (mWindowMap) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
new file mode 100644
index 0000000..8a962e7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.junit.Test;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test class for {@link WindowContainerController}.
+ *
+ * Build/Install/Run:
+ *  bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
+ */
+@SmallTest
+@Presubmit
+@org.junit.runner.RunWith(AndroidJUnit4.class)
+public class AppWindowContainerControllerTests extends WindowTestsBase {
+// TODO Add tests once TaskWindowContainerController is created.
+    @Test
+    public void dummyTest() throws Exception {}
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 07f65bd..6129198 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -19,7 +19,6 @@
 import static junit.framework.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManagerInternal;
 import android.content.Context;
@@ -27,7 +26,6 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.IApplicationToken;
 
 import com.android.server.LocalServices;
 
@@ -114,7 +112,6 @@
     }
 
     private AppWindowToken createAppToken() {
-        return new AppWindowToken(mWm, mock(IApplicationToken.class), false,
-                mWm.getDefaultDisplayContentLocked());
+        return new AppWindowToken(mWm, null, false, mWm.getDefaultDisplayContentLocked());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
new file mode 100644
index 0000000..956735c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -0,0 +1,84 @@
+/*
+ * 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 org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test class for {@link WindowContainerController}.
+ *
+ * Build/Install/Run:
+ *  bit FrameworksServicesTests:com.android.server.wm.WindowContainerControllerTests
+ */
+@SmallTest
+@Presubmit
+@org.junit.runner.RunWith(AndroidJUnit4.class)
+public class WindowContainerControllerTests extends WindowTestsBase {
+
+    @Test
+    public void testCreation() throws Exception {
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+        final WindowContainer container = new WindowContainer();
+
+        container.setController(controller);
+        assertEquals(controller, container.getController());
+        assertEquals(controller.mContainer, container);
+    }
+
+    @Test
+    public void testSetContainer() throws Exception {
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+        final WindowContainer container = new WindowContainer();
+
+        controller.setContainer(container);
+        assertEquals(controller.mContainer, container);
+
+        // Assert we can't change the container to another one once set
+        boolean gotException = false;
+        try {
+            controller.setContainer(new WindowContainer());
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue(gotException);
+
+        // Assert that we can set the container to null.
+        controller.setContainer(null);
+        assertNull(controller.mContainer);
+    }
+
+    @Test
+    public void testRemoveContainer() throws Exception {
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+        final WindowContainer container = new WindowContainer();
+
+        controller.setContainer(container);
+        assertEquals(controller.mContainer, container);
+
+        controller.removeContainer();
+        assertNull(controller.mContainer);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 7277ba4..b57329c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -52,7 +52,7 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class WindowContainerTests {
+public class WindowContainerTests extends WindowTestsBase {
 
     @Test
     public void testCreation() throws Exception {
@@ -192,6 +192,44 @@
     }
 
     @Test
+    public void testRemoveImmediately_WithController() throws Exception {
+        final WindowContainer container = new WindowContainer();
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+
+        container.setController(controller);
+        assertEquals(controller, container.getController());
+        assertEquals(container, controller.mContainer);
+
+        container.removeImmediately();
+        assertNull(container.getController());
+        assertNull(controller.mContainer);
+    }
+
+    @Test
+    public void testSetController() throws Exception {
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+        final WindowContainer container = new WindowContainer();
+
+        container.setController(controller);
+        assertEquals(controller, container.getController());
+        assertEquals(container, controller.mContainer);
+
+        // Assert we can't change the controller to another one once set
+        boolean gotException = false;
+        try {
+            container.setController(new WindowContainerController(null, sWm));
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue(gotException);
+
+        // Assert that we can set the controller to null.
+        container.setController(null);
+        assertNull(container.getController());
+        assertNull(controller.mContainer);
+    }
+
+    @Test
     public void testPositionChildAt() throws Exception {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
         final TestWindowContainer root = builder.setLayer(0).build();
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 3985687..fb3beb3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -44,7 +44,7 @@
 /**
  * Common base class for window manager unit test classes.
  */
-public class WindowTestsBase {
+class WindowTestsBase {
     static WindowManagerService sWm = null;
     private final IWindow mIWindow = new TestIWindow();
     private final Session mMockSession = mock(Session.class);
@@ -52,17 +52,17 @@
     private static int sNextTaskId = 0;
 
     private static boolean sOneTimeSetupDone = false;
-    protected static DisplayContent sDisplayContent;
-    protected static WindowLayersController sLayersController;
-    protected static WindowState sWallpaperWindow;
-    protected static WindowState sImeWindow;
-    protected static WindowState sImeDialogWindow;
-    protected static WindowState sStatusBarWindow;
-    protected static WindowState sDockedDividerWindow;
-    protected static WindowState sNavBarWindow;
-    protected static WindowState sAppWindow;
-    protected static WindowState sChildAppWindowAbove;
-    protected static WindowState sChildAppWindowBelow;
+    static DisplayContent sDisplayContent;
+    static WindowLayersController sLayersController;
+    static WindowState sWallpaperWindow;
+    static WindowState sImeWindow;
+    static WindowState sImeDialogWindow;
+    static WindowState sStatusBarWindow;
+    static WindowState sDockedDividerWindow;
+    static WindowState sNavBarWindow;
+    static WindowState sAppWindow;
+    static WindowState sChildAppWindowAbove;
+    static WindowState sChildAppWindowBelow;
 
     @Before
     public void setUp() throws Exception {
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 28a2cb3..4aeae70 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -43,26 +43,6 @@
     @SmallTest
     public void testMANAGE_APP_TOKENS() {
         try {
-            mWm.pauseKeyDispatching(null);
-            fail("IWindowManager.pauseKeyDispatching did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.resumeKeyDispatching(null);
-            fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
             mWm.setEventDispatching(true);
             fail("IWindowManager.setEventDispatching did not throw SecurityException as"
                     + " expected");
@@ -93,26 +73,6 @@
         }
 
         try {
-            mWm.addAppToken(0, null, 0, 0, false, false, 0, false, false, false, 0, -1);
-            fail("IWindowManager.addAppToken did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.addAppToTask(null, 0);
-            fail("IWindowManager.setAppGroupId did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
             mWm.updateOrientationFromAppTokens(new Configuration(),
                     null /* freezeThisOneIfNeeded */, DEFAULT_DISPLAY);
             fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
@@ -124,17 +84,6 @@
         }
 
         try {
-            mWm.setAppOrientation(null, 0);
-            mWm.addWindowToken(null, 0, DEFAULT_DISPLAY);
-            fail("IWindowManager.setAppOrientation did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
             mWm.setFocusedApp(null, false);
             fail("IWindowManager.setFocusedApp did not throw SecurityException as"
                     + " expected");
@@ -163,56 +112,6 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-
-        try {
-            mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
-            fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.setAppVisibility(null, false);
-            fail("IWindowManager.setAppVisibility did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.startAppFreezingScreen(null, 0);
-            fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.stopAppFreezingScreen(null, false);
-            fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.removeAppToken(null, DEFAULT_DISPLAY);
-            fail("IWindowManager.removeAppToken did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
     }
 
     @SmallTest
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 4b9815d..71c1117 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -77,14 +77,6 @@
     // ---- unused implementation of IWindowManager ----
 
     @Override
-    public void addAppToken(int addPos, IApplicationToken token, int taskId,
-            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int configChanges,
-            boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
-            int targetSdkVersion, int rotationAnimationHint) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public void addWindowToken(IBinder arg0, int arg1, int arg2) throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -159,12 +151,6 @@
     }
 
     @Override
-    public int getAppOrientation(IApplicationToken arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    @Override
     public int getPendingAppTransition() throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
@@ -258,12 +244,6 @@
     }
 
     @Override
-    public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
     public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -276,24 +256,12 @@
     }
 
     @Override
-    public void removeAppToken(IBinder arg0, int arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
     public void removeWindowToken(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
     @Override
-    public void resumeKeyDispatching(IBinder arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
     public boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver)
             throws RemoteException {
         // TODO Auto-generated method stub
@@ -301,13 +269,6 @@
     }
 
     @Override
-    public Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth,
-            int maxHeight, float frameScale) throws RemoteException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
     public void setAnimationScale(int arg0, float arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -325,41 +286,6 @@
     }
 
     @Override
-    public void addAppToTask(IBinder arg0, int arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public boolean setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
-            CharSequence arg4, int arg5, int arg6, int arg7, int arg8, IBinder arg9, boolean arg10)
-            throws RemoteException {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface)
-            throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void notifyAppStopped(IBinder token) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public void setEventDispatching(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
     }
@@ -443,11 +369,6 @@
     }
 
     @Override
-    public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public boolean startViewServer(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
@@ -469,11 +390,6 @@
     }
 
     @Override
-    public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public boolean stopViewServer() throws RemoteException {
         // TODO Auto-generated method stub
         return false;