Merge changes Idfd40156,Ic903fc25

* changes:
  Make user-switch transitions customizable
  Add support for custom user-switch UI
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 40b0906..ed12d06 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4428,9 +4428,15 @@
             //          mN.mLargeIcon
             //   2. !mBigLargeIconSet -> mN.mLargeIcon applies
             Icon oldLargeIcon = null;
+            Bitmap largeIconLegacy = null;
             if (mBigLargeIconSet) {
                 oldLargeIcon = mBuilder.mN.mLargeIcon;
                 mBuilder.mN.mLargeIcon = mBigLargeIcon;
+                // The legacy largeIcon might not allow us to clear the image, as it's taken in
+                // replacement if the other one is null. Because we're restoring these legacy icons
+                // for old listeners, this is in general non-null.
+                largeIconLegacy = mBuilder.mN.largeIcon;
+                mBuilder.mN.largeIcon = null;
             }
 
             RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource());
@@ -4442,6 +4448,7 @@
 
             if (mBigLargeIconSet) {
                 mBuilder.mN.mLargeIcon = oldLargeIcon;
+                mBuilder.mN.largeIcon = largeIconLegacy;
             }
 
             contentView.setImageViewBitmap(R.id.big_picture, mPicture);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index fe24230..1b37ed4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -636,7 +636,7 @@
 
         /**
          * Window type: shares similar characteristics with {@link #TYPE_DREAM}. The layer is
-         * reserved for screenshot region selection.
+         * reserved for screenshot region selection. These windows must not take input focus.
          * @hide
          */
         public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;
diff --git a/core/res/res/color/watch_switch_thumb_color_material.xml b/core/res/res/color/watch_switch_thumb_color_material.xml
index d4796a0..f78d9b62 100644
--- a/core/res/res/color/watch_switch_thumb_color_material.xml
+++ b/core/res/res/color/watch_switch_thumb_color_material.xml
@@ -10,9 +10,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?android:colorButtonNormal" android:state_enabled="false" />
-    <item android:color="?android:colorControlActivated" android:state_checked="true" />
-    <item android:color="?android:colorButtonNormal" />
-</selector>
\ No newline at end of file
+    <item android:color="?attr/colorButtonNormal" android:alpha="?attr/disabledAlpha"
+            android:state_enabled="false" />
+    <item android:color="?attr/colorControlActivated" android:state_checked="true" />
+    <item android:color="?attr/colorButtonNormal" />
+</selector>
diff --git a/core/res/res/color/watch_switch_track_color_material.xml b/core/res/res/color/watch_switch_track_color_material.xml
new file mode 100644
index 0000000..402a536
--- /dev/null
+++ b/core/res/res/color/watch_switch_track_color_material.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<!-- Used for the background of switch track for watch switch preference. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="0.4" android:color="?attr/colorPrimary" />
+    <item android:color="?attr/colorPrimary" />
+</selector>
diff --git a/core/res/res/layout-watch/preference_widget_switch.xml b/core/res/res/layout-watch/preference_widget_switch.xml
index 37d0c6b..ffc00b4 100644
--- a/core/res/res/layout-watch/preference_widget_switch.xml
+++ b/core/res/res/layout-watch/preference_widget_switch.xml
@@ -24,7 +24,7 @@
     android:thumb="@drawable/watch_switch_thumb_material_anim"
     android:thumbTint="@color/watch_switch_thumb_color_material"
     android:track="@drawable/watch_switch_track_material"
-    android:trackTint="?android:colorPrimary"
+    android:trackTint="@color/watch_switch_track_color_material"
     android:focusable="false"
     android:clickable="false"
     android:background="@null" />
diff --git a/packages/Keyguard/res/layout/keyguard_password_view.xml b/packages/Keyguard/res/layout/keyguard_password_view.xml
index 7d45017..29c93d5 100644
--- a/packages/Keyguard/res/layout/keyguard_password_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_password_view.xml
@@ -26,7 +26,6 @@
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
     androidprv:layout_maxHeight="@dimen/keyguard_security_height"
     android:gravity="bottom"
-    android:contentDescription="@string/keyguard_accessibility_password_unlock"
     >
 
     <Space
diff --git a/packages/Keyguard/res/layout/keyguard_pin_view.xml b/packages/Keyguard/res/layout/keyguard_pin_view.xml
index d3fb982..e75f3c15 100644
--- a/packages/Keyguard/res/layout/keyguard_pin_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pin_view.xml
@@ -26,7 +26,6 @@
         androidprv:layout_maxWidth="@dimen/keyguard_security_width"
         androidprv:layout_maxHeight="@dimen/keyguard_security_max_height"
         android:orientation="vertical"
-        android:contentDescription="@string/keyguard_accessibility_pin_unlock"
         >
     <include layout="@layout/keyguard_message_area"
              android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 09fec81..ff689aa 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -103,15 +103,6 @@
     <!-- Time format strings for fall-back clock widget -->
     <string name="keyguard_widget_24_hours_format" translatable="false">kk\uee01mm</string>
 
-    <string name="keyguard_accessibility_pattern_unlock">Pattern unlock.</string>
-    <!-- Accessibility description of the pin lock. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_pin_unlock">Pin unlock.</string>
-    <!-- Accessibility description of the password lock. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_password_unlock">Password unlock.</string>
-    <!-- Accessibility description of the unlock pattern area. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">Pattern area.</string>
-    <!-- Accessibility description of the unlock slide area. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_slide_area">Slide area.</string>
     <!-- Accessibility description of the PIN password view. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_pin_area">PIN area</string>
     <!-- Accessibility description of the SIM PIN password view. [CHAR_LIMIT=none] -->
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index f3a7acc..b3ff5d6 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -33,6 +33,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:paddingEnd="@dimen/volume_button_size"
+                android:paddingTop="@dimen/volume_dialog_collapsed_padding_top"
                 android:orientation="vertical" >
             <View android:id="@+id/spacer"
                   android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 50e7410..22cdd7d 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -61,11 +61,11 @@
     <string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Koristiti kao zadanu opciju za ovaj USB uređaj"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Koristiti kao zadanu opciju za ovaj USB uređaj"</string>
-    <string name="usb_debugging_title" msgid="4513918393387141949">"Omogućiti otklanjanje grešaka preko USB-a?"</string>
+    <string name="usb_debugging_title" msgid="4513918393387141949">"Omogućiti otklanjanje grešaka putem uređaja spojenog na USB?"</string>
     <string name="usb_debugging_message" msgid="2220143855912376496">"RSA otisak prsta za otključavanje računara je: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Uvijek dozvoli sa ovog računara"</string>
-    <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"Uklanjanje pogreški putem USB-a nije dozvoljeno"</string>
-    <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Korisnik koji je trenutno prijavljen na uređaju ne može uključiti opciju za otklanjanje grešaka koristeći USB. Da biste koristili ovu funkciju prebacite se na korisnika administratora."</string>
+    <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"Otklanjanje grešaka putem uređaja spojenog na USB nije dozvoljeno"</string>
+    <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Korisnik koji je trenutno prijavljen na uređaju ne može uključiti opciju za otklanjanje grešaka putem uređaja spojenog na USB. Da biste koristili ovu funkciju prebacite se na korisnika administratora."</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Uvećaj prikaz na ekran"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Razvuci prikaz na ekran"</string>
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Spašavanje snimka ekrana..."</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d378f0d..549d50e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -57,6 +57,9 @@
     <!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. -->
     <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
 
+    <!-- max height of a notification such that the content can still fade out when closing -->
+    <dimen name="max_notification_fadeout_height">100dp</dimen>
+
     <!-- End margin for the RSSI status icon of a device connected via bluetooth. -->
     <dimen name="status_bar_connected_device_signal_margin_end">16dp</dimen>
 
@@ -559,6 +562,7 @@
 
     <!-- Volume dialog root view bottom margin, at rest -->
     <dimen name="volume_dialog_margin_bottom">4dp</dimen>
+    <dimen name="volume_dialog_collapsed_padding_top">8dp</dimen>
     <dimen name="volume_dialog_expanded_spacer">14dp</dimen>
     <dimen name="volume_dialog_padding_end">40dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 9afb384..e35ef44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -744,6 +744,7 @@
                 }
                 if (!mWasCancelled) {
                     enableAppearDrawing(false);
+                    onAppearAnimationFinished(isAppearing);
                 }
             }
 
@@ -760,6 +761,9 @@
         mAppearAnimator.start();
     }
 
+    protected void onAppearAnimationFinished(boolean wasAppearing) {
+    }
+
     private void cancelAppearAnimation() {
         if (mAppearAnimator != null) {
             mAppearAnimator.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 58d402b..02fdd3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -598,7 +598,7 @@
     }
 
     private NotificationHeaderView getVisibleNotificationHeader() {
-        if (mIsSummaryWithChildren) {
+        if (mIsSummaryWithChildren && !mShowingPublic) {
             return mChildrenContainer.getHeaderView();
         }
         return getShowingLayout().getVisibleNotificationHeader();
@@ -1442,13 +1442,30 @@
 
     @Override
     protected View getContentView() {
-        if (mIsSummaryWithChildren) {
+        if (mIsSummaryWithChildren && !mShowingPublic) {
             return mChildrenContainer;
         }
         return getShowingLayout();
     }
 
     @Override
+    protected void onAppearAnimationFinished(boolean wasAppearing) {
+        super.onAppearAnimationFinished(wasAppearing);
+        if (wasAppearing) {
+            // During the animation the visible view might have changed, so let's make sure all
+            // alphas are reset
+            if (mChildrenContainer != null) {
+                mChildrenContainer.setAlpha(1.0f);
+                mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
+            }
+            mPrivateLayout.setAlpha(1.0f);
+            mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
+            mPublicLayout.setAlpha(1.0f);
+            mPublicLayout.setLayerType(LAYER_TYPE_NONE, null);
+        }
+    }
+
+    @Override
     public int getExtraBottomPadding() {
         if (mIsSummaryWithChildren && isGroupExpanded()) {
             return mIncreasedPaddingBetweenElements;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 8658111..f27f8f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -189,6 +189,7 @@
     private boolean mExpandingFromHeadsUp;
     private boolean mCollapsedOnDown;
     private int mPositionMinSideMargin;
+    private int mMaxFadeoutHeight;
     private int mLastOrientation = -1;
     private boolean mClosingWithAlphaFadeOut;
     private boolean mHeadsUpAnimatingAway;
@@ -278,6 +279,8 @@
                 R.dimen.qs_falsing_threshold);
         mPositionMinSideMargin = getResources().getDimensionPixelSize(
                 R.dimen.notification_panel_min_side_margin);
+        mMaxFadeoutHeight = getResources().getDimensionPixelSize(
+                R.dimen.max_notification_fadeout_height);
     }
 
     public void updateResources() {
@@ -552,7 +555,9 @@
     protected void flingToHeight(float vel, boolean expand, float target,
             float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
         mHeadsUpTouchHelper.notifyFling(!expand);
-        setClosingWithAlphaFadeout(!expand && getFadeoutAlpha() == 1.0f);
+        setClosingWithAlphaFadeout(!expand
+                && mNotificationStackScroller.getFirstChildIntrinsicHeight() <= mMaxFadeoutHeight
+                && getFadeoutAlpha() == 1.0f);
         super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index dd856ef..e95cc6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1614,7 +1614,7 @@
                     && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
                 if (mState == StatusBarState.SHADE) {
                     animateCollapsePanels();
-                } else if (mState == StatusBarState.SHADE_LOCKED) {
+                } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
                     goToKeyguard();
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 43336a0..c54e4b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -701,7 +701,7 @@
      */
     private float getExpandTranslationStart() {
         int startPosition = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
-                ? 0 : -getFirstChildMinHeight();
+                ? 0 : -getFirstChildIntrinsicHeight();
         return startPosition - mTopPadding;
     }
 
@@ -2011,7 +2011,7 @@
                 bottom = Math.min(bottom, getHeight());
             }
         } else {
-            top = (int) (mTopPadding + mStackTranslation);
+            top = mTopPadding;
             bottom = top;
         }
         if (mPhoneStatusBar.getBarState() != StatusBarState.KEYGUARD) {
@@ -2142,17 +2142,17 @@
     }
 
     public int getLayoutMinHeight() {
-        int firstChildMinHeight = getFirstChildMinHeight();
+        int firstChildMinHeight = getFirstChildIntrinsicHeight();
         return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
                 mMaxLayoutHeight - mTopPadding);
     }
 
-    private int getFirstChildMinHeight() {
+    public int getFirstChildIntrinsicHeight() {
         final ExpandableView firstChild = getFirstChildNotGone();
         int firstChildMinHeight = firstChild != null
                 ? firstChild.getIntrinsicHeight()
                 : mEmptyShadeView != null
-                        ? mEmptyShadeView.getMinHeight()
+                        ? mEmptyShadeView.getIntrinsicHeight()
                         : mCollapsedSize;
         if (mOwnScrollY > 0) {
             firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9cae382..edc165a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1003,7 +1003,7 @@
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
             if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                     "Sleep => pause with userLeaving=false");
-            startPausingLocked(false, true, false, false);
+            startPausingLocked(false, true, null, false);
             return true;
         }
         if (mPausingActivity != null) {
@@ -1081,15 +1081,16 @@
      * @param userLeaving True if this should result in an onUserLeaving to the current activity.
      * @param uiSleeping True if this is happening with the user interface going to sleep (the
      * screen turning off).
-     * @param resuming True if this is being called as part of resuming the top activity, so
-     * we shouldn't try to instigate a resume here.
+     * @param resuming The activity we are currently trying to resume or null if this is not being
+     *                 called as part of resuming the top activity, so we shouldn't try to instigate
+     *                 a resume here if not null.
      * @param dontWait True if the caller does not want to wait for the pause to complete.  If
      * set to true, we will immediately complete the pause here before returning.
      * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
      * it to tell us when it is done.
      */
-    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
-            boolean dontWait) {
+    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
+            ActivityRecord resuming, boolean dontWait) {
         if (mPausingActivity != null) {
             Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
                     + " state=" + mPausingActivity.state);
@@ -1097,12 +1098,12 @@
                 // Avoid recursion among check for sleep and complete pause during sleeping.
                 // Because activity will be paused immediately after resume, just let pause
                 // be completed by the order of activity paused from clients.
-                completePauseLocked(false);
+                completePauseLocked(false, resuming);
             }
         }
         ActivityRecord prev = mResumedActivity;
         if (prev == null) {
-            if (!resuming) {
+            if (resuming == null) {
                 Slog.wtf(TAG, "Trying to pause when nothing is resumed");
                 mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
@@ -1175,7 +1176,7 @@
             if (dontWait) {
                 // If the caller said they don't want to wait for the pause, then complete
                 // the pause now.
-                completePauseLocked(false);
+                completePauseLocked(false, resuming);
                 return false;
 
             } else {
@@ -1194,7 +1195,7 @@
             // This activity failed to schedule the
             // pause, so just treat it as being paused now.
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
-            if (!resuming) {
+            if (resuming == null) {
                 mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             return false;
@@ -1211,7 +1212,7 @@
             if (mPausingActivity == r) {
                 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
                         + (timeout ? " (due to timeout)" : " (pause complete)"));
-                completePauseLocked(true);
+                completePauseLocked(true, null);
                 return;
             } else {
                 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
@@ -1282,7 +1283,7 @@
         }
     }
 
-    private void completePauseLocked(boolean resumeNext) {
+    private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
         ActivityRecord prev = mPausingActivity;
         if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
 
@@ -1374,7 +1375,7 @@
             mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
         }
 
-        mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS);
     }
 
     private void addToStopping(ActivityRecord r, boolean immediate) {
@@ -2335,11 +2336,11 @@
 
         // We need to start pausing the current activity so the top one can be resumed...
         final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
-        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
+        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
         if (mResumedActivity != null) {
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "resumeTopActivityLocked: Pausing " + mResumedActivity);
-            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
+            pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
         }
         if (pausing) {
             if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
@@ -3581,7 +3582,7 @@
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
                 if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                         "finish() => pause with userLeaving=false");
-                startPausingLocked(false, false, false, false);
+                startPausingLocked(false, false, null, false);
             }
 
             if (endTask) {
@@ -3884,8 +3885,7 @@
         r.finishLaunchTickingLocked();
     }
 
-    private void removeActivityFromHistoryLocked(
-            ActivityRecord r, TaskRecord oldTop, String reason) {
+    private void removeActivityFromHistoryLocked(ActivityRecord r, String reason) {
         mStackSupervisor.removeChildActivityContainers(r);
         finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
         r.makeFinishingLocked();
@@ -3904,11 +3904,10 @@
             validateAppTokensLocked();
         }
         final TaskRecord task = r.task;
-        final TaskRecord topTask = oldTop != null ? oldTop : topTask();
         if (task != null && task.removeActivity(r)) {
             if (DEBUG_STACK) Slog.i(TAG_STACK,
                     "removeActivityFromHistoryLocked: last activity removed from " + this);
-            if (mStackSupervisor.isFocusedStack(this) && task == topTask &&
+            if (mStackSupervisor.isFocusedStack(this) && task == topTask() &&
                     task.isOverHomeStack()) {
                 mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(), reason);
             }
@@ -4044,12 +4043,6 @@
 
         boolean removedFromHistory = false;
 
-        // If the activity is finishing, it's no longer considered in topRunningActivityLocked,
-        // and cleanUpActivityLocked() may change focus to another activity (or task).
-        // Get the current top task now, as removeActivityFromHistoryLocked() below need this
-        // to decide whether to return to home stack after removal.
-        final TaskRecord topTask = topTask();
-
         cleanUpActivityLocked(r, false, false);
 
         final boolean hadApp = r.app != null;
@@ -4084,8 +4077,7 @@
                 // up.
                 //Slog.w(TAG, "Exception thrown during finish", e);
                 if (r.finishing) {
-                    removeActivityFromHistoryLocked(
-                            r, topTask, reason + " exceptionInScheduleDestroy");
+                    removeActivityFromHistoryLocked(r, reason + " exceptionInScheduleDestroy");
                     removedFromHistory = true;
                     skipDestroy = true;
                 }
@@ -4116,7 +4108,7 @@
         } else {
             // remove this record from the history.
             if (r.finishing) {
-                removeActivityFromHistoryLocked(r, topTask, reason + " hadNoApp");
+                removeActivityFromHistoryLocked(r, reason + " hadNoApp");
                 removedFromHistory = true;
             } else {
                 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (no app)");
@@ -4147,7 +4139,7 @@
             if (isInStackLocked(r) != null) {
                 if (r.state == ActivityState.DESTROYING) {
                     cleanUpActivityLocked(r, true, false);
-                    removeActivityFromHistoryLocked(r, null, reason);
+                    removeActivityFromHistoryLocked(r, reason);
                 }
             }
             mStackSupervisor.resumeFocusedStackTopActivityLocked();
@@ -4305,7 +4297,7 @@
                     }
                     cleanUpActivityLocked(r, true, true);
                     if (remove) {
-                        removeActivityFromHistoryLocked(r, null, "appDied");
+                        removeActivityFromHistoryLocked(r, "appDied");
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8f05aa3..271483e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -920,9 +920,12 @@
     /**
      * Pause all activities in either all of the stacks or just the back stacks.
      * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
+     * @param resuming The resuming activity.
+     * @param dontWait The resuming activity isn't going to wait for all activities to be paused
+     *                 before resuming.
      * @return true if any activity was paused as a result of this call.
      */
-    boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
+    boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
         boolean someActivityPaused = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -961,7 +964,7 @@
     }
 
     void pauseChildStacks(ActivityRecord parent, boolean userLeaving, boolean uiSleeping,
-            boolean resuming, boolean dontWait) {
+            ActivityRecord resuming, boolean dontWait) {
         // TODO: Put all stacks in supervisor and iterate through them instead.
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -4230,7 +4233,7 @@
                 mContainerState = CONTAINER_STATE_NO_SURFACE;
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
                 if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
-                    mStack.startPausingLocked(false, true, false, false);
+                    mStack.startPausingLocked(false, true, null, false);
                 }
             }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c1b5102..60fbabf 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2310,6 +2310,9 @@
                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
                 }
                 break;
+            case TYPE_SCREENSHOT:
+                attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+                break;
         }
 
         if (attrs.type != TYPE_STATUS_BAR) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 47f435f..c78e94b 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -73,9 +73,6 @@
     // Non-null only for application tokens.
     final IApplicationToken appToken;
 
-    // All of the windows and child windows that are included in this
-    // application token.  Note this list is NOT sorted!
-    private final WindowList allAppWindows = new WindowList();
     @NonNull final AppWindowAnimator mAppAnimator;
 
     final boolean voiceInteraction;
@@ -163,9 +160,9 @@
     }
 
     void sendAppVisibilityToClients() {
-        final int N = allAppWindows.size();
+        final int N = windows.size();
         for (int i=0; i<N; i++) {
-            WindowState win = allAppWindows.get(i);
+            WindowState win = windows.get(i);
             if (win == startingWindow && clientHidden) {
                 // Don't hide the starting window.
                 continue;
@@ -180,8 +177,8 @@
     }
 
     void setVisibleBeforeClientHidden() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             w.setVisibleBeforeClientHidden();
         }
     }
@@ -217,9 +214,9 @@
 
         if (DEBUG_VISIBILITY) Slog.v(TAG,
                 "Update reported visibility: " + this);
-        final int N = allAppWindows.size();
+        final int N = windows.size();
         for (int i=0; i<N; i++) {
-            WindowState win = allAppWindows.get(i);
+            WindowState win = windows.get(i);
             if (win == startingWindow || win.mAppFreezing
                     || win.mViewVisibility != View.VISIBLE
                     || win.mAttrs.type == TYPE_APPLICATION_STARTING
@@ -330,9 +327,9 @@
                 changed = true;
             }
 
-            final int windowsCount = allAppWindows.size();
+            final int windowsCount = windows.size();
             for (int i = 0; i < windowsCount; i++) {
-                final WindowState win = allAppWindows.get(i);
+                final WindowState win = windows.get(i);
                 if (win == startingWindow) {
                     // Starting window that's exiting will be removed when the animation finishes.
                     // Mark all relevant flags for that onExitAnimationDone will proceed all the way
@@ -406,8 +403,8 @@
             delayed = true;
         }
 
-        for (int i = allAppWindows.size() - 1; i >= 0 && !delayed; i--) {
-            if (allAppWindows.get(i).mWinAnimator.isWindowAnimationSet()) {
+        for (int i = windows.size() - 1; i >= 0 && !delayed; i--) {
+            if (windows.get(i).mWinAnimator.isWindowAnimationSet()) {
                 delayed = true;
             }
         }
@@ -434,10 +431,10 @@
 
     WindowState findMainWindow() {
         WindowState candidate = null;
-        int j = allAppWindows.size();
+        int j = windows.size();
         while (j > 0) {
             j--;
-            WindowState win = allAppWindows.get(j);
+            WindowState win = windows.get(j);
             if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
                     || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
                 // In cases where there are multiple windows, we prefer the non-exiting window. This
@@ -458,9 +455,9 @@
     }
 
     boolean isVisible() {
-        final int N = allAppWindows.size();
+        final int N = windows.size();
         for (int i=0; i<N; i++) {
-            WindowState win = allAppWindows.get(i);
+            WindowState win = windows.get(i);
             // If we're animating with a saved surface, we're already visible.
             // Return true so that the alpha doesn't get cleared.
             if (!win.mAppFreezing
@@ -476,8 +473,8 @@
     }
 
     boolean isVisibleForUser() {
-        for (int j = allAppWindows.size() - 1; j >= 0; j--) {
-            final WindowState w = allAppWindows.get(j);
+        for (int j = windows.size() - 1; j >= 0; j--) {
+            final WindowState w = windows.get(j);
             if (!w.isHiddenFromUserLocked()) {
                 return true;
             }
@@ -501,8 +498,8 @@
     }
 
     void clearAnimatingFlags() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState win = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState win = windows.get(i);
             // We don't want to clear it out for windows that get replaced, because the
             // animation depends on the flag to remove the replaced window.
             //
@@ -540,7 +537,7 @@
      */
 
     private void destroySurfaces(boolean cleanupOnResume) {
-        final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) allAppWindows.clone();
+        final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) windows.clone();
         final DisplayContentList displayList = new DisplayContentList();
         for (int i = allWindows.size() - 1; i >= 0; i--) {
             final WindowState win = allWindows.get(i);
@@ -620,8 +617,8 @@
     }
 
     boolean canRestoreSurfaces() {
-        for (int i = allAppWindows.size() -1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() -1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             if (w.canRestoreSurface()) {
                 return true;
             }
@@ -630,8 +627,8 @@
     }
 
     void clearVisibleBeforeClientHidden() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             w.clearVisibleBeforeClientHidden();
         }
     }
@@ -641,8 +638,8 @@
      * animating with saved surface.
      */
     boolean isAnimatingInvisibleWithSavedSurface() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             if (w.isAnimatingInvisibleWithSavedSurface()) {
                 return true;
             }
@@ -655,8 +652,8 @@
      * with a saved surface, and mark them destroying.
      */
     void stopUsingSavedSurfaceLocked() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             if (w.isAnimatingInvisibleWithSavedSurface()) {
                 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
                         "stopUsingSavedSurfaceLocked: " + w);
@@ -670,8 +667,8 @@
     }
 
     void markSavedSurfaceExiting() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             if (w.isAnimatingInvisibleWithSavedSurface()) {
                 w.mAnimatingExit = true;
                 w.mWinAnimator.mAnimating = true;
@@ -687,8 +684,8 @@
         // Check if we have enough drawn windows to mark allDrawn= true.
         int numInteresting = 0;
         int numDrawn = 0;
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            WindowState w = windows.get(i);
             if (w != startingWindow && !w.mAppDied && w.wasVisibleBeforeClientHidden()
                     && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
                 numInteresting++;
@@ -715,8 +712,8 @@
     }
 
     void destroySavedSurfaces() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            WindowState win = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            WindowState win = windows.get(i);
             win.destroySavedSurface();
         }
     }
@@ -728,40 +725,19 @@
     }
 
     @Override
-    void removeAllWindows() {
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
-                // removeWindowLocked at bottom of loop may remove multiple entries from
-                // allAppWindows if the window to be removed has child windows. It also may
-                // not remove any windows from allAppWindows at all if win is exiting and
-                // currently animating away. This ensures that winNdx is monotonically decreasing
-                // and never beyond allAppWindows bounds.
-                winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
-            WindowState win = allAppWindows.get(winNdx);
-            if (DEBUG_WINDOW_MOVEMENT) {
-                Slog.w(TAG, "removeAllWindows: removing win=" + win);
-            }
-
-            mService.removeWindowLocked(win);
-        }
-        allAppWindows.clear();
-        windows.clear();
-    }
-
-    @Override
     void removeWindow(WindowState win) {
         super.removeWindow(win);
 
-        allAppWindows.remove(win);
-
+        // TODO: Something smells about the code below...Is there a better way?
         if (startingWindow == win) {
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
             mService.scheduleRemoveStartingWindowLocked(this);
-        } else if (allAppWindows.size() == 0 && startingData != null) {
+        } else if (windows.size() == 0 && startingData != null) {
             // If this is the last window and we had requested a starting transition window,
             // well there is no point now.
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingWindow");
             startingData = null;
-        } else if (allAppWindows.size() == 1 && startingView != null) {
+        } else if (windows.size() == 1 && startingView != null) {
             // If this is the last window except for a starting transition window,
             // we need to get rid of the starting transition.
             mService.scheduleRemoveStartingWindowLocked(this);
@@ -769,28 +745,27 @@
     }
 
     void removeAllDeadWindows() {
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
-            // removeWindowLocked at bottom of loop may remove multiple entries from
-            // allAppWindows if the window to be removed has child windows. It also may
-            // not remove any windows from allAppWindows at all if win is exiting and
+        for (int winNdx = windows.size() - 1; winNdx >= 0;
+            // WindowState#removeIfPossible() at bottom of loop may remove multiple entries from
+            // windows if the window to be removed has child windows. It also may
+            // not remove any windows from windows at all if win is exiting and
             // currently animating away. This ensures that winNdx is monotonically decreasing
-            // and never beyond allAppWindows bounds.
-            winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
-            WindowState win = allAppWindows.get(winNdx);
+            // and never beyond windows bounds.
+            winNdx = Math.min(winNdx - 1, windows.size() - 1)) {
+            WindowState win = windows.get(winNdx);
             if (win.mAppDied) {
-                if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
-                    Slog.w(TAG, "removeAllDeadWindows: " + win);
-                }
+                if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
+                        "removeAllDeadWindows: " + win);
                 // Set mDestroying, we don't want any animation or delayed removal here.
                 win.mDestroying = true;
-                mService.removeWindowLocked(win);
+                win.removeIfPossible();
             }
         }
     }
 
     boolean hasWindowsAlive() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            if (!allAppWindows.get(i).mAppDied) {
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            if (!windows.get(i).mAppDied) {
                 return true;
             }
         }
@@ -801,8 +776,8 @@
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
                 "Marking app token " + this + " with replacing windows.");
 
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             w.setReplacing(animate);
         }
         if (animate) {
@@ -818,8 +793,8 @@
     void setReplacingChildren() {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
                 + " with replacing child windows.");
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             if (w.shouldBeReplacedWithChildren()) {
                 w.setReplacing(false /* animate */);
             }
@@ -830,15 +805,15 @@
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
                 "Resetting app token " + this + " of replacing window marks.");
 
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             w.resetReplacing();
         }
     }
 
     void requestUpdateWallpaperIfNeeded() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState w = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState w = windows.get(i);
             w.requestUpdateWallpaperIfNeeded();
         }
     }
@@ -873,28 +848,26 @@
         mPendingRelaunchCount = 0;
     }
 
+    @Override
     void addWindow(WindowState w) {
-        if (allAppWindows.contains(w)) {
-            return;
-        }
+        super.addWindow(w);
 
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            WindowState candidate = allAppWindows.get(i);
-            if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
-                    candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState candidate = windows.get(i);
+            if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null
+                    && candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
+
                 candidate.mReplacingWindow = w;
                 w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow;
-
                 // if we got a replacement window, reset the timeout to give drawing more time
                 mService.scheduleReplacingWindowTimeouts(this);
             }
         }
-        allAppWindows.add(w);
     }
 
     boolean waitingForReplacement() {
-        for (int i = allAppWindows.size() -1; i >= 0; i--) {
-            WindowState candidate = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            WindowState candidate = windows.get(i);
             if (candidate.mWillReplaceWindow) {
                 return true;
             }
@@ -903,15 +876,14 @@
     }
 
     void clearTimedoutReplacesLocked() {
-        for (int i = allAppWindows.size() - 1; i >= 0;
-             // removeWindowLocked at bottom of loop may remove multiple entries from
-             // allAppWindows if the window to be removed has child windows. It also may
-             // not remove any windows from allAppWindows at all if win is exiting and
-             // currently animating away. This ensures that winNdx is monotonically decreasing
-             // and never beyond allAppWindows bounds.
-             i = Math.min(i - 1, allAppWindows.size() - 1)) {
-            WindowState candidate = allAppWindows.get(i);
-            if (candidate.mWillReplaceWindow == false) {
+        for (int i = windows.size() - 1; i >= 0;
+             // WindowState#remove() at bottom of loop may remove multiple entries from windows if
+             // the window to be removed has child windows. It also may not remove any windows from
+             // windows at all if win is exiting and currently animating away. This ensures that
+             // winNdx is monotonically decreasing and never beyond windows bounds.
+             i = Math.min(i - 1, windows.size() - 1)) {
+            final WindowState candidate = windows.get(i);
+            if (!candidate.mWillReplaceWindow) {
                 continue;
             }
             candidate.mWillReplaceWindow = false;
@@ -919,7 +891,7 @@
                 candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false;
             }
             // Since the window already timed out, remove it immediately now.
-            // Use WindowState#remove() instead of removeWindowLocked(), as the latter
+            // Use WindowState#remove() instead of WindowState#removeIfPossible(), as the latter
             // delays removal on certain conditions, which will leave the stale window in the
             // stack and marked mWillReplaceWindow=false, so the window will never be removed.
             candidate.remove();
@@ -962,8 +934,8 @@
         if (!mFrozenMergedConfig.isEmpty()) {
             mFrozenMergedConfig.remove();
         }
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState win = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState win = windows.get(i);
             if (!win.mHasSurface) {
                 continue;
             }
@@ -1007,49 +979,14 @@
     }
 
     void resetJustMovedInStack() {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            allAppWindows.get(i).resetJustMovedInStack();
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            windows.get(i).resetJustMovedInStack();
         }
     }
 
-    @Override
-    int adjustAnimLayer(int adj) {
-        int highestAnimLayer = super.adjustAnimLayer(adj);
-
-        final int windowCount = allAppWindows.size();
-
-        for (int i = 0; i < windowCount; i++) {
-            final WindowState w = allAppWindows.get(i);
-            w.adjustAnimLayer(adj);
-
-            final int animLayer = w.mWinAnimator.mAnimLayer;
-            if (DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": " + animLayer);
-            if (animLayer > highestAnimLayer) {
-                highestAnimLayer = animLayer;
-            }
-            if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
-                mService.mLayersController.setInputMethodAnimLayerAdjustment(adj);
-            }
-        }
-
-        return highestAnimLayer;
-    }
-
-    @Override
-    int getHighestAnimLayer() {
-        int layer = super.getHighestAnimLayer();
-        for (int j = 0; j < allAppWindows.size(); j++) {
-            final WindowState win = allAppWindows.get(j);
-            if (win.mWinAnimator.mAnimLayer > layer) {
-                layer = win.mWinAnimator.mAnimLayer;
-            }
-        }
-        return layer;
-    }
-
     void setWaitingForDrawnIfResizingChanged() {
-        for (int i = allAppWindows.size() - 1; i >= 0; --i) {
-            final WindowState win = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; --i) {
+            final WindowState win = windows.get(i);
             if (win.isDragResizeChanged()) {
                 mService.mWaitingForDrawn.add(win);
             }
@@ -1062,8 +999,8 @@
         // destroy all saved surfaces here.
         destroySavedSurfaces();
 
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = allAppWindows.get(winNdx);
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = windows.get(winNdx);
             if (win.mHasSurface && !resizingWindows.contains(win)) {
                 if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
                 resizingWindows.add(win);
@@ -1092,33 +1029,33 @@
     }
 
     void moveWindows() {
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = allAppWindows.get(winNdx);
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = windows.get(winNdx);
             if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
             win.mMovedByResize = true;
         }
     }
 
     void notifyMovedInStack() {
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = allAppWindows.get(winNdx);
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = windows.get(winNdx);
             win.notifyMovedInStack();
         }
     }
 
     void resetDragResizingChangeReported() {
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = allAppWindows.get(winNdx);
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = windows.get(winNdx);
             win.resetDragResizingChangeReported();
         }
     }
 
     void detachDisplay() {
         boolean doAnotherLayoutPass = false;
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
             // We are in the middle of changing the state of displays/stacks/tasks. We need
             // to finish that, before we let layout interfere with it.
-            mService.removeWindowLocked(allAppWindows.get(winNdx));
+            windows.get(winNdx).removeIfPossible();
             doAnotherLayoutPass = true;
         }
         if (doAnotherLayoutPass) {
@@ -1127,8 +1064,8 @@
     }
 
     void forceWindowsScaleableInTransaction(boolean force) {
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowStateAnimator winAnimator = allAppWindows.get(winNdx).mWinAnimator;
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
             if (winAnimator == null || !winAnimator.hasSurface()) {
                 continue;
             }
@@ -1137,8 +1074,8 @@
     }
 
     boolean isAnimating() {
-        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowStateAnimator winAnimator = allAppWindows.get(winNdx).mWinAnimator;
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
             if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
                 return true;
             }
@@ -1148,8 +1085,8 @@
 
     void setAppLayoutChanges(int changes, String reason, int displayId) {
         final WindowAnimator windowAnimator = mAppAnimator.mAnimator;
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            if (displayId == allAppWindows.get(i).getDisplayId()) {
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            if (displayId == windows.get(i).getDisplayId()) {
                 windowAnimator.setPendingLayoutChanges(displayId, changes);
                 if (DEBUG_LAYOUT_REPEATS) {
                     mService.mWindowPlacerLocked.debugLayoutRepeats(
@@ -1161,8 +1098,8 @@
     }
 
     void removeReplacedWindowIfNeeded(WindowState replacement) {
-        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
-            final WindowState win = allAppWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState win = windows.get(i);
             if (win.mWillReplaceWindow && win.mReplacingWindow == replacement
                     && replacement.hasDrawnLw()) {
                 replacement.mSkipEnterAnimationForSeamlessReplacement = false;
@@ -1185,9 +1122,9 @@
                     mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
                 }
             }
-            final int count = allAppWindows.size();
+            final int count = windows.size();
             for (int i = 0; i < count; i++) {
-                final WindowState w = allAppWindows.get(i);
+                final WindowState w = windows.get(i);
                 w.mAppFreezing = true;
             }
         }
@@ -1198,10 +1135,10 @@
             return;
         }
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force);
-        final int count = allAppWindows.size();
+        final int count = windows.size();
         boolean unfrozeWindows = false;
         for (int i = 0; i < count; i++) {
-            final WindowState w = allAppWindows.get(i);
+            final WindowState w = windows.get(i);
             if (w.mAppFreezing) {
                 w.mAppFreezing = false;
                 if (w.mHasSurface && !w.mOrientationChanging
@@ -1260,7 +1197,6 @@
             fromToken.startingWindow = null;
             fromToken.startingMoved = true;
             tStartingWindow.mToken = this;
-            tStartingWindow.mRootToken = this;
             tStartingWindow.mAppToken = this;
 
             if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
@@ -1270,8 +1206,7 @@
             if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
                     "Removing starting " + tStartingWindow + " from " + fromToken);
             fromToken.removeWindow(tStartingWindow);
-            fromToken.allAppWindows.remove(tStartingWindow);
-            addWindowToList(tStartingWindow);
+            addWindow(tStartingWindow);
 
             // Propagate other interesting state between the tokens. If the old token is displayed,
             // we should immediately force the new one to be displayed. If it is animating, we need
@@ -1331,25 +1266,19 @@
     }
 
     int getWindowsCount() {
-        return allAppWindows.size();
+        return windows.size();
     }
 
     void setAllAppWinAnimators() {
         final ArrayList<WindowStateAnimator> allAppWinAnimators = mAppAnimator.mAllAppWinAnimators;
         allAppWinAnimators.clear();
 
-        final int windowsCount = allAppWindows.size();
+        final int windowsCount = windows.size();
         for (int j = 0; j < windowsCount; j++) {
-            allAppWinAnimators.add(allAppWindows.get(j).mWinAnimator);
+            allAppWinAnimators.add(windows.get(j).mWinAnimator);
         }
     }
 
-    /** Returns true if the app token windows list is empty. */
-    @Override
-    boolean isEmpty() {
-        return allAppWindows.isEmpty();
-    }
-
     @Override
     AppWindowToken asAppWindowToken() {
         // I am an app window token!
@@ -1362,9 +1291,6 @@
         if (appToken != null) {
             pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
         }
-        if (allAppWindows.size() > 0) {
-            pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
-        }
         pw.print(prefix); pw.print("task="); pw.println(mTask);
         pw.print(prefix); pw.print(" appFullscreen="); pw.print(appFullscreen);
                 pw.print(" requestedOrientation="); pw.println(requestedOrientation);
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 00781c5..b9c55a5 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -87,7 +87,7 @@
             WindowState windowState = (WindowState) inputWindowHandle.windowState;
             if (windowState != null) {
                 Slog.i(TAG_WM, "WINDOW DIED " + windowState);
-                mService.removeWindowLocked(windowState);
+                windowState.removeIfPossible();
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index dee9cc3..6515fbd 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -363,7 +363,7 @@
                             + " destroying=" + win.mDestroying
                             + " parentHidden=" + win.isParentWindowHidden()
                             + " vis=" + win.mViewVisibility
-                            + " hidden=" + win.mRootToken.hidden
+                            + " hidden=" + win.mToken.hidden
                             + " anim=" + win.mWinAnimator.mAnimation);
                 } else if (canBeForceHidden) {
                     if (shouldBeForceHidden) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 74c5968..8f7896e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1270,12 +1270,12 @@
             moveInputMethodDialogsLocked(pos + 1);
             return;
         }
-        win.mToken.addWindowToList(win);
+        win.mToken.addWindow(win);
         moveInputMethodDialogsLocked(pos);
     }
 
     private void reAddWindowToListInOrderLocked(WindowState win) {
-        win.mToken.addWindowToList(win);
+        win.mToken.addWindow(win);
         // This is a hack to get all of the child windows added as well at the right position. Child
         // windows should be rare and this case should be rare, so it shouldn't be that big a deal.
         WindowList windows = win.getWindowList();
@@ -1284,7 +1284,7 @@
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "ReAdd removing from " + wpos + ": " + win);
             windows.remove(wpos);
             mWindowsChanged = true;
-            win.reAddWindowLocked(wpos);
+            win.reAddWindow(wpos);
         }
     }
 
@@ -1326,7 +1326,7 @@
             if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Adding " + N + " dialogs at pos=" + pos);
             for (int i=0; i<N; i++) {
                 WindowState win = dialogs.get(i);
-                pos = win.reAddWindowLocked(pos);
+                pos = win.reAddWindow(pos);
             }
             if (DEBUG_INPUT_METHOD) {
                 Slog.v(TAG_WM, "Final window list:");
@@ -1405,7 +1405,7 @@
                     Slog.v(TAG_WM, "List after removing with new pos " + imPos + ":");
                     logWindowList(windows, "  ");
                 }
-                imWin.reAddWindowLocked(imPos);
+                imWin.reAddWindow(imPos);
                 if (DEBUG_INPUT_METHOD) {
                     Slog.v(TAG_WM, "List after moving IM to " + imPos + ":");
                     logWindowList(windows, "  ");
@@ -1462,7 +1462,7 @@
         }
 
         boolean reportNewConfig = false;
-        WindowState attachedWindow = null;
+        WindowState parentWindow = null;
         long origId;
         final int type = attrs.type;
 
@@ -1489,14 +1489,14 @@
             }
 
             if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
-                attachedWindow = windowForClientLocked(null, attrs.token, false);
-                if (attachedWindow == null) {
+                parentWindow = windowForClientLocked(null, attrs.token, false);
+                if (parentWindow == null) {
                     Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                 }
-                if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
-                        && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
+                if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
+                        && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                     Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
@@ -1508,46 +1508,52 @@
                 return WindowManagerGlobal.ADD_PERMISSION_DENIED;
             }
 
-            WindowToken token = mTokenMap.get(attrs.token);
             AppWindowToken atoken = null;
+            final boolean hasParent = parentWindow != null;
+            // Use existing parent window token for child windows since they go in the same token
+            // as there parent window so we can apply the same policy on them.
+            WindowToken token = mTokenMap.get(hasParent ? parentWindow.mAttrs.token : attrs.token);
+            // If this is a child window, we want to apply the same type checking rules as the
+            // parent window type.
+            final int rootType = hasParent ? parentWindow.mAttrs.type : type;
             if (token == null) {
-                if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
+                if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                     Slog.w(TAG_WM, "Attempted to add application window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (type == TYPE_INPUT_METHOD) {
+                if (rootType == TYPE_INPUT_METHOD) {
                     Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (type == TYPE_VOICE_INTERACTION) {
+                if (rootType == TYPE_VOICE_INTERACTION) {
                     Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (type == TYPE_WALLPAPER) {
+                if (rootType == TYPE_WALLPAPER) {
                     Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (type == TYPE_DREAM) {
+                if (rootType == TYPE_DREAM) {
                     Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (type == TYPE_QS_DIALOG) {
+                if (rootType == TYPE_QS_DIALOG) {
                     Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (type == TYPE_ACCESSIBILITY_OVERLAY) {
+                if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
                     Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 token = new WindowToken(this, attrs.token, -1, false);
-            } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
+            } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                 atoken = token.asAppWindowToken();
                 if (atoken == null) {
                     Slog.w(TAG_WM, "Attempted to add window with non-application token "
@@ -1558,57 +1564,57 @@
                           + token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_APP_EXITING;
                 }
-                if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
+                if (rootType == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
                     // No need for this guy!
                     if (DEBUG_STARTING_WINDOW || localLOGV) Slog.v(
                             TAG_WM, "**** NO NEED TO START: " + attrs.getTitle());
                     return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
                 }
-            } else if (type == TYPE_INPUT_METHOD) {
+            } else if (rootType == TYPE_INPUT_METHOD) {
                 if (token.windowType != TYPE_INPUT_METHOD) {
                     Slog.w(TAG_WM, "Attempted to add input method window with bad token "
                             + attrs.token + ".  Aborting.");
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (type == TYPE_VOICE_INTERACTION) {
+            } else if (rootType == TYPE_VOICE_INTERACTION) {
                 if (token.windowType != TYPE_VOICE_INTERACTION) {
                     Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token "
                             + attrs.token + ".  Aborting.");
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (type == TYPE_WALLPAPER) {
+            } else if (rootType == TYPE_WALLPAPER) {
                 if (token.windowType != TYPE_WALLPAPER) {
                     Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token "
                             + attrs.token + ".  Aborting.");
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (type == TYPE_DREAM) {
+            } else if (rootType == TYPE_DREAM) {
                 if (token.windowType != TYPE_DREAM) {
                     Slog.w(TAG_WM, "Attempted to add Dream window with bad token "
                             + attrs.token + ".  Aborting.");
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (type == TYPE_ACCESSIBILITY_OVERLAY) {
+            } else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
                 if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
                     Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token "
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (type == TYPE_QS_DIALOG) {
+            } else if (rootType == TYPE_QS_DIALOG) {
                 if (token.windowType != TYPE_QS_DIALOG) {
                     Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (token.asAppWindowToken() != null) {
-                Slog.w(TAG_WM, "Non-null appWindowToken for system window of type=" + type);
+                Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType);
                 // It is not valid to use an app token with other system types; we will
                 // instead make a new token for it (as if null had been passed in for the token).
                 attrs.token = null;
                 token = new WindowToken(this, null, -1, false);
             }
 
-            WindowState win = new WindowState(this, session, client, token, attachedWindow,
+            WindowState win = new WindowState(this, session, client, token, parentWindow,
                     appOp[0], seq, attrs, viewVisibility, displayContent, session.mUid);
             if (win.mDeathRecipient == null) {
                 // Client has apparently died, so there is no reason to
@@ -1674,11 +1680,11 @@
                 imMayMove = false;
             } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                 mInputMethodDialogs.add(win);
-                win.mToken.addWindowToList(win);
+                win.mToken.addWindow(win);
                 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
                 imMayMove = false;
             } else {
-                win.mToken.addWindowToList(win);
+                win.mToken.addWindow(win);
                 if (type == TYPE_WALLPAPER) {
                     mWallpaperControllerLocked.clearLastWallpaperTimeoutTime();
                     displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
@@ -1873,14 +1879,10 @@
             if (win == null) {
                 return;
             }
-            removeWindowLocked(win);
+            win.removeIfPossible();
         }
     }
 
-    void removeWindowLocked(WindowState win) {
-        win.removeIfPossible(false /*keepVisibleDeadWindow*/);
-    }
-
     /**
      * Performs some centralized bookkeeping clean-up on the window that is being removed.
      * NOTE: Should only be called from {@link WindowState#remove()}
@@ -8220,16 +8222,13 @@
     // Internals
     // -------------------------------------------------------------
 
-    final WindowState windowForClientLocked(Session session, IWindow client,
-            boolean throwOnError) {
+    final WindowState windowForClientLocked(Session session, IWindow client, boolean throwOnError) {
         return windowForClientLocked(session, client.asBinder(), throwOnError);
     }
 
-    final WindowState windowForClientLocked(Session session, IBinder client,
-            boolean throwOnError) {
+    final WindowState windowForClientLocked(Session session, IBinder client, boolean throwOnError) {
         WindowState win = mWindowMap.get(client);
-        if (localLOGV) Slog.v(
-            TAG_WM, "Looking up client " + client + ": " + win);
+        if (localLOGV) Slog.v(TAG_WM, "Looking up client " + client + ": " + win);
         if (win == null) {
             RuntimeException ex = new IllegalArgumentException(
                     "Requested window " + client + " does not exist");
@@ -8289,15 +8288,13 @@
             i++;
         }
 
-        // Keep whatever windows were below the app windows still below,
-        // by skipping them.
+        // Keep whatever windows were below the app windows still below, by skipping them.
         lastBelow++;
         i = lastBelow;
 
-        // First add all of the exiting app tokens...  these are no longer
-        // in the main app list, but still have windows shown.  We put them
-        // in the back because now that the animation is over we no longer
-        // will care about them.
+        // First add all of the exiting app tokens...  these are no longer in the main app list,
+        // but still have windows shown. We put them in the back because now that the animation is
+        // over we no longer will care about them.
         final ArrayList<TaskStack> stacks = displayContent.getStacks();
         final int numStacks = stacks.size();
         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d9836a8..546498a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -165,7 +165,7 @@
     final int mOwnerUid;
     final IWindowId mWindowId;
     WindowToken mToken;
-    WindowToken mRootToken;
+    // The same object as mToken if this is an app window and null for non-app windows.
     AppWindowToken mAppToken;
 
     // mAttrs.flags is tested in animation without being locked. If the bits tested are ever
@@ -554,6 +554,7 @@
         mClient = c;
         mAppOp = appOp;
         mToken = token;
+        mAppToken = mToken.asAppWindowToken();
         mOwnerUid = ownerId;
         mWindowId = new IWindowId.Stub() {
             @Override
@@ -627,8 +628,6 @@
         }
         mIsFloatingLayer = mIsImWindow || mIsWallpaper;
 
-        mRootToken = getTopParentWindow().mToken;
-        mAppToken = mRootToken.asAppWindowToken();
         if (mAppToken != null) {
             final DisplayContent appDisplay = getDisplayContent();
             mNotOnAppsDisplay = displayContent != appDisplay;
@@ -1192,14 +1191,14 @@
      */
     @Override
     public boolean isVisibleOrBehindKeyguardLw() {
-        if (mRootToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
+        if (mToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
             return false;
         }
         final AppWindowToken atoken = mAppToken;
         final boolean animating = atoken != null && atoken.mAppAnimator.animation != null;
         return mHasSurface && !mDestroying && !mAnimatingExit
                 && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
-                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
+                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
                         || mWinAnimator.mAnimation != null || animating);
     }
 
@@ -1217,7 +1216,7 @@
      * not the pending requested hidden state.
      */
     boolean isVisibleNow() {
-        return (!mRootToken.hidden || mAttrs.type == TYPE_APPLICATION_STARTING)
+        return (!mToken.hidden || mAttrs.type == TYPE_APPLICATION_STARTING)
                 && isVisibleUnchecked();
     }
 
@@ -1299,11 +1298,11 @@
      * of a transition that has not yet been started.
      */
     boolean isReadyForDisplay() {
-        if (mRootToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
+        if (mToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
             return false;
         }
         return mHasSurface && mPolicyVisibility && !mDestroying
-                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
+                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
                         || mWinAnimator.mAnimation != null
                         || ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null)));
     }
@@ -1313,7 +1312,7 @@
      * to the keyguard.
      */
     boolean isReadyForDisplayIgnoringKeyguard() {
-        if (mRootToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
+        if (mToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
             return false;
         }
         final AppWindowToken atoken = mAppToken;
@@ -1323,7 +1322,7 @@
             return false;
         }
         return mHasSurface && !mDestroying
-                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
+                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
                         || mWinAnimator.mAnimation != null
                         || ((atoken != null) && (atoken.mAppAnimator.animation != null)
                                 && !mWinAnimator.isDummyAnimation()));
@@ -1357,7 +1356,7 @@
         final AppWindowToken atoken = mAppToken;
         return mViewVisibility == View.GONE
                 || !mRelayoutCalled
-                || (atoken == null && mRootToken.hidden)
+                || (atoken == null && mToken.hidden)
                 || (atoken != null && atoken.hiddenRequested)
                 || isParentWindowHidden()
                 || (mAnimatingExit && !isAnimatingLw())
@@ -1487,6 +1486,10 @@
         mService.postWindowRemoveCleanupLocked(this);
     }
 
+    void removeIfPossible() {
+        removeIfPossible(false /*keepVisibleDeadWindow*/);
+    }
+
     void removeIfPossible(boolean keepVisibleDeadWindow) {
         mWindowRemovalAllowed = true;
         if (DEBUG_ADD_REMOVE) Slog.v(TAG,
@@ -1950,7 +1953,7 @@
                         }
                     } else if (mHasSurface) {
                         Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
-                        mService.removeWindowLocked(WindowState.this);
+                        WindowState.this.removeIfPossible();
                     }
                 }
             } catch (IllegalArgumentException ex) {
@@ -2728,7 +2731,6 @@
         }
         if (dumpAll) {
             pw.print(prefix); pw.print("mToken="); pw.println(mToken);
-            pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
             if (mAppToken != null) {
                 pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
                 pw.print(prefix); pw.print(" isAnimatingWithSavedSurface()=");
@@ -3020,7 +3022,7 @@
     /** Returns the topmost parent window if this is a child of another window, else this. */
     WindowState getTopParentWindow() {
         WindowState w = this;
-        while (w.mIsChildWindow) {
+        while (w != null && w.mIsChildWindow) {
             w = w.getParentWindow();
         }
         return w;
@@ -3215,7 +3217,7 @@
     // TODO: come-up with a better name for this method that represents what it does.
     // Or, it is probably not going to matter anyways if we are successful in getting rid of
     // the WindowList concept.
-    int reAddWindowLocked(int index) {
+    int reAddWindow(int index) {
         final WindowList windows = getWindowList();
         // Adding child windows relies on child windows being ordered by mSubLayer using
         // {@link #sWindowSubLayerComparator}.
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 25709c5..c26c078 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -956,13 +956,13 @@
                 if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
                         + win.mViewVisibility + " mRelayoutCalled="
                         + win.mRelayoutCalled + " hidden="
-                        + win.mRootToken.hidden + " hiddenRequested="
+                        + win.mToken.hidden + " hiddenRequested="
                         + (atoken != null && atoken.hiddenRequested)
                         + " parentHidden=" + win.isParentWindowHidden());
                 else Slog.v(TAG, "  VIS: mViewVisibility="
                         + win.mViewVisibility + " mRelayoutCalled="
                         + win.mRelayoutCalled + " hidden="
-                        + win.mRootToken.hidden + " hiddenRequested="
+                        + win.mToken.hidden + " hiddenRequested="
                         + (atoken != null && atoken.hiddenRequested)
                         + " parentHidden=" + win.isParentWindowHidden());
             }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 7ed16f5..00e71f2 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.annotation.CallSuper;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
@@ -95,10 +96,16 @@
     }
 
     void removeAllWindows() {
-        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+        for (int winNdx = windows.size() - 1; winNdx >= 0;
+                // WindowState#removeIfPossible() at bottom of loop may remove multiple entries from
+                // allAppWindows if the window to be removed has child windows. It also may not
+                // remove any windows from allAppWindows at all if win is exiting and currently
+                // animating away. This ensures that winNdx is monotonically decreasing and never
+                // beyond allAppWindows bounds.
+                winNdx = Math.min(winNdx - 1, windows.size() - 1)) {
             WindowState win = windows.get(winNdx);
             if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM, "removeAllWindows: removing win=" + win);
-            win.mService.removeWindowLocked(win);
+            win.removeIfPossible();
         }
         windows.clear();
     }
@@ -157,6 +164,9 @@
             if (animLayer > highestAnimLayer) {
                 highestAnimLayer = animLayer;
             }
+            if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
+                mService.mLayersController.setInputMethodAnimLayerAdjustment(adj);
+            }
         }
         return highestAnimLayer;
     }
@@ -258,8 +268,7 @@
         }
     }
 
-    // TODO: Rename to addWindow when conflict with AppWindowToken is resolved. The call below.
-    void addWindowToList(final WindowState win) {
+    void addWindow(final WindowState win) {
         if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
 
         if (!win.isChildWindow()) {
@@ -276,11 +285,6 @@
         } else {
             addChildWindow(win);
         }
-
-        final AppWindowToken appToken = win.mAppToken;
-        if (appToken != null) {
-            appToken.addWindow(win);
-        }
     }
 
     private int addAppWindow(final WindowState win) {
@@ -451,10 +455,20 @@
         final int count = windows.size();
         for (int i = 0; i < count; i++) {
             final WindowState win = windows.get(i);
+            if (win.isChildWindow()) {
+                // The WindowState.reAddWindow below already takes care of re-adding the
+                // child windows for any parent window in this token. This is a side effect of
+                // ensuring child windows are in the same WindowToken as their parent window.
+                //
+                // TODO: Can be removed once WindowToken no longer contains child windows. i.e it is
+                // using WindowContainer which uses the hierarchy to access child windows through
+                // their parent window.
+                continue;
+            }
             final DisplayContent winDisplayContent = win.getDisplayContent();
             if (winDisplayContent == displayContent || winDisplayContent == null) {
                 win.mDisplayContent = displayContent;
-                index = win.reAddWindowLocked(index);
+                index = win.reAddWindow(index);
             }
         }
         return index;
@@ -486,6 +500,7 @@
         return null;
     }
 
+    @CallSuper
     void removeWindow(WindowState win) {
         windows.remove(win);
     }