Merge changes from topic 'keyguard_refactor'

* changes:
  The big keyguard transition refactor (6/n)
  The big keyguard transition refactor (5/n)
  The big keyguard transition refactor (4/n)
  The big keyguard transition refactor (3/n)
  The big keyguard transition refactor (2/n)
  The big keyguard transition refactor (1/n)
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0ba937a..1ee31d8 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.IIntentSender;
 import android.content.Intent;
@@ -179,4 +180,13 @@
      * (-1).
      */
     public abstract int getUidProcessState(int uid);
+
+    /**
+     * Called when Keyguard flags might have changed.
+     *
+     * @param callback Callback to run after activity visibilities have been reevaluated. This can
+     *                 be used from window manager so that when the callback is called, it's
+     *                 guaranteed that all apps have their visibility updated accordingly.
+     */
+    public abstract void notifyKeyguardFlagsChanged(@Nullable Runnable callback);
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 623a11d..15f6361 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1555,8 +1555,7 @@
         case SET_LOCK_SCREEN_SHOWN_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final boolean showing = data.readInt() != 0;
-            final boolean occluded = data.readInt() != 0;
-            setLockScreenShown(showing, occluded);
+            setLockScreenShown(showing);
             reply.writeNoException();
             return true;
         }
@@ -2337,13 +2336,6 @@
             return true;
         }
 
-        case KEYGUARD_WAITING_FOR_ACTIVITY_DRAWN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            keyguardWaitingForActivityDrawn();
-            reply.writeNoException();
-            return true;
-        }
-
         case KEYGUARD_GOING_AWAY_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             keyguardGoingAway(data.readInt());
@@ -5035,13 +5027,12 @@
         reply.recycle();
         return pfd;
     }
-    public void setLockScreenShown(boolean showing, boolean occluded) throws RemoteException
+    public void setLockScreenShown(boolean showing) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(showing ? 1 : 0);
-        data.writeInt(occluded ? 1 : 0);
         mRemote.transact(SET_LOCK_SCREEN_SHOWN_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -6060,16 +6051,6 @@
         reply.recycle();
     }
 
-    public void keyguardWaitingForActivityDrawn() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(KEYGUARD_WAITING_FOR_ACTIVITY_DRAWN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
     public void keyguardGoingAway(int flags)
             throws RemoteException {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 7b25c76..0323651 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -357,8 +357,7 @@
     public void killPackageDependents(final String packageName, int userId) throws RemoteException;
     public void forceStopPackage(final String packageName, int userId) throws RemoteException;
 
-    // Note: probably don't want to allow applications access to these.
-    public void setLockScreenShown(boolean showing, boolean occluded) throws RemoteException;
+    public void setLockScreenShown(boolean showing) throws RemoteException;
 
     public void unhandledBack() throws RemoteException;
     public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException;
@@ -518,8 +517,6 @@
 
     public void showBootMessage(CharSequence msg, boolean always) throws RemoteException;
 
-    public void keyguardWaitingForActivityDrawn() throws RemoteException;
-
     /**
      * Notify the system that the keyguard is going away.
      *
@@ -1017,7 +1014,6 @@
     int NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+228;
     int START_ACTIVITY_FROM_RECENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 229;
     int NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+230;
-    int KEYGUARD_WAITING_FOR_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+231;
     int START_ACTIVITY_AS_CALLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+232;
     int ADD_APP_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+233;
     int GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+234;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 986ff46..39d7883 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -213,16 +213,6 @@
     void dismissKeyguard();
     void keyguardGoingAway(int flags);
 
-    /**
-     * Called to tell WindowManager whether the keyguard is animating in. While this property
-     * is true, WindowManager won't assume that the keyguard is opaque (eg. WindowAnimator won't
-     * force-hide windows just because keyguard is visible and WallpaperController won't occlude
-     * app windows with the system wallpaper.
-     *
-     * <p>Requires CONTROL_KEYGUARD permission</p>
-     */
-    void setKeyguardAnimatingIn(boolean animating);
-
     // Requires INTERACT_ACROSS_USERS_FULL permission
     void setSwitchingUser(boolean switching);
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f14acaa..106b211 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -599,13 +599,6 @@
         public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
 
         /**
-         * Window type: keyguard scrim window. Shows if keyguard needs to be restarted.
-         * In multiuser systems shows on all users' windows.
-         * @hide
-         */
-        public static final int TYPE_KEYGUARD_SCRIM           = FIRST_SYSTEM_WINDOW+29;
-
-        /**
          * Window type: Window for Presentation on top of private
          * virtual display.
          */
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 653e583..f61a637 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -99,19 +99,30 @@
 
         /**
          * Called when a pending app transition gets cancelled.
+         *
+         * @param transit transition type indicating what kind of transition got cancelled
          */
-        public void onAppTransitionCancelledLocked() {}
+        public void onAppTransitionCancelledLocked(int transit) {}
 
         /**
          * Called when an app transition gets started
          *
+         * @param transit transition type indicating what kind of transition gets run, must be one
+         *                of AppTransition.TRANSIT_* values
          * @param openToken the token for the opening app
          * @param closeToken the token for the closing app
          * @param openAnimation the animation for the opening app
          * @param closeAnimation the animation for the closing app
+         *
+         * @return Return any bit set of {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
+         * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
+         * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER},
+         * or {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
          */
-        public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
-                Animation openAnimation, Animation closeAnimation) {}
+        public int onAppTransitionStartingLocked(int transit, IBinder openToken, IBinder closeToken,
+                Animation openAnimation, Animation closeAnimation) {
+            return 0;
+        }
 
         /**
          * Called when an app transition is finished running.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index a6be493..a8d70c4 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -136,10 +136,10 @@
             throws RemoteException;
 
     /**
-     * @return true if windows with FLAG_DISMISS_KEYGUARD should be allowed to show even if
-     *         the keyguard is locked.
+     * Called when the Keyguard occluded state changed.
+     * @param occluded Whether Keyguard is currently occluded or not.
      */
-    boolean canShowDismissingWindowWhileLockedLw();
+    void onKeyguardOccludedChangedLw(boolean occluded);
 
     /**
      * Interface to the Window Manager state associated with a particular
@@ -424,6 +424,10 @@
         public boolean isInMultiWindowMode();
 
         public int getRotationAnimationHint();
+
+        public boolean isInputMethodWindow();
+
+        public int getDisplayId();
     }
 
     /**
@@ -509,9 +513,9 @@
         void getStackBounds(int stackId, Rect outBounds);
 
         /**
-         * Overrides all currently playing app animations with {@param a}.
+         * Notifies window manager that {@link #isShowingDreamLw} has changed.
          */
-        void overridePlayingAppAnimationsLw(Animation a);
+        void notifyShowingDreamChanged();
     }
 
     public interface PointerEventListener {
@@ -699,31 +703,15 @@
             int uiMode);
 
     /**
-     * Return whether the given window is forcibly hiding all windows except windows with
-     * FLAG_SHOW_WHEN_LOCKED set.  Typically returns true for the keyguard.
-     */
-    public boolean isForceHiding(WindowManager.LayoutParams attrs);
-
-
-    /**
-     * Return whether the given window can become one that passes isForceHiding() test.
-     * Typically returns true for the StatusBar.
+     * Return whether the given window can become the Keyguard window. Typically returns true for
+     * the StatusBar.
      */
     public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs);
 
     /**
-     * Determine if a window that is behind one that is force hiding
-     * (as determined by {@link #isForceHiding}) should actually be hidden.
-     * For example, typically returns false for the status bar.  Be careful
-     * to return false for any window that you may hide yourself, since this
-     * will conflict with what you set.
+     * @return whether {@param win} can be hidden by Keyguard
      */
-    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs);
-
-    /**
-     * Return the window that is hiding the keyguard, if such a thing exists.
-     */
-    public WindowState getWinShowWhenLockedLw();
+    public boolean canBeHiddenByKeyguardLw(WindowState win);
 
     /**
      * Called when the system would like to show a UI to indicate that an
@@ -834,16 +822,16 @@
             boolean forceDefault);
 
     /**
-     * Create and return an animation to re-display a force hidden window.
+     * Create and return an animation to re-display a window that was force hidden by Keyguard.
      */
-    public Animation createForceHideEnterAnimation(boolean onWallpaper,
+    public Animation createHiddenByKeyguardExit(boolean onWallpaper,
             boolean goingToNotificationShade);
 
     /**
-     * Create and return an animation to let the wallpaper disappear after being shown on a force
-     * hiding window.
+     * Create and return an animation to let the wallpaper disappear after being shown behind
+     * Keyguard.
      */
-    public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade);
+    public Animation createKeyguardWallpaperExit(boolean goingToNotificationShade);
 
     /**
      * Called from the input reader thread before a key is enqueued.
@@ -1000,7 +988,7 @@
      * @param attached For sub-windows, the window it is attached to. Otherwise null.
      */
     public void applyPostLayoutPolicyLw(WindowState win,
-            WindowManager.LayoutParams attrs, WindowState attached);
+            WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget);
 
     /**
      * Called following layout of all windows and after policy has been applied
@@ -1147,11 +1135,11 @@
     public boolean isKeyguardSecure(int userId);
 
     /**
-     * Return whether the keyguard is on.
+     * Return whether the keyguard is currently occluded.
      *
-     * @return true if in keyguard is on.
+     * @return true if in keyguard is occluded, false otherwise
      */
-    public boolean isKeyguardShowingOrOccluded();
+    public boolean isKeyguardOccluded();
 
     /**
      * @return true if in keyguard is on and not occluded.
@@ -1159,6 +1147,11 @@
     public boolean isKeyguardShowingAndNotOccluded();
 
     /**
+     * @return whether Keyguard is in trusted state and can be dismissed without credentials
+     */
+    public boolean isKeyguardTrustedLw();
+
+    /**
      * inKeyguardRestrictedKeyInputMode
      *
      * if keyguard screen is showing or in restricted key input mode (i.e. in
@@ -1175,11 +1168,6 @@
     public void dismissKeyguardLw();
 
     /**
-     * Notifies the keyguard that the activity has drawn it was waiting for.
-     */
-    public void notifyActivityDrawnForKeyguardLw();
-
-    /**
      * Ask the policy whether the Keyguard has drawn. If the Keyguard is disabled, this method
      * returns true as soon as we know that Keyguard is disabled.
      *
@@ -1187,6 +1175,8 @@
      */
     public boolean isKeyguardDrawnLw();
 
+    public boolean isShowingDreamLw();
+
     /**
      * Given an orientation constant, returns the appropriate surface rotation,
      * taking into account sensors, docking mode, rotation lock, and other factors.
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 50dd33a..788103d 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -34,7 +34,6 @@
 
     void addStateMonitorCallback(IKeyguardStateCallback callback);
     void verifyUnlock(IKeyguardExitCallback callback);
-    void keyguardDone(boolean authenticated, boolean wakeup);
     void dismiss(boolean allowWhileOccluded);
     void onDreamingStarted();
     void onDreamingStopped();
@@ -93,10 +92,4 @@
      * @param fadeoutDuration the duration of the exit animation, in milliseconds
      */
     void startKeyguardExitAnimation(long startTime, long fadeoutDuration);
-
-    /**
-     * Notifies the Keyguard that the activity that was starting has now been drawn and it's safe
-     * to start the keyguard dismiss sequence.
-     */
-    void onActivityDrawn();
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
index 474ffea..327d218 100644
--- a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
@@ -76,12 +76,6 @@
     void playTrustedSound();
 
     /**
-     * @return true if and only if Keyguard is showing or if Keyguard is disabled by an external app
-     *         (legacy API)
-     */
-    boolean isInputRestricted();
-
-    /**
      * @return true if the screen is on
      */
     boolean isScreenOn();
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
index a616369..4947863 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
@@ -31,7 +31,7 @@
 
     // This should be incremented any time this class or ActivityStarter or BaseStatusBarHeader
     // change in incompatible ways.
-    public static final int VERSION = 2;
+    public static final int VERSION = 3;
 
     public QSContainer(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
@@ -116,7 +116,6 @@
         void startPendingIntentDismissingKeyguard(PendingIntent intent);
         void startActivity(Intent intent, boolean dismissShade);
         void startActivity(Intent intent, boolean dismissShade, Callback callback);
-        void preventNextAnimation();
 
         interface Callback {
             void onActivityStarted(int resultCode);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index e05e507..816d70d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -81,15 +81,6 @@
         }
 
         @Override // Binder interface
-        public void keyguardDone(boolean authenticated, boolean wakeup) {
-            Trace.beginSection("KeyguardService.mBinder#keyguardDone");
-            checkPermission();
-            // TODO: Remove wakeup
-            mKeyguardViewMediator.keyguardDone(authenticated);
-            Trace.endSection();
-        }
-
-        @Override // Binder interface
         public void setOccluded(boolean isOccluded, boolean animate) {
             Trace.beginSection("KeyguardService.mBinder#setOccluded");
             checkPermission();
@@ -202,12 +193,6 @@
             mKeyguardViewMediator.startKeyguardExitAnimation(startTime, fadeoutDuration);
             Trace.endSection();
         }
-
-        @Override
-        public void onActivityDrawn() {
-            checkPermission();
-            mKeyguardViewMediator.onActivityDrawn();
-        }
     };
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 24247e4..9ae341a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -135,7 +135,6 @@
 
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
-    private final static boolean DBG_WAKE = false;
 
     private final static String TAG = "KeyguardViewMediator";
 
@@ -145,25 +144,23 @@
             "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_LOCK";
 
     // used for handler messages
-    private static final int SHOW = 2;
-    private static final int HIDE = 3;
-    private static final int RESET = 4;
-    private static final int VERIFY_UNLOCK = 5;
-    private static final int NOTIFY_FINISHED_GOING_TO_SLEEP = 6;
-    private static final int NOTIFY_SCREEN_TURNING_ON = 7;
-    private static final int KEYGUARD_DONE = 9;
-    private static final int KEYGUARD_DONE_DRAWING = 10;
-    private static final int KEYGUARD_DONE_AUTHENTICATING = 11;
-    private static final int SET_OCCLUDED = 12;
-    private static final int KEYGUARD_TIMEOUT = 13;
-    private static final int DISMISS = 17;
-    private static final int START_KEYGUARD_EXIT_ANIM = 18;
-    private static final int ON_ACTIVITY_DRAWN = 19;
-    private static final int KEYGUARD_DONE_PENDING_TIMEOUT = 20;
-    private static final int NOTIFY_STARTED_WAKING_UP = 21;
-    private static final int NOTIFY_SCREEN_TURNED_ON = 22;
-    private static final int NOTIFY_SCREEN_TURNED_OFF = 23;
-    private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 24;
+    private static final int SHOW = 1;
+    private static final int HIDE = 2;
+    private static final int RESET = 3;
+    private static final int VERIFY_UNLOCK = 4;
+    private static final int NOTIFY_FINISHED_GOING_TO_SLEEP = 5;
+    private static final int NOTIFY_SCREEN_TURNING_ON = 6;
+    private static final int KEYGUARD_DONE = 7;
+    private static final int KEYGUARD_DONE_DRAWING = 8;
+    private static final int SET_OCCLUDED = 9;
+    private static final int KEYGUARD_TIMEOUT = 10;
+    private static final int DISMISS = 11;
+    private static final int START_KEYGUARD_EXIT_ANIM = 12;
+    private static final int KEYGUARD_DONE_PENDING_TIMEOUT = 13;
+    private static final int NOTIFY_STARTED_WAKING_UP = 14;
+    private static final int NOTIFY_SCREEN_TURNED_ON = 15;
+    private static final int NOTIFY_SCREEN_TURNED_OFF = 16;
+    private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17;
 
     /**
      * The default amount of time we stay awake (used for all key input)
@@ -185,11 +182,6 @@
     private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000;
 
     /**
-     * Secure setting whether analytics are collected on the keyguard.
-     */
-    private static final String KEYGUARD_ANALYTICS_SETTING = "keyguard_analytics";
-
-    /**
      * Boolean option for doKeyguardLocked/doKeyguardTimeout which, when set to true, forces the
      * keyguard to show even if it is disabled for the current user.
      */
@@ -209,16 +201,9 @@
     /** High level access to the power manager for WakeLocks */
     private PowerManager mPM;
 
-    /** High level access to the window manager for dismissing keyguard animation */
-    private IWindowManager mWM;
-
-
     /** TrustManager for letting it know when we change visibility */
     private TrustManager mTrustManager;
 
-    /** SearchManager for determining whether or not search assistant is available */
-    private SearchManager mSearchManager;
-
     /**
      * Used to keep the device awake while to ensure the keyguard finishes opening before
      * we sleep.
@@ -342,8 +327,6 @@
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
 
-    private boolean mIsPerUserLock;
-
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
@@ -533,7 +516,7 @@
             }
 
             if (!mKeyguardDonePending) {
-                KeyguardViewMediator.this.keyguardDone(true /* authenticated */);
+                KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */);
             }
             if (strongAuth) {
                 mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
@@ -584,7 +567,7 @@
             if (mKeyguardDonePending) {
                 // Somebody has called keyguardDonePending before, which means that we are
                 // authenticated
-                KeyguardViewMediator.this.keyguardDone(true /* authenticated */);
+                KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */);
             }
             Trace.endSection();
         }
@@ -600,11 +583,6 @@
         }
 
         @Override
-        public boolean isInputRestricted() {
-            return KeyguardViewMediator.this.isInputRestricted();
-        }
-
-        @Override
         public boolean isScreenOn() {
             return mDeviceInteractive;
         }
@@ -645,7 +623,6 @@
 
     private void setupLocked() {
         mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mWM = WindowManagerGlobal.getWindowManagerService();
         mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
 
         mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
@@ -720,14 +697,12 @@
      * Let us know that the system is ready after startup.
      */
     public void onSystemReady() {
-        mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
         synchronized (this) {
             if (DEBUG) Log.d(TAG, "onSystemReady");
             mSystemReady = true;
             doKeyguardLocked(null);
             mUpdateMonitor.registerCallback(mUpdateCallback);
         }
-        mIsPerUserLock = StorageManager.isFileEncryptedNativeOrEmulated();
         // Most services aren't available until the system reaches the ready state, so we
         // send it here when the device first boots.
         maybeSendUserPresentBroadcast();
@@ -1153,7 +1128,6 @@
             if (mOccluded != isOccluded) {
                 mOccluded = isOccluded;
                 mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate);
-                updateActivityLockScreenState();
                 adjustStatusBarLocked();
             }
         }
@@ -1514,9 +1488,6 @@
                     Trace.beginSection("KeyguardViewMediator#handleMessage KEYGUARD_DONE_PENDING_TIMEOUT");
                     Log.w(TAG, "Timeout while waiting for activity drawn!");
                     Trace.endSection();
-                    // Fall through.
-                case ON_ACTIVITY_DRAWN:
-                    handleOnActivityDrawn();
                     break;
             }
         }
@@ -1638,7 +1609,7 @@
     private void updateActivityLockScreenState() {
         Trace.beginSection("KeyguardViewMediator#updateActivityLockScreenState");
         try {
-            ActivityManagerNative.getDefault().setLockScreenShown(mShowing, mOccluded);
+            ActivityManagerNative.getDefault().setLockScreenShown(mShowing);
         } catch (RemoteException e) {
         }
         Trace.endSection();
@@ -1668,7 +1639,6 @@
             mWakeAndUnlocking = false;
             resetKeyguardDonePendingLocked();
             mHideAnimationRun = false;
-            updateActivityLockScreenState();
             adjustStatusBarLocked();
             userActivity();
 
@@ -1745,13 +1715,6 @@
         Trace.endSection();
     }
 
-    private void handleOnActivityDrawn() {
-        if (DEBUG) Log.d(TAG, "handleOnActivityDrawn: mKeyguardDonePending=" + mKeyguardDonePending);
-        if (mKeyguardDonePending) {
-            mStatusBarKeyguardViewManager.onActivityDrawn();
-        }
-    }
-
     private void handleStartKeyguardExitAnimation(long startTime, long fadeoutDuration) {
         Trace.beginSection("KeyguardViewMediator#handleStartKeyguardExitAnimation");
         if (DEBUG) Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
@@ -1784,7 +1747,6 @@
             mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
             resetKeyguardDonePendingLocked();
             mHideAnimationRun = false;
-            updateActivityLockScreenState();
             adjustStatusBarLocked();
             sendUserPresentBroadcast();
         }
@@ -1831,7 +1793,7 @@
     private void handleReset() {
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleReset");
-            mStatusBarKeyguardViewManager.reset();
+            mStatusBarKeyguardViewManager.reset(true /* hideBouncerWhenShowing */);
         }
     }
 
@@ -1845,7 +1807,6 @@
             if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
             setShowingLocked(true);
             mStatusBarKeyguardViewManager.verifyUnlock();
-            updateActivityLockScreenState();
         }
         Trace.endSection();
     }
@@ -1964,10 +1925,6 @@
         Trace.endSection();
     }
 
-    public void onActivityDrawn() {
-        mHandler.sendEmptyMessage(ON_ACTIVITY_DRAWN);
-    }
-
     public ViewMediatorCallback getViewMediatorCallback() {
         return mViewMediatorCallback;
     }
@@ -2027,6 +1984,7 @@
             }
             updateInputRestrictedLocked();
             mTrustManager.reportKeyguardShowingChanged();
+            updateActivityLockScreenState();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 76440d5..70e21d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -345,17 +345,12 @@
                 dismissKeyguardThenExecute(new OnDismissAction() {
                     @Override
                     public boolean onDismiss() {
-                        if (keyguardShowing && !afterKeyguardGone) {
-                            try {
-                                ActivityManagerNative.getDefault()
-                                        .keyguardWaitingForActivityDrawn();
-                                ActivityManagerNative.getDefault().resumeAppSwitches();
-                            } catch (RemoteException e) {
-                            }
+                        try {
+                            ActivityManagerNative.getDefault().resumeAppSwitches();
+                        } catch (RemoteException e) {
                         }
 
                         boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
-                        overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone);
 
                         // close the shade if it was open
                         if (handled) {
@@ -1052,24 +1047,15 @@
     }
 
     private void startNotificationGutsIntent(final Intent intent, final int appUid) {
-        final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
         dismissKeyguardThenExecute(new OnDismissAction() {
             @Override
             public boolean onDismiss() {
                 AsyncTask.execute(new Runnable() {
                     public void run() {
-                        try {
-                            if (keyguardShowing) {
-                                ActivityManagerNative.getDefault()
-                                        .keyguardWaitingForActivityDrawn();
-                            }
-                            TaskStackBuilder.create(mContext)
-                                    .addNextIntentWithParentStack(intent)
-                                    .startActivities(getActivityOptions(),
-                                            new UserHandle(UserHandle.getUserId(appUid)));
-                            overrideActivityPendingAppTransition(keyguardShowing);
-                        } catch (RemoteException e) {
-                        }
+                        TaskStackBuilder.create(mContext)
+                                .addNextIntentWithParentStack(intent)
+                                .startActivities(getActivityOptions(),
+                                        new UserHandle(UserHandle.getUserId(appUid)));
                     }
                 });
                 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
@@ -1832,11 +1818,6 @@
                     @Override
                     public void run() {
                         try {
-                            if (keyguardShowing && !afterKeyguardGone) {
-                                ActivityManagerNative.getDefault()
-                                        .keyguardWaitingForActivityDrawn();
-                            }
-
                             // The intent we are sending is for the application, which
                             // won't have permission to immediately start an activity after
                             // the user switches to home.  We know it is safe to do at this
@@ -1855,8 +1836,6 @@
                         }
                         if (intent.isActivity()) {
                             mAssistManager.hideAssist();
-                            overrideActivityPendingAppTransition(keyguardShowing
-                                    && !afterKeyguardGone);
                         }
                     }
                 }.start();
@@ -1943,11 +1922,6 @@
                         @Override
                         public void run() {
                             try {
-                                if (keyguardShowing && !afterKeyguardGone) {
-                                    ActivityManagerNative.getDefault()
-                                            .keyguardWaitingForActivityDrawn();
-                                }
-
                                 // The intent we are sending is for the application, which
                                 // won't have permission to immediately start an activity after
                                 // the user switches to home.  We know it is safe to do at this
@@ -1993,8 +1967,6 @@
                                 }
                                 if (intent.isActivity()) {
                                     mAssistManager.hideAssist();
-                                    overrideActivityPendingAppTransition(keyguardShowing
-                                            && !afterKeyguardGone);
                                 }
                             }
 
@@ -2065,16 +2037,6 @@
     public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
     }
 
-    public void overrideActivityPendingAppTransition(boolean keyguardShowing) {
-        if (keyguardShowing) {
-            try {
-                mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error overriding app transition: " + e);
-            }
-        }
-    }
-
     protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
             String notificationKey) {
         final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index f9b7bb5..dfb06d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -496,7 +496,6 @@
                     } catch (RemoteException e) {
                         Log.w(TAG, "Unable to start camera activity", e);
                     }
-                    mActivityStarter.preventNextAnimation();
                     final boolean launched = isSuccessfulLaunch(result);
                     post(new Runnable() {
                         @Override
@@ -539,7 +538,6 @@
             @Override
             public void run() {
                 mAssistManager.launchVoiceAssistFromKeyguard();
-                mActivityStarter.preventNextAnimation();
             }
         };
         if (mPhoneStatusBar.isKeyguardCurrentlySecure()) {
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 7b35cbd..cda0bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1858,6 +1858,7 @@
             mLaunchAnimationEndRunnable.run();
             mLaunchAnimationEndRunnable = null;
         }
+        mStatusBar.readyForKeyguardDone();
     }
 
     @Override
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 be03ce6..669a512 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -37,7 +37,6 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
-import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -51,7 +50,6 @@
 import android.content.IntentSender;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -2515,11 +2513,6 @@
         startActivityDismissingKeyguard(intent, false, dismissShade, callback);
     }
 
-    @Override
-    public void preventNextAnimation() {
-        overrideActivityPendingAppTransition(true /* keyguardShowing */);
-    }
-
     public void setQsExpanded(boolean expanded) {
         mStatusBarWindowManager.setQsExpanded(expanded);
         mKeyguardStatusView.setImportantForAccessibility(expanded
@@ -2871,7 +2864,7 @@
         for (int i = 0; i < size; i++) {
             clonedList.get(i).run();
         }
-
+        mStatusBarKeyguardViewManager.readyForKeyguardDone();
     }
 
     @Override
@@ -3498,7 +3491,6 @@
 
         final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
                 mContext, intent, mCurrentUserId);
-        final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
@@ -3529,8 +3521,6 @@
                 } catch (RemoteException e) {
                     Log.w(TAG, "Unable to start activity", e);
                 }
-                overrideActivityPendingAppTransition(
-                        keyguardShowing && !afterKeyguardGone);
                 if (callback != null) {
                     callback.onActivityStarted(result);
                 }
@@ -3548,36 +3538,24 @@
                 afterKeyguardGone, true /* deferred */);
     }
 
+    public void readyForKeyguardDone() {
+        mStatusBarKeyguardViewManager.readyForKeyguardDone();
+    }
+
     public void executeRunnableDismissingKeyguard(final Runnable runnable,
             final Runnable cancelAction,
             final boolean dismissShade,
             final boolean afterKeyguardGone,
             final boolean deferred) {
-        final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
-        dismissKeyguardThenExecute(new OnDismissAction() {
-            @Override
-            public boolean onDismiss() {
-                AsyncTask.execute(new Runnable() {
-                    @Override
-                    public void run() {
-                        try {
-                            if (keyguardShowing && !afterKeyguardGone) {
-                                ActivityManagerNative.getDefault()
-                                        .keyguardWaitingForActivityDrawn();
-                            }
-                            if (runnable != null) {
-                                runnable.run();
-                            }
-                        } catch (RemoteException e) {
-                        }
-                    }
-                });
-                if (dismissShade) {
-                    animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
-                            true /* delayed*/);
-                }
-                return deferred;
+        dismissKeyguardThenExecute(() -> {
+            if (runnable != null) {
+                AsyncTask.execute(runnable);
             }
+            if (dismissShade) {
+                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
+                        true /* delayed*/);
+            }
+            return deferred;
         }, cancelAction, afterKeyguardGone);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 77c60fb..d296498 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -120,14 +120,14 @@
         mShowing = true;
         mStatusBarWindowManager.setKeyguardShowing(true);
         mScrimController.abortKeyguardFadingOut();
-        reset();
+        reset(true /* hideBouncerWhenShowing */);
     }
 
     /**
      * Shows the notification keyguard or the bouncer depending on
      * {@link KeyguardBouncer#needsFullscreenBouncer()}.
      */
-    protected void showBouncerOrKeyguard() {
+    protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
         if (mBouncer.needsFullscreenBouncer()) {
 
             // The keyguard might be showing (already). So we need to hide it.
@@ -135,8 +135,10 @@
             mBouncer.show(true /* resetSecuritySelection */);
         } else {
             mPhoneStatusBar.showKeyguard();
-            mBouncer.hide(false /* destroyView */);
-            mBouncer.prepare();
+            if (hideBouncerWhenShowing) {
+                mBouncer.hide(false /* destroyView */);
+                mBouncer.prepare();
+            }
         }
     }
 
@@ -163,14 +165,14 @@
     /**
      * Reset the state of the view.
      */
-    public void reset() {
+    public void reset(boolean hideBouncerWhenShowing) {
         if (mShowing) {
             if (mOccluded) {
                 mPhoneStatusBar.hideKeyguard();
                 mPhoneStatusBar.stopWaitingForKeyguardExit();
                 mBouncer.hide(false /* destroyView */);
             } else {
-                showBouncerOrKeyguard();
+                showBouncerOrKeyguard(hideBouncerWhenShowing);
             }
             KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset();
             updateStates();
@@ -257,7 +259,7 @@
                             @Override
                             public void run() {
                                 mStatusBarWindowManager.setKeyguardOccluded(mOccluded);
-                                reset();
+                                reset(true /* hideBouncerWhenShowing */);
                             }
                         });
                 return;
@@ -268,7 +270,10 @@
             mPhoneStatusBar.updateMediaMetaData(false, animate && !occluded);
         }
         mStatusBarWindowManager.setKeyguardOccluded(occluded);
-        reset();
+
+        // If Keyguard is reshown, don't hide the bouncer as it might just have been requested by
+        // a FLAG_DISMISS_KEYGUARD_ACTIVITY.
+        reset(false /* hideBouncerWhenShowing*/);
         if (animate && !occluded && mShowing) {
             mPhoneStatusBar.animateKeyguardUnoccluding();
         }
@@ -418,9 +423,7 @@
      * Dismisses the keyguard by going to the next screen or making it gone.
      */
     public void dismiss() {
-        if (mDeviceInteractive || mDeviceWillWakeUp) {
-            showBouncer();
-        }
+        showBouncer();
     }
 
     /**
@@ -445,7 +448,7 @@
     public boolean onBackPressed() {
         if (mBouncer.isShowing()) {
             mPhoneStatusBar.endAffordanceLaunch();
-            reset();
+            reset(true /* hideBouncerWhenShowing */);
             return true;
         }
         return false;
@@ -556,17 +559,8 @@
         return mBouncer.interceptMediaKey(event);
     }
 
-    public void onActivityDrawn() {
-        if (mPhoneStatusBar.isCollapsing()) {
-            mPhoneStatusBar.addPostCollapseAction(new Runnable() {
-                @Override
-                public void run() {
-                    mViewMediatorCallback.readyForKeyguardDone();
-                }
-            });
-        } else {
-            mViewMediatorCallback.readyForKeyguardDone();
-        }
+    public void readyForKeyguardDone() {
+        mViewMediatorCallback.readyForKeyguardDone();
     }
 
     public boolean shouldDisableWindowAnimationsForUnlock() {
@@ -581,10 +575,6 @@
         return mBouncer.isSecure() || mLockPatternUtils.isSecure(userId);
     }
 
-    public boolean isInputRestricted() {
-        return mViewMediatorCallback.isInputRestricted();
-    }
-
     public void keyguardGoingAway() {
         mPhoneStatusBar.keyguardGoingAway();
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 40f0aae..5d41d36 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.app.ApplicationThreadConstants;
+import android.annotation.Nullable;
 import android.os.IDeviceIdentifiersPolicyService;
 import android.util.Size;
 import android.util.TypedValue;
@@ -312,7 +313,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
@@ -374,13 +374,14 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
+import static com.android.server.wm.AppTransition.TRANSIT_NONE;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
-public final class ActivityManagerService extends ActivityManagerNative
+public class ActivityManagerService extends ActivityManagerNative
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
@@ -549,6 +550,7 @@
 
     /** Run all ActivityStacks through this */
     final ActivityStackSupervisor mStackSupervisor;
+    private final KeyguardController mKeyguardController;
 
     final ActivityStarter mActivityStarter;
 
@@ -632,7 +634,7 @@
 
     public boolean canShowErrorDialogs() {
         return mShowDialogs && !mSleeping && !mShuttingDown
-                && mLockScreenShown != LOCK_SCREEN_SHOWN;
+                && !mKeyguardController.isKeyguardShowing();
     }
 
     private static final class PriorityState {
@@ -1251,14 +1253,6 @@
      */
     final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
 
-    static final int LOCK_SCREEN_HIDDEN = 0;
-    static final int LOCK_SCREEN_LEAVING = 1;
-    static final int LOCK_SCREEN_SHOWN = 2;
-    /**
-     * State of external call telling us if the lock screen is shown.
-     */
-    int mLockScreenShown = LOCK_SCREEN_HIDDEN;
-
     /**
      * Set if we are shutting down the system, similar to sleeping.
      */
@@ -2621,6 +2615,7 @@
 
         mStackSupervisor = new ActivityStackSupervisor(this);
         mStackSupervisor.onConfigurationChanged(mTempConfig);
+        mKeyguardController = mStackSupervisor.mKeyguardController;
         mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
         mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
         mTaskChangeNotificationController =
@@ -3037,7 +3032,7 @@
                 mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
     }
 
-    private void applyVrModeIfNeededLocked(ActivityRecord r, boolean enable) {
+    void applyVrModeIfNeededLocked(ActivityRecord r, boolean enable) {
         mHandler.sendMessage(
                 mHandler.obtainMessage(VR_MODE_APPLY_IF_NEEDED_MSG, enable ? 1 : 0, 0, r));
     }
@@ -4967,12 +4962,17 @@
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
         }
 
-        if (!restarting && hasVisibleActivities
-                && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
-            // If there was nothing to resume, and we are not already restarting this process, but
-            // there is a visible activity that is hosted by the process...  then make sure all
-            // visible activities are running, taking care of restarting this process.
-            mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        mWindowManager.deferSurfaceLayout();
+        try {
+            if (!restarting && hasVisibleActivities
+                    && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
+                // If there was nothing to resume, and we are not already restarting this process, but
+                // there is a visible activity that is hosted by the process...  then make sure all
+                // visible activities are running, taking care of restarting this process.
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+            }
+        } finally {
+            mWindowManager.continueSurfaceLayout();
         }
     }
 
@@ -6602,39 +6602,12 @@
     }
 
     @Override
-    public void keyguardWaitingForActivityDrawn() {
-        enforceNotIsolatedCaller("keyguardWaitingForActivityDrawn");
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (this) {
-                if (DEBUG_LOCKSCREEN) logLockScreen("");
-                mWindowManager.keyguardWaitingForActivityDrawn();
-                if (mLockScreenShown == LOCK_SCREEN_SHOWN) {
-                    mLockScreenShown = LOCK_SCREEN_LEAVING;
-                    updateSleepIfNeededLocked();
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
     public void keyguardGoingAway(int flags) {
         enforceNotIsolatedCaller("keyguardGoingAway");
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                if (DEBUG_LOCKSCREEN) logLockScreen("");
-                mWindowManager.keyguardGoingAway(flags);
-                if (mLockScreenShown == LOCK_SCREEN_SHOWN) {
-                    mLockScreenShown = LOCK_SCREEN_HIDDEN;
-                    updateSleepIfNeededLocked();
-
-                    // Some stack visibility might change (e.g. docked stack)
-                    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-                    applyVrModeIfNeededLocked(mStackSupervisor.getResumedActivityLocked(), true);
-                }
+                mKeyguardController.keyguardGoingAway(flags);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -6785,6 +6758,7 @@
         final long origId = Binder.clearCallingIdentity();
         synchronized(this) {
             ActivityRecord.activityResumedLocked(token);
+            mWindowManager.notifyAppResumedFinished(token);
         }
         Binder.restoreCallingIdentity(origId);
     }
@@ -11524,7 +11498,7 @@
             case PowerManagerInternal.WAKEFULNESS_DOZING:
                 // Pause applications whenever the lock screen is shown or any sleep
                 // tokens have been acquired.
-                return (mLockScreenShown != LOCK_SCREEN_HIDDEN || !mSleepTokens.isEmpty());
+                return mKeyguardController.isKeyguardShowing() || !mSleepTokens.isEmpty();
             case PowerManagerInternal.WAKEFULNESS_ASLEEP:
             default:
                 // If we're asleep then pause applications unconditionally.
@@ -11592,22 +11566,6 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    private String lockScreenShownToString() {
-        switch (mLockScreenShown) {
-            case LOCK_SCREEN_HIDDEN: return "LOCK_SCREEN_HIDDEN";
-            case LOCK_SCREEN_LEAVING: return "LOCK_SCREEN_LEAVING";
-            case LOCK_SCREEN_SHOWN: return "LOCK_SCREEN_SHOWN";
-            default: return "Unknown=" + mLockScreenShown;
-        }
-    }
-
-    void logLockScreen(String msg) {
-        if (DEBUG_LOCKSCREEN) Slog.d(TAG_LOCKSCREEN, Debug.getCallers(2) + ":" + msg
-                + " mLockScreenShown=" + lockScreenShownToString() + " mWakefulness="
-                + PowerManagerInternal.wakefulnessToString(mWakefulness)
-                + " mSleeping=" + mSleeping);
-    }
-
     void startRunningVoiceLocked(IVoiceInteractionSession session, int targetUid) {
         Slog.d(TAG, "<<<  startRunningVoiceLocked()");
         mVoiceWakeLock.setWorkSource(new WorkSource(targetUid));
@@ -11625,7 +11583,8 @@
         mWindowManager.setEventDispatching(mBooted && !mShuttingDown);
     }
 
-    public void setLockScreenShown(boolean showing, boolean occluded) {
+    @Override
+    public void setLockScreenShown(boolean showing) {
         if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
@@ -11635,18 +11594,7 @@
         synchronized(this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (DEBUG_LOCKSCREEN) logLockScreen(" showing=" + showing + " occluded=" + occluded);
-                mLockScreenShown = (showing && !occluded) ? LOCK_SCREEN_SHOWN : LOCK_SCREEN_HIDDEN;
-                if (showing && occluded) {
-                    // The lock screen is currently showing, but is occluded by a window that can
-                    // show on top of the lock screen. In this can we want to dismiss the docked
-                    // stack since it will be complicated/risky to try to put the activity on top
-                    // of the lock screen in the right fullscreen configuration.
-                    mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
-                            mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
-                }
-
-                updateSleepIfNeededLocked();
+                mKeyguardController.setKeyguardShown(showing);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -14652,8 +14600,7 @@
             pw.println("  mWakefulness="
                     + PowerManagerInternal.wakefulnessToString(mWakefulness));
             pw.println("  mSleepTokens=" + mSleepTokens);
-            pw.println("  mSleeping=" + mSleeping + " mLockScreenShown="
-                    + lockScreenShownToString());
+            pw.println("  mSleeping=" + mSleeping);
             pw.println("  mShuttingDown=" + mShuttingDown + " mTestPssMode=" + mTestPssMode);
             if (mRunningVoice != null) {
                 pw.println("  mRunningVoice=" + mRunningVoice);
@@ -22091,6 +22038,21 @@
         public int getUidProcessState(int uid) {
             return getUidState(uid);
         }
+
+        @Override
+        public void notifyKeyguardFlagsChanged(@Nullable Runnable callback) {
+            synchronized (ActivityManagerService.this) {
+
+                // We might change the visibilities here, so prepare an empty app transition which
+                // might be overridden later if we actually change visibilities.
+                mWindowManager.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+                mWindowManager.executeAppTransition();
+            }
+            if (callback != null) {
+                callback.run();
+            }
+        }
     }
 
     private final class SleepTokenImpl extends SleepToken {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index df03af2..90b46ed 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -83,6 +83,7 @@
 import android.view.AppTransitionAnimationSpec;
 import android.view.IApplicationToken;
 import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.ReferrerIntent;
@@ -721,7 +722,7 @@
                         : android.R.style.Theme_Holo;
             }
             if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
-                windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+                windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED;
             }
             if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
                     && _caller != null
@@ -929,6 +930,22 @@
         return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
     }
 
+    /**
+     * @return true if the activity contains windows that have
+     *         {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set
+     */
+    boolean hasShowWhenLockedWindows() {
+        return service.mWindowManager.containsShowWhenLockedWindow(appToken);
+    }
+
+    /**
+     * @return true if the activity contains windows that have
+     *         {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set
+     */
+    boolean hasDismissKeyguardWindows() {
+        return service.mWindowManager.containsDismissKeyguardWindow(appToken);
+    }
+
     void makeFinishingLocked() {
         if (!finishing) {
             final ActivityStack stack = getStack();
@@ -1334,7 +1351,6 @@
         if (nowVisible) {
             // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
             mStackSupervisor.reportActivityVisibleLocked(this);
-            mStackSupervisor.notifyActivityDrawnForKeyguard();
         }
 
         // Schedule an idle timeout in case the app doesn't do it for us.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index fc41fd3..ffe2185 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -31,7 +31,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_APP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
@@ -60,7 +59,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
 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;
@@ -332,6 +330,9 @@
 
     private final LaunchingTaskPositioner mTaskPositioner;
 
+    private boolean mTopActivityOccludesKeyguard;
+    private ActivityRecord mTopDismissingKeyguardActivity;
+
     static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
     static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
     static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
@@ -1169,7 +1170,12 @@
             if (mPausingActivity == r) {
                 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
                         + (timeout ? " (due to timeout)" : " (pause complete)"));
-                completePauseLocked(true, null);
+                mService.mWindowManager.deferSurfaceLayout();
+                try {
+                    completePauseLocked(true, null);
+                } finally {
+                    mService.mWindowManager.continueSurfaceLayout();
+                }
                 return;
             } else {
                 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
@@ -1581,153 +1587,218 @@
      */
     final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
             boolean preserveWindows) {
-        ActivityRecord top = topRunningActivityLocked();
-        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + top
-                + " configChanges=0x" + Integer.toHexString(configChanges));
-        if (top != null) {
-            checkTranslucentActivityWaiting(top);
-        }
+        mTopActivityOccludesKeyguard = false;
+        mTopDismissingKeyguardActivity = null;
+        mStackSupervisor.mKeyguardController.beginActivityVisibilityUpdate();
+        try {
+            ActivityRecord top = topRunningActivityLocked();
+            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + top
+                    + " configChanges=0x" + Integer.toHexString(configChanges));
+            if (top != null) {
+                checkTranslucentActivityWaiting(top);
+            }
 
-        // If the top activity is not fullscreen, then we need to
-        // make sure any activities under it are now visible.
-        boolean aboveTop = top != null;
-        final int stackVisibility = getStackVisibilityLocked(starting);
-        final boolean stackInvisible = stackVisibility != STACK_VISIBLE;
-        final boolean stackVisibleBehind = stackVisibility == STACK_VISIBLE_ACTIVITY_BEHIND;
-        boolean behindFullscreenActivity = stackInvisible;
-        boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this)
-                && (isInStackLocked(starting) == null);
-        boolean behindTranslucentActivity = false;
-        final ActivityRecord visibleBehind = getVisibleBehindActivity();
-        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = mTaskHistory.get(taskNdx);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
-            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.finishing) {
-                    // Normally the screenshot will be taken in makeInvisible(). When an activity
-                    // is finishing, we no longer change its visibility, but we still need to take
-                    // the screenshots if startPausingLocked decided it should be taken.
-                    if (r.mUpdateTaskThumbnailWhenHidden) {
-                        r.updateThumbnailLocked(r.screenshotActivityLocked(),
-                                null /* description */);
-                        r.mUpdateTaskThumbnailWhenHidden = false;
+            // If the top activity is not fullscreen, then we need to
+            // make sure any activities under it are now visible.
+            boolean aboveTop = top != null;
+            final int stackVisibility = getStackVisibilityLocked(starting);
+            final boolean stackInvisible = stackVisibility != STACK_VISIBLE;
+            final boolean stackVisibleBehind = stackVisibility == STACK_VISIBLE_ACTIVITY_BEHIND;
+            boolean behindFullscreenActivity = stackInvisible;
+            boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this)
+                    && (isInStackLocked(starting) == null);
+            boolean behindTranslucentActivity = false;
+            final ActivityRecord visibleBehind = getVisibleBehindActivity();
+            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+                final TaskRecord task = mTaskHistory.get(taskNdx);
+                final ArrayList<ActivityRecord> activities = task.mActivities;
+                for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                    final ActivityRecord r = activities.get(activityNdx);
+                    if (r.finishing) {
+                        // Normally the screenshot will be taken in makeInvisible(). When an activity
+                        // is finishing, we no longer change its visibility, but we still need to take
+                        // the screenshots if startPausingLocked decided it should be taken.
+                        if (r.mUpdateTaskThumbnailWhenHidden) {
+                            r.updateThumbnailLocked(r.screenshotActivityLocked(),
+                                    null /* description */);
+                            r.mUpdateTaskThumbnailWhenHidden = false;
+                        }
+                        continue;
                     }
-                    continue;
-                }
-                final boolean isTop = r == top;
-                if (aboveTop && !isTop) {
-                    continue;
-                }
-                aboveTop = false;
-
-                if (r.shouldBeVisible(behindTranslucentActivity, stackVisibleBehind,
-                        visibleBehind, behindFullscreenActivity)) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
-                            + " finishing=" + r.finishing + " state=" + r.state);
-                    // First: if this is not the current activity being started, make
-                    // sure it matches the current configuration.
-                    if (r != starting) {
-                        r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindows);
+                    final boolean isTop = r == top;
+                    if (aboveTop && !isTop) {
+                        continue;
                     }
+                    aboveTop = false;
 
-                    if (r.app == null || r.app.thread == null) {
-                        if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
-                                resumeNextActivity, r)) {
-                            if (activityNdx >= activities.size()) {
-                                // Record may be removed if its process needs to restart.
-                                activityNdx = activities.size() - 1;
-                            } else {
+                    // Check whether activity should be visible without Keyguard influence
+                    final boolean shouldBeVisible = r.shouldBeVisible(behindTranslucentActivity,
+                            stackVisibleBehind, visibleBehind, behindFullscreenActivity);
+
+                    // Now check whether it's really visible depending on Keyguard state.
+                    final boolean reallyVisible = checkKeyguardVisibility(r, shouldBeVisible,
+                            isTop);
+                    if (shouldBeVisible) {
+                        behindFullscreenActivity = updateBehindFullscreen(stackInvisible,
+                                behindFullscreenActivity, task, r);
+                        if (behindFullscreenActivity && !r.fullscreen) {
+                            behindTranslucentActivity = true;
+                        }
+                    }
+                    if (reallyVisible) {
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
+                                + " finishing=" + r.finishing + " state=" + r.state);
+                        // First: if this is not the current activity being started, make
+                        // sure it matches the current configuration.
+                        if (r != starting) {
+                            r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindows);
+                        }
+
+                        if (r.app == null || r.app.thread == null) {
+                            if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
+                                    resumeNextActivity, r)) {
+                                if (activityNdx >= activities.size()) {
+                                    // Record may be removed if its process needs to restart.
+                                    activityNdx = activities.size() - 1;
+                                } else {
+                                    resumeNextActivity = false;
+                                }
+                            }
+                        } else if (r.visible) {
+                            // If this activity is already visible, then there is nothing to do here.
+                            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                    "Skipping: already visible at " + r);
+
+                            if (r.handleAlreadyVisible()) {
                                 resumeNextActivity = false;
                             }
+                        } else {
+                            r.makeVisibleIfNeeded(starting);
                         }
-                    } else if (r.visible) {
-                        // If this activity is already visible, then there is nothing to do here.
-                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
-                                "Skipping: already visible at " + r);
-
-                        if (r.handleAlreadyVisible()) {
-                            resumeNextActivity = false;
-                        }
+                        // Aggregate current change flags.
+                        configChanges |= r.configChangeFlags;
                     } else {
-                        r.makeVisibleIfNeeded(starting);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
+                                + " finishing=" + r.finishing + " state=" + r.state + " stackInvisible="
+                                + stackInvisible + " behindFullscreenActivity="
+                                + behindFullscreenActivity + " mLaunchTaskBehind="
+                                + r.mLaunchTaskBehind);
+                        makeInvisible(r, visibleBehind);
                     }
-                    // Aggregate current change flags.
-                    configChanges |= r.configChangeFlags;
-                    behindFullscreenActivity = updateBehindFullscreen(stackInvisible,
-                            behindFullscreenActivity, task, r);
-                    if (behindFullscreenActivity && !r.fullscreen) {
-                        behindTranslucentActivity = true;
+                }
+                if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                    // The visibility of tasks and the activities they contain in freeform stack are
+                    // determined individually unlike other stacks where the visibility or fullscreen
+                    // status of an activity in a previous task affects other.
+                    behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
+                } else if (mStackId == HOME_STACK_ID) {
+                    if (task.isOnTopLauncher()) {
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "On-top launcher: at " + task
+                                + " stackInvisible=" + stackInvisible
+                                + " behindFullscreenActivity=" + behindFullscreenActivity);
+                        // When an on-top launcher is visible, (e.g. it's on the top of the home stack),
+                        // other tasks in the home stack could be visible if and only if:
+                        // - some app is running in the docked stack;
+                        // - no app is running in either the fullscreen stack or the freefrom stack.
+                        final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
+                        final ActivityStack fullscreenStack = mStackSupervisor.getStack(
+                                FULLSCREEN_WORKSPACE_STACK_ID);
+                        final ActivityStack freeformStack = mStackSupervisor.getStack(
+                                FREEFORM_WORKSPACE_STACK_ID);
+                        final boolean dockedStackEmpty = dockedStack == null ||
+                                dockedStack.topRunningActivityLocked() == null;
+                        final boolean fullscreenStackEmpty = fullscreenStack == null ||
+                                fullscreenStack.topRunningActivityLocked() == null;
+                        final boolean freeformStackEmpty = freeformStack == null ||
+                                freeformStack.topRunningActivityLocked() == null;
+                        behindFullscreenActivity = dockedStackEmpty || !fullscreenStackEmpty ||
+                                !freeformStackEmpty;
+                    } else if (task.isHomeTask()) {
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
+                                + " stackInvisible=" + stackInvisible
+                                + " behindFullscreenActivity=" + behindFullscreenActivity);
+                        // No other task in the home stack should be visible behind the home activity.
+                        // Home activities is usually a translucent activity with the wallpaper behind
+                        // them. However, when they don't have the wallpaper behind them, we want to
+                        // show activities in the next application stack behind them vs. another
+                        // task in the home stack like recents.
+                        behindFullscreenActivity = true;
+                    } else if (task.isRecentsTask()
+                            && task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                "Recents task returning to app: at " + task
+                                        + " stackInvisible=" + stackInvisible
+                                        + " behindFullscreenActivity=" + behindFullscreenActivity);
+                        // We don't want any other tasks in the home stack visible if the recents
+                        // activity is going to be returning to an application activity type.
+                        // We do this to preserve the visible order the user used to get into the
+                        // recents activity. The recents activity is normally translucent and if it
+                        // doesn't have the wallpaper behind it the next activity in the home stack
+                        // shouldn't be visible when the home stack is brought to the front to display
+                        // the recents activity from an app.
+                        behindFullscreenActivity = true;
                     }
-                } else {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
-                            + " finishing=" + r.finishing + " state=" + r.state + " stackInvisible="
-                            + stackInvisible + " behindFullscreenActivity="
-                            + behindFullscreenActivity + " mLaunchTaskBehind="
-                            + r.mLaunchTaskBehind);
-                    makeInvisible(r, visibleBehind);
+
                 }
             }
-            if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                // The visibility of tasks and the activities they contain in freeform stack are
-                // determined individually unlike other stacks where the visibility or fullscreen
-                // status of an activity in a previous task affects other.
-                behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
-            } else if (mStackId == HOME_STACK_ID) {
-                if (task.isOnTopLauncher()) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "On-top launcher: at " + task
-                            + " stackInvisible=" + stackInvisible
-                            + " behindFullscreenActivity=" + behindFullscreenActivity);
-                    // When an on-top launcher is visible, (e.g. it's on the top of the home stack),
-                    // other tasks in the home stack could be visible if and only if:
-                    // - some app is running in the docked stack;
-                    // - no app is running in either the fullscreen stack or the freefrom stack.
-                    final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
-                    final ActivityStack fullscreenStack = mStackSupervisor.getStack(
-                            FULLSCREEN_WORKSPACE_STACK_ID);
-                    final ActivityStack freeformStack = mStackSupervisor.getStack(
-                            FREEFORM_WORKSPACE_STACK_ID);
-                    final boolean dockedStackEmpty = dockedStack == null ||
-                            dockedStack.topRunningActivityLocked() == null;
-                    final boolean fullscreenStackEmpty = fullscreenStack == null ||
-                            fullscreenStack.topRunningActivityLocked() == null;
-                    final boolean freeformStackEmpty = freeformStack == null ||
-                            freeformStack.topRunningActivityLocked() == null;
-                    behindFullscreenActivity = dockedStackEmpty || !fullscreenStackEmpty ||
-                            !freeformStackEmpty;
-                } else if (task.isHomeTask()) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
-                            + " stackInvisible=" + stackInvisible
-                            + " behindFullscreenActivity=" + behindFullscreenActivity);
-                    // No other task in the home stack should be visible behind the home activity.
-                    // Home activities is usually a translucent activity with the wallpaper behind
-                    // them. However, when they don't have the wallpaper behind them, we want to
-                    // show activities in the next application stack behind them vs. another
-                    // task in the home stack like recents.
-                    behindFullscreenActivity = true;
-                } else if (task.isRecentsTask()
-                        && task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
-                            "Recents task returning to app: at " + task
-                                    + " stackInvisible=" + stackInvisible
-                                    + " behindFullscreenActivity=" + behindFullscreenActivity);
-                    // We don't want any other tasks in the home stack visible if the recents
-                    // activity is going to be returning to an application activity type.
-                    // We do this to preserve the visible order the user used to get into the
-                    // recents activity. The recents activity is normally translucent and if it
-                    // doesn't have the wallpaper behind it the next activity in the home stack
-                    // shouldn't be visible when the home stack is brought to the front to display
-                    // the recents activity from an app.
-                    behindFullscreenActivity = true;
-                }
 
+            if (mTranslucentActivityWaiting != null &&
+                    mUndrawnActivitiesBelowTopTranslucent.isEmpty()) {
+                // Nothing is getting drawn or everything was already visible, don't wait for timeout.
+                notifyActivityDrawnLocked(null);
+            }
+        } finally {
+            mStackSupervisor.mKeyguardController.endActivityVisibilityUpdate();
+        }
+    }
+
+    /**
+     * @return true if the top visible activity wants to occlude the Keyguard, false otherwise
+     */
+    boolean topActivityOccludesKeyguard() {
+        return mTopActivityOccludesKeyguard;
+    }
+
+    /**
+     * @return the top most visible activity that wants to dismiss Keyguard
+     */
+    ActivityRecord getTopDismissingKeyguardActivity() {
+        return mTopDismissingKeyguardActivity;
+    }
+
+    /**
+     * Checks whether {@param r} should be visible depending on Keyguard state and updates
+     * {@link #mTopActivityOccludesKeyguard} and {@link #mTopDismissingKeyguardActivity} if
+     * necessary.
+     *
+     * @return true if {@param r} is visible taken Keyguard state into account, false otherwise
+     */
+    private boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
+            boolean isTop) {
+        final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
+        final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
+        final boolean showWhenLocked = r.hasShowWhenLockedWindows();
+        if (shouldBeVisible) {
+            if (r.hasDismissKeyguardWindows() && mTopDismissingKeyguardActivity == null) {
+                mTopDismissingKeyguardActivity = r;
+            }
+
+            // Only the top activity may control occluded, as we can't occlude the Keyguard if the
+            // top app doesn't want to occlude it.
+            if (isTop) {
+                mTopActivityOccludesKeyguard |= showWhenLocked;
             }
         }
+        if (keyguardShowing) {
 
-        if (mTranslucentActivityWaiting != null &&
-                mUndrawnActivitiesBelowTopTranslucent.isEmpty()) {
-            // Nothing is getting drawn or everything was already visible, don't wait for timeout.
-            notifyActivityDrawnLocked(null);
+            // If keyguard is showing, nothing is visible.
+            return false;
+        } else if (keyguardLocked) {
+
+            // Show when locked windows above keyguard.
+            return shouldBeVisible && showWhenLocked;
+        } else {
+            return shouldBeVisible;
         }
     }
 
@@ -1947,10 +2018,6 @@
         try {
             // Protect against recursion.
             mStackSupervisor.inResumeTopActivity = true;
-            if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
-                mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
-                mService.updateSleepIfNeededLocked();
-            }
             result = resumeTopActivityInnerLocked(prev, options);
         } finally {
             mStackSupervisor.inResumeTopActivity = false;
@@ -1969,8 +2036,6 @@
     }
 
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
-        if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
-
         if (!mService.mBooting && !mService.mBooted) {
             // Not ready yet!
             return false;
@@ -3287,72 +3352,77 @@
             return false;
         }
 
-        r.makeFinishingLocked();
-        final TaskRecord task = r.task;
-        EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
-                r.userId, System.identityHashCode(r),
-                task.taskId, r.shortComponentName, reason);
-        final ArrayList<ActivityRecord> activities = task.mActivities;
-        final int index = activities.indexOf(r);
-        if (index < (activities.size() - 1)) {
-            task.setFrontOfTask();
-            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
-                // If the caller asked that this activity (and all above it)
-                // be cleared when the task is reset, don't lose that information,
-                // but propagate it up to the next activity.
-                ActivityRecord next = activities.get(index+1);
-                next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+        mWindowManager.deferSurfaceLayout();
+        try {
+            r.makeFinishingLocked();
+            final TaskRecord task = r.task;
+            EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
+                    r.userId, System.identityHashCode(r),
+                    task.taskId, r.shortComponentName, reason);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            final int index = activities.indexOf(r);
+            if (index < (activities.size() - 1)) {
+                task.setFrontOfTask();
+                if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+                    // If the caller asked that this activity (and all above it)
+                    // be cleared when the task is reset, don't lose that information,
+                    // but propagate it up to the next activity.
+                    ActivityRecord next = activities.get(index+1);
+                    next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+                }
             }
-        }
 
-        r.pauseKeyDispatchingLocked();
+            r.pauseKeyDispatchingLocked();
 
-        adjustFocusedActivityStackLocked(r, "finishActivity");
+            adjustFocusedActivityStackLocked(r, "finishActivity");
 
-        finishActivityResultsLocked(r, resultCode, resultData);
+            finishActivityResultsLocked(r, resultCode, resultData);
 
-        final boolean endTask = index <= 0;
-        final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
-        if (mResumedActivity == r) {
-            if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
-                    "Prepare close transition: finishing " + r);
+            final boolean endTask = index <= 0;
+            final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
+            if (mResumedActivity == r) {
+                if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
+                        "Prepare close transition: finishing " + r);
             if (endTask) {
                 mService.mTaskChangeNotificationController.notifyTaskRemovalStarted(task.taskId);
             }
-            mWindowManager.prepareAppTransition(transit, false);
-
-            // Tell window manager to prepare for this one to be removed.
-            mWindowManager.setAppVisibility(r.appToken, false);
-
-            if (mPausingActivity == null) {
-                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, null, false);
-            }
-
-            if (endTask) {
-                mStackSupervisor.removeLockedTaskLocked(task);
-            }
-        } else if (r.state != ActivityState.PAUSING) {
-            // If the activity is PAUSING, we will complete the finish once
-            // it is done pausing; else we can just directly finish it here.
-            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
-            if (r.visible) {
                 mWindowManager.prepareAppTransition(transit, false);
-                mWindowManager.setAppVisibility(r.appToken, false);
-                mWindowManager.executeAppTransition();
-                if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) {
-                    mStackSupervisor.mWaitingVisibleActivities.add(r);
-                }
-            }
-            return finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ?
-                    FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null;
-        } else {
-            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
-        }
 
-        return false;
+                // Tell window manager to prepare for this one to be removed.
+                mWindowManager.setAppVisibility(r.appToken, false);
+
+                if (mPausingActivity == null) {
+                    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, null, false);
+                }
+
+                if (endTask) {
+                    mStackSupervisor.removeLockedTaskLocked(task);
+                }
+            } else if (r.state != ActivityState.PAUSING) {
+                // If the activity is PAUSING, we will complete the finish once
+                // it is done pausing; else we can just directly finish it here.
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
+                if (r.visible) {
+                    mWindowManager.prepareAppTransition(transit, false);
+                    mWindowManager.setAppVisibility(r.appToken, false);
+                    mWindowManager.executeAppTransition();
+                    if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) {
+                        mStackSupervisor.mWaitingVisibleActivities.add(r);
+                    }
+                }
+                return finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ?
+                        FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null;
+            } else {
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
+            }
+
+            return false;
+        } finally {
+            mWindowManager.continueSurfaceLayout();
+        }
     }
 
     static final int FINISH_IMMEDIATELY = 0;
@@ -4762,7 +4832,8 @@
                 voiceInteractor);
         // add the task to stack first, mTaskPositioner might need the stack association
         addTask(task, toTop, "createTaskRecord");
-        final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
+        final boolean isLockscreenShown =
+                mService.mStackSupervisor.mKeyguardController.isKeyguardShowing();
         if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable()
                 && !isLockscreenShown) {
             task.updateOverrideConfiguration(mBounds);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f0427e4..eed8dd7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -16,6 +16,79 @@
 
 package com.android.server.am;
 
+import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.ActivityManager.RESIZE_MODE_FORCED;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+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.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.ANIMATE;
+import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
+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.RECENTS_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
+import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
+import static com.android.server.am.ActivityStack.STACK_VISIBLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
+
 import android.Manifest;
 import android.annotation.UserIdInt;
 import android.app.Activity;
@@ -26,7 +99,6 @@
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
-import android.app.IActivityContainer;
 import android.app.IActivityContainerCallback;
 import android.app.IActivityManager;
 import android.app.IActivityManager.WaitResult;
@@ -83,7 +155,6 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.Display;
-import android.view.DisplayInfo;
 import android.view.InputEvent;
 import android.view.Surface;
 
@@ -106,79 +177,7 @@
 import java.util.Objects;
 import java.util.Set;
 
-import static android.Manifest.permission.START_ANY_ACTIVITY;
-import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
-import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
-import static android.app.ActivityManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
-import static android.app.ActivityManager.START_TASK_TO_FRONT;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-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.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.ANIMATE;
-import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
-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.RECENTS_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
-import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
-import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
-import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
-import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
-import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
-import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
-import static com.android.server.am.ActivityStack.STACK_VISIBLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
-import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
-
-public final class ActivityStackSupervisor extends ConfigurationContainer
+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;
@@ -477,6 +476,8 @@
      */
     boolean mIsDockMinimized;
 
+    final KeyguardController mKeyguardController;
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -514,6 +515,7 @@
         mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
         mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
         mResizeDockedStackTimeout = new ResizeDockedStackTimeout(service, this, mHandler);
+        mKeyguardController = new KeyguardController(service, this);
     }
 
     void setRecentTasks(RecentTasks recentTasks) {
@@ -562,6 +564,7 @@
     void setWindowManager(WindowManagerService wm) {
         synchronized (mService) {
             mWindowManager = wm;
+            mKeyguardController.setWindowManager(wm);
 
             mDisplayManager =
                     (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
@@ -585,11 +588,6 @@
         }
     }
 
-    void notifyActivityDrawnForKeyguard() {
-        if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
-        mWindowManager.notifyActivityDrawnForKeyguard();
-    }
-
     ActivityStack getFocusedStack() {
         return mFocusedStack;
     }
@@ -1224,6 +1222,10 @@
                     displayId);
         }
 
+        if (mKeyguardController.isKeyguardLocked()) {
+            mWindowManager.notifyUnknownAppVisibilityLaunched(r.appToken);
+        }
+
         r.app = app;
         app.waitingToKill = null;
         r.launchCount++;
@@ -1944,7 +1946,7 @@
             return null;
         }
         // TODO(multi-display): Allow creating stacks on secondary displays.
-        return createStackOnDisplay(stackId, Display.DEFAULT_DISPLAY, createOnTop);
+        return createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
     }
 
     ArrayList<ActivityStack> getStacks() {
@@ -1955,6 +1957,10 @@
         return allStacks;
     }
 
+    ArrayList<ActivityStack> getStacksOnDefaultDisplay() {
+        return mActivityDisplays.valueAt(DEFAULT_DISPLAY).mStacks;
+    }
+
     ActivityRecord getHomeActivity() {
         return getHomeActivityForUser(mCurrentUser);
     }
@@ -2919,14 +2925,19 @@
 
     void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
             boolean preserveWindows) {
-        // First the front stacks. In case any are not fullscreen and are in front of home.
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int topStackNdx = stacks.size() - 1;
-            for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
-                stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows);
+        mKeyguardController.beginActivityVisibilityUpdate();
+        try {
+            // First the front stacks. In case any are not fullscreen and are in front of home.
+            for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+                final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+                final int topStackNdx = stacks.size() - 1;
+                for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = stacks.get(stackNdx);
+                    stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows);
+                }
             }
+        } finally {
+            mKeyguardController.endActivityVisibilityUpdate();
         }
     }
 
@@ -3157,15 +3168,16 @@
         pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
         pw.print(prefix); pw.println("mActivityContainers=" + mActivityContainers);
         pw.print(prefix); pw.print("mLockTaskModeState=" + lockTaskModeToString());
-                final SparseArray<String[]> packages = mService.mLockTaskPackages;
-                if (packages.size() > 0) {
-                    pw.println(" mLockTaskPackages (userId:packages)=");
-                    for (int i = 0; i < packages.size(); ++i) {
-                        pw.print(prefix); pw.print(prefix); pw.print(packages.keyAt(i));
-                        pw.print(":"); pw.println(Arrays.toString(packages.valueAt(i)));
-                    }
-                }
-                pw.println(" mLockTaskModeTasks" + mLockTaskModeTasks);
+        final SparseArray<String[]> packages = mService.mLockTaskPackages;
+        if (packages.size() > 0) {
+            pw.print(prefix); pw.println("mLockTaskPackages (userId:packages)=");
+            for (int i = 0; i < packages.size(); ++i) {
+                pw.print(prefix); pw.print(prefix); pw.print(packages.keyAt(i));
+                pw.print(":"); pw.println(Arrays.toString(packages.valueAt(i)));
+            }
+        }
+        pw.println(" mLockTaskModeTasks" + mLockTaskModeTasks);
+        mKeyguardController.dump(pw, prefix);
     }
 
     /**
@@ -3470,10 +3482,10 @@
     }
 
     private StackInfo getStackInfoLocked(ActivityStack stack) {
-        final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
+        final ActivityDisplay display = mActivityDisplays.get(DEFAULT_DISPLAY);
         StackInfo info = new StackInfo();
         mWindowManager.getStackBounds(stack.mStackId, info.bounds);
-        info.displayId = Display.DEFAULT_DISPLAY;
+        info.displayId = DEFAULT_DISPLAY;
         info.stackId = stack.mStackId;
         info.userId = stack.mCurrentUser;
         info.visible = stack.getStackVisibilityLocked(null) == STACK_VISIBLE;
@@ -4390,7 +4402,7 @@
 
     ActivityStack findStackBehind(ActivityStack stack) {
         // TODO(multi-display): We are only looking for stacks on the default display.
-        final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
+        final ActivityDisplay display = mActivityDisplays.get(DEFAULT_DISPLAY);
         if (display == null) {
             return null;
         }
@@ -4505,7 +4517,7 @@
     public List<IBinder> getTopVisibleActivities() {
         // TODO(multi-display): Get rid of DEFAULT_DISPLAY here. Used in
         // VoiceInteractionManagerServiceImpl#showSessionLocked.
-        final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
+        final ActivityDisplay display = mActivityDisplays.get(DEFAULT_DISPLAY);
         if (display == null) {
             return Collections.EMPTY_LIST;
         }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 006c13d..db73048 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -577,10 +577,6 @@
             ActivityStack targetStack) {
 
         if (result < START_SUCCESS) {
-            // If someone asked to have the keyguard dismissed on the next activity start,
-            // but we are not actually doing an activity switch...  just dismiss the keyguard now,
-            // because we probably want to see whatever is behind it.
-            mSupervisor.notifyActivityDrawnForKeyguard();
             return;
         }
 
@@ -1661,11 +1657,6 @@
     private void resumeTargetStackIfNeeded() {
         if (mDoResume) {
             mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, null, mOptions);
-            if (!mMovedToFront) {
-                // Make sure to notify Keyguard as well if we are not running an app transition
-                // later.
-                mSupervisor.notifyActivityDrawnForKeyguard();
-            }
         } else {
             ActivityOptions.abort(mOptions);
         }
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
new file mode 100644
index 0000000..98acc9c
--- /dev/null
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -0,0 +1,269 @@
+/*
+ * 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.am;
+
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
+import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
+import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
+import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+
+import com.android.server.wm.WindowManagerService;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
+ * currently visible.
+ * <p>
+ * Note that everything in this class should only be accessed with the AM lock being held.
+ */
+class KeyguardController {
+
+    private final ActivityManagerService mService;
+    private final ActivityStackSupervisor mStackSupervisor;
+    private WindowManagerService mWindowManager;
+    private boolean mKeyguardShowing;
+    private boolean mKeyguardGoingAway;
+    private boolean mOccluded;
+    private ActivityRecord mDismissingKeyguardActivity;
+    private int mBeforeUnoccludeTransit;
+    private int mVisibilityTransactionDepth;
+
+    KeyguardController(ActivityManagerService service,
+            ActivityStackSupervisor stackSupervisor) {
+        mService = service;
+        mStackSupervisor = stackSupervisor;
+    }
+
+    void setWindowManager(WindowManagerService windowManager) {
+        mWindowManager = windowManager;
+    }
+
+    /**
+     * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
+     */
+    boolean isKeyguardShowing() {
+        return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
+    }
+
+    /**
+     * @return true if Keyguard is either showing or occluded, but not going away
+     */
+    boolean isKeyguardLocked() {
+        return mKeyguardShowing && !mKeyguardGoingAway;
+    }
+
+    /**
+     * Update the Keyguard showing state.
+     */
+    void setKeyguardShown(boolean showing) {
+        if (showing == mKeyguardShowing) {
+            return;
+        }
+        mKeyguardShowing = showing;
+        if (showing) {
+            mKeyguardGoingAway = false;
+
+            // Allow an activity to redismiss Keyguard.
+            mDismissingKeyguardActivity = null;
+        }
+        mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        mService.updateSleepIfNeededLocked();
+    }
+
+    /**
+     * Called when Keyguard is going away.
+     *
+     * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
+     *              etc.
+     */
+    void keyguardGoingAway(int flags) {
+        if (mKeyguardShowing) {
+            mWindowManager.deferSurfaceLayout();
+            try {
+                mKeyguardGoingAway = true;
+                mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
+                        false /* alwaysKeepCurrent */, convertTransitFlags(flags),
+                        false /* forceOverride */);
+                mWindowManager.keyguardGoingAway(flags);
+                mService.updateSleepIfNeededLocked();
+
+                // Some stack visibility might change (e.g. docked stack)
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+                mWindowManager.executeAppTransition();
+                mService.applyVrModeIfNeededLocked(mStackSupervisor.getResumedActivityLocked(),
+                        true /* enable */);
+            } finally {
+                mWindowManager.continueSurfaceLayout();
+            }
+        }
+    }
+
+    private int convertTransitFlags(int keyguardGoingAwayFlags) {
+        int result = 0;
+        if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
+            result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+        }
+        if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
+            result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+        }
+        if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
+            result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+        }
+        return result;
+    }
+
+    /**
+     * Starts a batch of visibility updates.
+     */
+    void beginActivityVisibilityUpdate() {
+        mVisibilityTransactionDepth++;
+    }
+
+    /**
+     * Ends a batch of visibility updates. After all batches are done, this method makes sure to
+     * update lockscreen occluded/dismiss state if needed.
+     */
+    void endActivityVisibilityUpdate() {
+        mVisibilityTransactionDepth--;
+        if (mVisibilityTransactionDepth == 0) {
+            visibilitiesUpdated();
+        }
+    }
+
+    private void visibilitiesUpdated() {
+        final boolean lastOccluded = mOccluded;
+        final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
+        mOccluded = false;
+        mDismissingKeyguardActivity = null;
+        final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
+        final int topStackNdx = stacks.size() - 1;
+        for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = stacks.get(stackNdx);
+
+            // Only the very top activity may control occluded state
+            if (stackNdx == topStackNdx) {
+                mOccluded = stack.topActivityOccludesKeyguard();
+            }
+            if (mDismissingKeyguardActivity == null
+                    && stack.getTopDismissingKeyguardActivity() != null) {
+                mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
+            }
+        }
+        mOccluded |= mWindowManager.isShowingDream();
+        if (mOccluded != lastOccluded) {
+            handleOccludedChanged();
+        }
+        if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
+            handleDismissKeyguard();
+        }
+    }
+
+    /**
+     * Called when occluded state changed.
+     */
+    private void handleOccludedChanged() {
+        mWindowManager.onKeyguardOccludedChanged(mOccluded);
+        if (isKeyguardLocked()) {
+            mWindowManager.deferSurfaceLayout();
+            try {
+                mWindowManager.prepareAppTransition(resolveOccludeTransit(),
+                        false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
+                mService.updateSleepIfNeededLocked();
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+                mWindowManager.executeAppTransition();
+            } finally {
+                mWindowManager.continueSurfaceLayout();
+            }
+        }
+        dismissDockedStackIfNeeded();
+    }
+
+    /**
+     * Called when somebody might want to dismiss the Keyguard.
+     */
+    private void handleDismissKeyguard() {
+        if (mDismissingKeyguardActivity != null) {
+            mWindowManager.dismissKeyguard();
+
+            // If we are about to unocclude the Keyguard, but we can dismiss it without security,
+            // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
+            if (mKeyguardShowing && canDismissKeyguard()
+                    && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
+                mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
+                        false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
+                mKeyguardGoingAway = true;
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+                mWindowManager.executeAppTransition();
+            }
+        }
+    }
+
+    /**
+     * @return true if Keyguard can be currently dismissed without entering credentials.
+     */
+    private boolean canDismissKeyguard() {
+        return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
+    }
+
+    private int resolveOccludeTransit() {
+        if (mBeforeUnoccludeTransit != TRANSIT_UNSET
+                && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
+                && mOccluded) {
+
+            // Reuse old transit in case we are occluding Keyguard again, meaning that we never
+            // actually occclude/unocclude Keyguard, but just run a normal transition.
+            return mBeforeUnoccludeTransit;
+        } else if (!mOccluded) {
+
+            // Save transit in case we dismiss/occlude Keyguard shortly after.
+            mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
+            return TRANSIT_KEYGUARD_UNOCCLUDE;
+        } else {
+            return TRANSIT_KEYGUARD_OCCLUDE;
+        }
+    }
+
+    private void dismissDockedStackIfNeeded() {
+        if (mKeyguardShowing && mOccluded) {
+            // The lock screen is currently showing, but is occluded by a window that can
+            // show on top of the lock screen. In this can we want to dismiss the docked
+            // stack since it will be complicated/risky to try to put the activity on top
+            // of the lock screen in the right fullscreen configuration.
+            mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
+                    mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
+        }
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "KeyguardController:");
+        pw.println(prefix + "  mKeyguardShowing=" + mKeyguardShowing);
+        pw.println(prefix + "  mKeyguardGoingAway=" + mKeyguardGoingAway);
+        pw.println(prefix + "  mOccluded=" + mOccluded);
+        pw.println(prefix + "  mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
+        pw.println(prefix + "  mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
+    }
+}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index b37b3f0..86e3ccc 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -56,8 +56,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 import java.util.Objects;
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -89,7 +87,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
 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.RECENTS_ACTIVITY_TYPE;
@@ -1700,7 +1697,7 @@
     /** Returns the bounds that should be used to launch this task. */
     Rect getLaunchBounds() {
         // If we're over lockscreen, forget about stack bounds and use fullscreen.
-        if (mService.mLockScreenShown == LOCK_SCREEN_SHOWN) {
+        if (mService.mStackSupervisor.mKeyguardController.isKeyguardShowing()) {
             return null;
         }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 40dfcda..41fd16b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -25,13 +25,82 @@
 import static android.content.res.Configuration.EMPTY;
 import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
-import static android.view.WindowManager.DOCKED_TOP;
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW;
+import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
+import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
+import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
 import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
-import static android.view.WindowManager.LayoutParams.*;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -39,6 +108,7 @@
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerInternal;
@@ -112,10 +182,10 @@
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.MutableBoolean;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.LongSparseArray;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -133,19 +203,21 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerInternal;
+import android.view.WindowManagerInternal.AppTransitionListener;
 import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
+
 import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.policy.PhoneWindow;
 import com.android.internal.policy.IShortcutService;
+import com.android.internal.policy.PhoneWindow;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.widget.PointerLocationView;
@@ -154,12 +226,12 @@
 import com.android.server.policy.keyguard.KeyguardServiceDelegate;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
 import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.AppTransition;
 
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -280,8 +352,6 @@
     /**
      * Keyguard stuff
      */
-    private WindowState mKeyguardScrim;
-    private boolean mKeyguardHidden;
     private boolean mKeyguardDrawnOnce;
 
     /* Table of Application Launch keys.  Maps from key codes to intent categories.
@@ -582,54 +652,23 @@
     WindowState mTopFullscreenOpaqueOrDimmingWindowState;
     WindowState mTopDockedOpaqueWindowState;
     WindowState mTopDockedOpaqueOrDimmingWindowState;
-    HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
-    HashSet<IApplicationToken> mAppsThatDismissKeyguard = new HashSet<IApplicationToken>();
     boolean mTopIsFullscreen;
     boolean mForceStatusBar;
     boolean mForceStatusBarFromKeyguard;
     private boolean mForceStatusBarTransparent;
     int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
-    boolean mHideLockScreen;
     boolean mForcingShowNavBar;
     int mForcingShowNavBarLayer;
 
-    // States of keyguard dismiss.
-    private static final int DISMISS_KEYGUARD_NONE = 0; // Keyguard not being dismissed.
-    private static final int DISMISS_KEYGUARD_START = 1; // Keyguard needs to be dismissed.
-    private static final int DISMISS_KEYGUARD_CONTINUE = 2; // Keyguard has been dismissed.
-    int mDismissKeyguard = DISMISS_KEYGUARD_NONE;
+    private boolean mPendingKeyguardOccluded;
+    private boolean mKeyguardOccludedChanged;
 
-    /**
-     * Indicates that we asked the Keyguard to be dismissed and we just wait for the Keyguard to
-     * dismiss itself.
-     */
-    @GuardedBy("Lw")
-    private boolean mCurrentlyDismissingKeyguard;
-
-    /** The window that is currently dismissing the keyguard. Dismissing the keyguard must only
-     * be done once per window. */
-    private WindowState mWinDismissingKeyguard;
-
-    /** When window is currently dismissing the keyguard, dismissing the keyguard must handle
-     * the keygaurd secure state change instantly case, e.g. the use case of inserting a PIN
-     * lock SIM card. This variable is used to record the previous keyguard secure state for
-     * monitoring secure state change on window dismissing keyguard. */
-    private boolean mSecureDismissingKeyguard;
-
-    /** The window that is currently showing "over" the keyguard. If there is an app window
-     * belonging to another app on top of this the keyguard shows. If there is a fullscreen
-     * app window under this, still dismiss the keyguard but don't show the app underneath. Show
-     * the wallpaper. */
-    private WindowState mWinShowWhenLocked;
-
-    boolean mShowingLockscreen;
     boolean mShowingDream;
+    private boolean mLastShowingDream;
     boolean mDreamingLockscreen;
     boolean mDreamingSleepTokenNeeded;
     SleepToken mDreamingSleepToken;
     SleepToken mScreenOffSleepToken;
-    boolean mKeyguardSecure;
-    boolean mKeyguardSecureIncludingHidden;
     volatile boolean mKeyguardOccluded;
     boolean mHomePressed;
     boolean mHomeConsumed;
@@ -1911,6 +1950,19 @@
 
         mWindowManagerInternal.registerAppTransitionListener(
                 mStatusBarController.getAppTransitionListener());
+        mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() {
+            @Override
+            public int onAppTransitionStartingLocked(int transit, IBinder openToken,
+                    IBinder closeToken,
+                    Animation openAnimation, Animation closeAnimation) {
+                return handleStartTransitionForKeyguardLw(transit, openAnimation);
+            }
+
+            @Override
+            public void onAppTransitionCancelledLocked(int transit) {
+                handleStartTransitionForKeyguardLw(transit, null /* transit */);
+            }
+        });
     }
 
     /**
@@ -2316,7 +2368,6 @@
             case TYPE_BOOT_PROGRESS:
             case TYPE_DISPLAY_OVERLAY:
             case TYPE_INPUT_CONSUMER:
-            case TYPE_KEYGUARD_SCRIM:
             case TYPE_KEYGUARD_DIALOG:
             case TYPE_MAGNIFICATION_OVERLAY:
             case TYPE_NAVIGATION_BAR:
@@ -2357,7 +2408,7 @@
                 // remove the wallpaper and keyguard flag so that any change in-flight after setting
                 // the keyguard as occluded wouldn't set these flags again.
                 // See {@link #processKeyguardSetHiddenResultLw}.
-                if (mKeyguardHidden) {
+                if (mKeyguardOccluded) {
                     attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
                 }
@@ -2533,9 +2584,6 @@
         case TYPE_INPUT_METHOD_DIALOG:
             // on-screen keyboards and other such input method user interfaces go here.
             return 13;
-        case TYPE_KEYGUARD_SCRIM:
-            // the safety window that shows behind keyguard while keyguard is starting
-            return 14;
         case TYPE_STATUS_BAR_SUB_PANEL:
             return 15;
         case TYPE_STATUS_BAR:
@@ -2673,26 +2721,17 @@
     }
 
     @Override
-    public boolean isForceHiding(WindowManager.LayoutParams attrs) {
-        return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
-                (isKeyguardHostWindow(attrs) &&
-                        (mKeyguardDelegate != null && mKeyguardDelegate.isShowing())) ||
-                (attrs.type == TYPE_KEYGUARD_SCRIM);
-    }
-
-    @Override
     public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
         return attrs.type == TYPE_STATUS_BAR;
     }
 
     @Override
-    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
-        switch (attrs.type) {
+    public boolean canBeHiddenByKeyguardLw(WindowState win) {
+        switch (win.getAttrs().type) {
             case TYPE_STATUS_BAR:
             case TYPE_NAVIGATION_BAR:
             case TYPE_WALLPAPER:
             case TYPE_DREAM:
-            case TYPE_KEYGUARD_SCRIM:
                 return false;
             default:
                 // Hide only windows below the keyguard host window.
@@ -2701,9 +2740,34 @@
         }
     }
 
-    @Override
-    public WindowState getWinShowWhenLockedLw() {
-        return mWinShowWhenLocked;
+    private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) {
+
+        // Keyguard visibility of window from activities are determined over activity visibility.
+        if (win.getAppToken() != null) {
+            return false;
+        }
+
+        final LayoutParams attrs = win.getAttrs();
+        final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw() &&
+                ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0
+                        || !canBeHiddenByKeyguardLw(imeTarget));
+
+        // Show IME over the keyguard if the target allows it
+        boolean allowWhenLocked = (win.isInputMethodWindow() || imeTarget == this)
+                && showImeOverKeyguard;;
+
+        if (isKeyguardLocked() && isKeyguardOccluded()) {
+            // Show SHOW_WHEN_LOCKED windows if Keyguard is occluded.
+            allowWhenLocked |= (attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
+                    // Show error dialogs over apps that are shown on lockscreen
+                    || (attrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
+        }
+
+        boolean keyguardLocked = isKeyguardLocked();
+        boolean hideDockDivider = attrs.type == TYPE_DOCK_DIVIDER
+                && !mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID);
+        return (keyguardLocked && !allowWhenLocked && win.getDisplayId() == Display.DEFAULT_DISPLAY)
+                || hideDockDivider;
     }
 
     /** {@inheritDoc} */
@@ -2771,7 +2835,7 @@
                 // Assumes it's safe to show starting windows of launched apps while
                 // the keyguard is being hidden. This is okay because starting windows never show
                 // secret information.
-                if (mKeyguardHidden) {
+                if (mKeyguardOccluded) {
                     windowFlags |= FLAG_SHOW_WHEN_LOCKED;
                 }
             }
@@ -2904,12 +2968,6 @@
                         android.Manifest.permission.STATUS_BAR_SERVICE,
                         "PhoneWindowManager");
                 break;
-            case TYPE_KEYGUARD_SCRIM:
-                if (mKeyguardScrim != null) {
-                    return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
-                }
-                mKeyguardScrim = win;
-                break;
         }
         return WindowManagerGlobal.ADD_OKAY;
     }
@@ -2920,11 +2978,7 @@
         if (mStatusBar == win) {
             mStatusBar = null;
             mStatusBarController.setWindow(null);
-            mKeyguardDelegate.showScrim();
-        } else if (mKeyguardScrim == win) {
-            Log.v(TAG, "Removing keyguard scrim");
-            mKeyguardScrim = null;
-        } if (mNavigationBar == win) {
+        } else if (mNavigationBar == win) {
             mNavigationBar = null;
             mNavigationBarController.setWindow(null);
         }
@@ -3081,7 +3135,7 @@
     }
 
     @Override
-    public Animation createForceHideEnterAnimation(boolean onWallpaper,
+    public Animation createHiddenByKeyguardExit(boolean onWallpaper,
             boolean goingToNotificationShade) {
         if (goingToNotificationShade) {
             return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_behind_enter_fade_in);
@@ -3102,7 +3156,7 @@
 
 
     @Override
-    public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade) {
+    public Animation createKeyguardWallpaperExit(boolean goingToNotificationShade) {
         if (goingToNotificationShade) {
             return null;
         } else {
@@ -3236,8 +3290,7 @@
             WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
             if (attrs != null) {
                 final int type = attrs.type;
-                if (type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
-                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
+                if (type == TYPE_KEYGUARD_DIALOG
                         || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                     // the "app" is keyguard, so give it the key
                     return 0;
@@ -3703,12 +3756,35 @@
     }
 
     @Override
-    public boolean canShowDismissingWindowWhileLockedLw() {
-        // If the keyguard is trusted, it will unlock without a challenge. Therefore, if we are in
-        // the process of dismissing Keyguard, we don't need to hide them as the phone will be
-        // unlocked right away in any case.
-        return mKeyguardDelegate != null && mKeyguardDelegate.isTrusted()
-                && mCurrentlyDismissingKeyguard;
+    public void onKeyguardOccludedChangedLw(boolean occluded) {
+        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+            mPendingKeyguardOccluded = occluded;
+            mKeyguardOccludedChanged = true;
+        } else {
+            setKeyguardOccludedLw(occluded);
+        }
+    }
+
+    private int handleStartTransitionForKeyguardLw(int transit, @Nullable Animation anim) {
+        if (mKeyguardOccludedChanged) {
+            if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded="
+                    + mPendingKeyguardOccluded);
+            mKeyguardOccludedChanged = false;
+            if (setKeyguardOccludedLw(mPendingKeyguardOccluded)) {
+                return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER;
+            }
+        }
+        if (AppTransition.isKeyguardGoingAwayTransit(transit)) {
+            if (DEBUG_KEYGUARD) Slog.d(TAG, "Starting keyguard exit animation");
+            final long startTime = anim != null
+                    ? SystemClock.uptimeMillis() + anim.getStartOffset()
+                    : SystemClock.uptimeMillis();
+            final long duration = anim != null
+                    ? anim.getDuration()
+                    : 0;
+            startKeyguardExitAnimation(startTime, duration);
+        }
+        return 0;
     }
 
     private void launchAssistLongPressAction() {
@@ -3853,7 +3929,7 @@
                 return;
             }
 
-            if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
+            if (!mKeyguardOccluded && mKeyguardDelegate.isInputRestricted()) {
                 // when in keyguard restricted mode, must first verify unlock
                 // before launching home
                 mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
@@ -4166,7 +4242,7 @@
             boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
             boolean navAllowedHidden = immersive || immersiveSticky;
             navTranslucent &= !immersiveSticky;  // transient trumps translucent
-            boolean isKeyguardShowing = isStatusBarKeyguard() && !mHideLockScreen;
+            boolean isKeyguardShowing = isStatusBarKeyguard() && !mKeyguardOccluded;
             if (!isKeyguardShowing) {
                 navTranslucent &= areTranslucentBarsAllowed();
             }
@@ -5073,31 +5149,23 @@
         mTopFullscreenOpaqueOrDimmingWindowState = null;
         mTopDockedOpaqueWindowState = null;
         mTopDockedOpaqueOrDimmingWindowState = null;
-        mAppsToBeHidden.clear();
-        mAppsThatDismissKeyguard.clear();
         mForceStatusBar = false;
         mForceStatusBarFromKeyguard = false;
         mForceStatusBarTransparent = false;
         mForcingShowNavBar = false;
         mForcingShowNavBarLayer = -1;
 
-        mHideLockScreen = false;
         mAllowLockscreenWhenOn = false;
-        mDismissKeyguard = DISMISS_KEYGUARD_NONE;
-        mShowingLockscreen = false;
         mShowingDream = false;
-        mWinShowWhenLocked = null;
-        mKeyguardSecure = isKeyguardSecure(mCurrentUserId);
-        mKeyguardSecureIncludingHidden = mKeyguardSecure
-                && (mKeyguardDelegate != null && mKeyguardDelegate.isShowing());
     }
 
     /** {@inheritDoc} */
     @Override
     public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
-            WindowState attached) {
+            WindowState attached, WindowState imeTarget) {
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
                 + win.isVisibleOrBehindKeyguardLw());
+        applyKeyguardPolicyLw(win, imeTarget);
         final int fl = PolicyControl.getWindowFlags(win, attrs);
         if (mTopFullscreenOpaqueWindowState == null
                 && win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) {
@@ -5107,7 +5175,6 @@
         if (attrs.type == TYPE_STATUS_BAR) {
             if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                 mForceStatusBarFromKeyguard = true;
-                mShowingLockscreen = true;
             }
             if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
                 mForceStatusBarTransparent = true;
@@ -5116,17 +5183,11 @@
 
         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
                 && attrs.type < FIRST_SYSTEM_WINDOW;
-        final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
-        final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
         final int stackId = win.getStackId();
         if (mTopFullscreenOpaqueWindowState == null &&
                 win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
-                if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                    mForceStatusBarFromKeyguard = true;
-                } else {
-                    mForceStatusBar = true;
-                }
+                mForceStatusBar = true;
             }
             if (attrs.type == TYPE_DREAM) {
                 // If the lockscreen was showing when the dream started then wait
@@ -5138,77 +5199,20 @@
                 }
             }
 
-            final IApplicationToken appToken = win.getAppToken();
-
             // For app windows that are not attached, we decide if all windows in the app they
             // represent should be hidden or if we should hide the lockscreen. For attached app
             // windows we defer the decision to the window it is attached to.
             if (appWindow && attached == null) {
-                if (showWhenLocked) {
-                    // Remove any previous windows with the same appToken.
-                    mAppsToBeHidden.remove(appToken);
-                    mAppsThatDismissKeyguard.remove(appToken);
-                    if (mAppsToBeHidden.isEmpty()) {
-                        if (dismissKeyguard && !mKeyguardSecure) {
-                            mAppsThatDismissKeyguard.add(appToken);
-                        } else if (win.isDrawnLw() || win.hasAppShownWindows()) {
-                            mWinShowWhenLocked = win;
-                            mHideLockScreen = true;
-                            mForceStatusBarFromKeyguard = false;
-                        }
-                    }
-                } else if (dismissKeyguard) {
-                    if (mKeyguardSecure) {
-                        mAppsToBeHidden.add(appToken);
-                    } else {
-                        mAppsToBeHidden.remove(appToken);
-                    }
-                    mAppsThatDismissKeyguard.add(appToken);
-                } else {
-                    mAppsToBeHidden.add(appToken);
-                }
                 if (isFullscreen(attrs) && StackId.normallyFullscreenWindows(stackId)) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
                     mTopFullscreenOpaqueWindowState = win;
                     if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
                         mTopFullscreenOpaqueOrDimmingWindowState = win;
                     }
-                    if (!mAppsThatDismissKeyguard.isEmpty() &&
-                            mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
-                        if (DEBUG_LAYOUT) Slog.v(TAG,
-                                "Setting mDismissKeyguard true by win " + win);
-                        mDismissKeyguard = (mWinDismissingKeyguard == win
-                                && mSecureDismissingKeyguard == mKeyguardSecure)
-                                ? DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
-                        mWinDismissingKeyguard = win;
-                        mSecureDismissingKeyguard = mKeyguardSecure;
-                        mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
-                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked
-                            && (win.isDrawnLw() || win.hasAppShownWindows())) {
-                        if (DEBUG_LAYOUT) Slog.v(TAG,
-                                "Setting mHideLockScreen to true by win " + win);
-                        mHideLockScreen = true;
-                        mForceStatusBarFromKeyguard = false;
-                    }
                     if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                         mAllowLockscreenWhenOn = true;
                     }
                 }
-
-                if (!mKeyguardHidden && mWinShowWhenLocked != null &&
-                        mWinShowWhenLocked.getAppToken() != win.getAppToken() &&
-                        (attrs.flags & FLAG_SHOW_WHEN_LOCKED) == 0) {
-                    win.hideLw(false);
-                }
-            }
-        } else if (mTopFullscreenOpaqueWindowState == null && mWinShowWhenLocked == null) {
-            // No TopFullscreenOpaqueWindow is showing, but we found a SHOW_WHEN_LOCKED window
-            // that is being hidden in an animation - keep the
-            // keyguard hidden until the new window shows up and
-            // we know whether to show the keyguard or not.
-            if (win.isAnimatingLw() && appWindow && showWhenLocked && mKeyguardHidden) {
-                mHideLockScreen = true;
-                mWinShowWhenLocked = win;
             }
         }
 
@@ -5255,6 +5259,16 @@
         }
     }
 
+    private void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget) {
+        if (canBeHiddenByKeyguardLw(win)) {
+            if (shouldBeHiddenByKeyguard(win, imeTarget)) {
+                win.hideLw(false /* doAnimation */);
+            } else {
+                win.showLw(false /* doAnimation */);
+            }
+        }
+    }
+
     private boolean isFullscreen(WindowManager.LayoutParams attrs) {
         return attrs.x == 0 && attrs.y == 0
                 && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
@@ -5264,17 +5278,6 @@
     /** {@inheritDoc} */
     @Override
     public int finishPostLayoutPolicyLw() {
-        if (mWinShowWhenLocked != null && mTopFullscreenOpaqueWindowState != null &&
-                mWinShowWhenLocked.getAppToken() != mTopFullscreenOpaqueWindowState.getAppToken()
-                && isKeyguardLocked()) {
-            // A dialog is dismissing the keyguard. Put the wallpaper behind it and hide the
-            // fullscreen window.
-            // TODO: Make sure FLAG_SHOW_WALLPAPER is restored when dialog is dismissed. Or not.
-            mWinShowWhenLocked.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
-            mTopFullscreenOpaqueWindowState.hideLw(false);
-            mTopFullscreenOpaqueWindowState = mWinShowWhenLocked;
-        }
-
         int changes = 0;
         boolean topIsFullscreen = false;
 
@@ -5287,7 +5290,7 @@
         // started while the lockscreen was showing and remember this state
         // while the dream is showing.
         if (!mShowingDream) {
-            mDreamingLockscreen = mShowingLockscreen;
+            mDreamingLockscreen = isKeyguardShowingAndNotOccluded();
             if (mDreamingSleepTokenNeeded) {
                 mDreamingSleepTokenNeeded = false;
                 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
@@ -5378,79 +5381,17 @@
             mTopIsFullscreen = topIsFullscreen;
         }
 
-        // Hide the key guard if a visible window explicitly specifies that it wants to be
-        // displayed when the screen is locked.
-        if (mKeyguardDelegate != null && mStatusBar != null) {
-            if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
-                    + mHideLockScreen);
-            if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardSecure) {
-                mKeyguardHidden = true;
-                if (setKeyguardOccludedLw(true)) {
-                    changes |= FINISH_LAYOUT_REDO_LAYOUT
-                            | FINISH_LAYOUT_REDO_CONFIG
-                            | FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-                if (mKeyguardDelegate.isShowing()) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            mKeyguardDelegate.keyguardDone(false, false);
-                        }
-                    });
-                }
-            } else if (mHideLockScreen) {
-                mKeyguardHidden = true;
-                mWinDismissingKeyguard = null;
-                if (setKeyguardOccludedLw(true)) {
-                    changes |= FINISH_LAYOUT_REDO_LAYOUT
-                            | FINISH_LAYOUT_REDO_CONFIG
-                            | FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-            } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
-                mKeyguardHidden = false;
-                boolean dismissKeyguard = false;
-                final boolean trusted = mKeyguardDelegate.isTrusted();
-                if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
-                    final boolean willDismiss = trusted && mKeyguardOccluded
-                            && mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
-                    if (willDismiss) {
-                        mCurrentlyDismissingKeyguard = true;
-                    }
-                    dismissKeyguard = true;
-                }
-
-                // If we are currently dismissing Keyguard, there is no need to unocclude it.
-                if (!mCurrentlyDismissingKeyguard) {
-                    if (setKeyguardOccludedLw(false)) {
-                        changes |= FINISH_LAYOUT_REDO_LAYOUT
-                                | FINISH_LAYOUT_REDO_CONFIG
-                                | FINISH_LAYOUT_REDO_WALLPAPER;
-                    }
-                }
-
-                if (dismissKeyguard) {
-                    // Only launch the next keyguard unlock window once per window.
-                    mHandler.post(() -> mKeyguardDelegate.dismiss(
-                            trusted /* allowWhileOccluded */));
-                }
-            } else {
-                mWinDismissingKeyguard = null;
-                mSecureDismissingKeyguard = false;
-                mKeyguardHidden = false;
-                if (setKeyguardOccludedLw(false)) {
-                    changes |= FINISH_LAYOUT_REDO_LAYOUT
-                            | FINISH_LAYOUT_REDO_CONFIG
-                            | FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-            }
-        }
-
         if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
             // If the navigation bar has been hidden or shown, we need to do another
             // layout pass to update that window.
             changes |= FINISH_LAYOUT_REDO_LAYOUT;
         }
 
+        if (mShowingDream != mLastShowingDream) {
+            mLastShowingDream = mShowingDream;
+            mWindowManagerFuncs.notifyShowingDreamChanged();
+        }
+
         // update since mAllowLockscreenWhenOn might have changed
         updateLockScreenTimeout();
         return changes;
@@ -5462,6 +5403,7 @@
      * @return Whether the flags have changed and we have to redo the layout.
      */
     private boolean setKeyguardOccludedLw(boolean isOccluded) {
+        if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded);
         boolean wasOccluded = mKeyguardOccluded;
         boolean showing = mKeyguardDelegate.isShowing();
         if (wasOccluded && !isOccluded && showing) {
@@ -5471,9 +5413,6 @@
             if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
                 mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
             }
-            Animation anim = AnimationUtils.loadAnimation(mContext,
-                    com.android.internal.R.anim.wallpaper_open_exit);
-            mWindowManagerFuncs.overridePlayingAppAnimationsLw(anim);
             return true;
         } else if (!wasOccluded && isOccluded && showing) {
             mKeyguardOccluded = true;
@@ -5490,14 +5429,6 @@
         }
     }
 
-    private void onKeyguardShowingStateChanged(boolean showing) {
-        if (!showing) {
-            synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
-                mCurrentlyDismissingKeyguard = false;
-            }
-        }
-    }
-
     private boolean isStatusBarKeyguard() {
         return mStatusBar != null
                 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
@@ -5505,7 +5436,7 @@
 
     @Override
     public boolean allowAppAnimationsLw() {
-        if (isStatusBarKeyguard() || mShowingDream) {
+        if (mShowingDream) {
             // If keyguard or dreams is currently visible, no reason to animate behind it.
             return false;
         }
@@ -6657,6 +6588,12 @@
         return mKeyguardDelegate.isShowing() && !mKeyguardOccluded;
     }
 
+    @Override
+    public boolean isKeyguardTrustedLw() {
+        if (mKeyguardDelegate == null) return false;
+        return mKeyguardDelegate.isTrusted();
+    }
+
     /** {@inheritDoc} */
     @Override
     public boolean isKeyguardLocked() {
@@ -6672,8 +6609,9 @@
 
     /** {@inheritDoc} */
     @Override
-    public boolean isKeyguardShowingOrOccluded() {
-        return mKeyguardDelegate == null ? false : mKeyguardDelegate.isShowing();
+    public boolean isKeyguardOccluded() {
+        if (mKeyguardDelegate == null) return false;
+        return mKeyguardOccluded;
     }
 
     /** {@inheritDoc} */
@@ -6687,25 +6625,9 @@
     public void dismissKeyguardLw() {
         if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw");
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    // ask the keyguard to prompt the user to authenticate if necessary
-                    mKeyguardDelegate.dismiss(false /* allowWhileOccluded */);
-                }
-            });
-        }
-    }
 
-    @Override
-    public void notifyActivityDrawnForKeyguardLw() {
-        if (mKeyguardDelegate != null) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mKeyguardDelegate.onActivityDrawn();
-                }
-            });
+            // ask the keyguard to prompt the user to authenticate if necessary
+            mKeyguardDelegate.dismiss(true /* allowWhileOccluded */);
         }
     }
 
@@ -6717,6 +6639,11 @@
     }
 
     @Override
+    public boolean isShowingDreamLw() {
+        return mShowingDream;
+    }
+
+    @Override
     public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
         if (mKeyguardDelegate != null) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.startKeyguardExitAnimation");
@@ -7028,8 +6955,7 @@
     /** {@inheritDoc} */
     @Override
     public void systemReady() {
-        mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
-                this::onKeyguardShowingStateChanged);
+        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
         mKeyguardDelegate.onSystemReady();
 
         readCameraLensCoverState();
@@ -7576,7 +7502,7 @@
             }
         }
         final WindowState win = winCandidate;
-        if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
+        if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mKeyguardOccluded) {
             // We are updating at a point where the keyguard has gotten
             // focus, but we were last in a state where the top window is
             // hiding it.  This is probably because the keyguard as been
@@ -7633,7 +7559,7 @@
     }
 
     private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
-        WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen
+        WindowState statusColorWin = isStatusBarKeyguard() && !mKeyguardOccluded
                 ? mStatusBar
                 : opaqueOrDimming;
 
@@ -7674,7 +7600,7 @@
         final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
 
         // apply translucent bar vis flags
-        WindowState fullscreenTransWin = isStatusBarKeyguard() && !mHideLockScreen
+        WindowState fullscreenTransWin = isStatusBarKeyguard() && !mKeyguardOccluded
                 ? mStatusBar
                 : mTopFullscreenOpaqueWindowState;
         vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
@@ -7700,7 +7626,7 @@
                     | View.SYSTEM_UI_FLAG_IMMERSIVE
                     | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                     | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-            if (mHideLockScreen) {
+            if (mKeyguardOccluded) {
                 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
             }
             vis = (vis & ~flags) | (oldVis & flags);
@@ -8069,8 +7995,7 @@
                 pw.print(","); pw.print(mDockBottom); pw.println(")");
         pw.print(prefix); pw.print("mDockLayer="); pw.print(mDockLayer);
                 pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
-        pw.print(prefix); pw.print("mShowingLockscreen="); pw.print(mShowingLockscreen);
-                pw.print(" mShowingDream="); pw.print(mShowingDream);
+        pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
                 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
                 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
         if (mLastInputMethodWindow != null) {
@@ -8098,10 +8023,6 @@
             pw.print(prefix); pw.print("mFocusedApp=");
                     pw.println(mFocusedApp);
         }
-        if (mWinDismissingKeyguard != null) {
-            pw.print(prefix); pw.print("mWinDismissingKeyguard=");
-                    pw.println(mWinDismissingKeyguard);
-        }
         if (mTopFullscreenOpaqueWindowState != null) {
             pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
                     pw.println(mTopFullscreenOpaqueWindowState);
@@ -8116,14 +8037,13 @@
                     pw.println(mForcingShowNavBarLayer);
         }
         pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
-                pw.print(" mHideLockScreen="); pw.println(mHideLockScreen);
+                pw.print(" mKeyguardOccluded="); pw.println(mKeyguardOccluded);
+                pw.print(" mKeyguardOccludedChanged="); pw.println(mKeyguardOccludedChanged);
+                pw.print(" mPendingKeyguardOccluded="); pw.println(mPendingKeyguardOccluded);
         pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
                 pw.print(" mForceStatusBarFromKeyguard=");
                 pw.println(mForceStatusBarFromKeyguard);
-        pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
-                pw.print(" mCurrentlyDismissingKeyguard="); pw.println(mCurrentlyDismissingKeyguard);
-                pw.print(" mWinDismissingKeyguard="); pw.print(mWinDismissingKeyguard);
-                pw.print(" mHomePressed="); pw.println(mHomePressed);
+        pw.print(prefix); pw.print("mHomePressed="); pw.println(mHomePressed);
         pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
                 pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
                 pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive);
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
index 1dbc44e..7d67b60 100644
--- a/services/core/java/com/android/server/policy/StatusBarController.java
+++ b/services/core/java/com/android/server/policy/StatusBarController.java
@@ -56,8 +56,8 @@
         }
 
         @Override
-        public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
-                final Animation openAnimation, final Animation closeAnimation) {
+        public int onAppTransitionStartingLocked(int transit, IBinder openToken,
+                IBinder closeToken, final Animation openAnimation, final Animation closeAnimation) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -71,10 +71,11 @@
                     }
                 }
             });
+            return 0;
         }
 
         @Override
-        public void onAppTransitionCancelledLocked() {
+        public void onAppTransitionCancelledLocked(int transit) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 10c237f..28f36f7 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,12 +1,13 @@
 package com.android.server.policy.keyguard;
 
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.ActivityManagerNative;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
-import android.graphics.PixelFormat;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -15,15 +16,13 @@
 import android.util.Log;
 import android.util.Slog;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.view.WindowManagerPolicy.OnKeyguardExitResult;
 
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
+import com.android.server.LocalServices;
 import com.android.server.UiThread;
-import com.android.server.policy.keyguard.KeyguardStateMonitor.OnShowingStateChangedCallback;
 
 import java.io.PrintWriter;
 
@@ -46,23 +45,13 @@
 
     protected KeyguardServiceWrapper mKeyguardService;
     private final Context mContext;
-    private final View mScrim; // shown if keyguard crashes
-    private final Handler mScrimHandler;
+    private final Handler mHandler;
     private final KeyguardState mKeyguardState = new KeyguardState();
     private DrawnListener mDrawnListenerWhenConnect;
-    private final OnShowingStateChangedCallback mShowingStateChangedCallback;
 
     private static final class KeyguardState {
         KeyguardState() {
-            // Assume keyguard is showing and secure until we know for sure. This is here in
-            // the event something checks before the service is actually started.
-            // KeyguardService itself should default to this state until the real state is known.
-            showing = true;
-            showingAndNotOccluded = true;
-            secure = true;
-            deviceHasKeyguard = true;
-            enabled = true;
-            currentUser = UserHandle.USER_NULL;
+            reset();
         }
         boolean showing;
         boolean showingAndNotOccluded;
@@ -78,6 +67,18 @@
         public boolean bootCompleted;
         public int screenState;
         public int interactiveState;
+
+        private void reset() {
+            // Assume keyguard is showing and secure until we know for sure. This is here in
+            // the event something checks before the service is actually started.
+            // KeyguardService itself should default to this state until the real state is known.
+            showing = true;
+            showingAndNotOccluded = true;
+            secure = true;
+            deviceHasKeyguard = true;
+            enabled = true;
+            currentUser = UserHandle.USER_NULL;
+        }
     };
 
     public interface DrawnListener {
@@ -98,7 +99,6 @@
             if (mDrawnListener != null) {
                 mDrawnListener.onDrawn();
             }
-            hideScrim();
         }
     };
 
@@ -119,12 +119,9 @@
         }
     };
 
-    public KeyguardServiceDelegate(Context context,
-            OnShowingStateChangedCallback showingStateChangedCallback) {
+    public KeyguardServiceDelegate(Context context) {
         mContext = context;
-        mScrimHandler = UiThread.getHandler();
-        mShowingStateChangedCallback = showingStateChangedCallback;
-        mScrim = createScrim(context, mScrimHandler);
+        mHandler = UiThread.getHandler();
     }
 
     public void bindService(Context context) {
@@ -137,7 +134,7 @@
         intent.setComponent(keyguardComponent);
 
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
-                Context.BIND_AUTO_CREATE, mScrimHandler, UserHandle.SYSTEM)) {
+                Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) {
             Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
             mKeyguardState.showing = false;
             mKeyguardState.showingAndNotOccluded = false;
@@ -147,7 +144,6 @@
                 // is at least self-healing but a race condition here can lead to the scrim being
                 // stuck on keyguard-less devices.
                 mKeyguardState.deviceHasKeyguard = false;
-                hideScrim();
             }
         } else {
             if (DEBUG) Log.v(TAG, "*** Keyguard started");
@@ -159,7 +155,7 @@
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
             mKeyguardService = new KeyguardServiceWrapper(mContext,
-                    IKeyguardService.Stub.asInterface(service), mShowingStateChangedCallback);
+                    IKeyguardService.Stub.asInterface(service));
             if (mKeyguardState.systemIsReady) {
                 // If the system is ready, it means keyguard crashed and restarted.
                 mKeyguardService.onSystemReady();
@@ -196,8 +192,15 @@
         public void onServiceDisconnected(ComponentName name) {
             if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
             mKeyguardService = null;
+            mKeyguardState.reset();
+            mHandler.post(() -> {
+                try {
+                    ActivityManagerNative.getDefault().setLockScreenShown(true);
+                } catch (RemoteException e) {
+                    // Local call.
+                }
+            });
         }
-
     };
 
     public boolean isShowing() {
@@ -234,12 +237,6 @@
         }
     }
 
-    public void keyguardDone(boolean authenticated, boolean wakeup) {
-        if (mKeyguardService != null) {
-            mKeyguardService.keyguardDone(authenticated, wakeup);
-        }
-    }
-
     public void setOccluded(boolean isOccluded, boolean animate) {
         if (mKeyguardService != null) {
             if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
@@ -301,7 +298,6 @@
             // This shouldn't happen, but if it does, show the scrim immediately and
             // invoke the listener's callback after the service actually connects.
             mDrawnListenerWhenConnect = drawnListener;
-            showScrim();
         }
         mKeyguardState.screenState = SCREEN_STATE_TURNING_ON;
     }
@@ -369,61 +365,6 @@
         }
     }
 
-    private static View createScrim(Context context, Handler handler) {
-        final View view = new View(context);
-
-        int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
-                | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
-                ;
-
-        final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
-        final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
-        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
-        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-        lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
-        lp.setTitle("KeyguardScrim");
-        final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        // Disable pretty much everything in statusbar until keyguard comes back and we know
-        // the state of the world.
-        view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
-                | View.STATUS_BAR_DISABLE_BACK
-                | View.STATUS_BAR_DISABLE_RECENT
-                | View.STATUS_BAR_DISABLE_EXPAND
-                | View.STATUS_BAR_DISABLE_SEARCH);
-        handler.post(new Runnable() {
-            @Override
-            public void run() {
-                wm.addView(view, lp);
-            }
-        });
-        return view;
-    }
-
-    public void showScrim() {
-        synchronized (mKeyguardState) {
-            if (!mKeyguardState.deviceHasKeyguard) return;
-            mScrimHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mScrim.setVisibility(View.VISIBLE);
-                }
-            });
-        }
-    }
-
-    public void hideScrim() {
-        mScrimHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mScrim.setVisibility(View.GONE);
-            }
-        });
-    }
-
     public void onBootCompleted() {
         if (mKeyguardService != null) {
             mKeyguardService.onBootCompleted();
@@ -431,12 +372,6 @@
         mKeyguardState.bootCompleted = true;
     }
 
-    public void onActivityDrawn() {
-        if (mKeyguardService != null) {
-            mKeyguardService.onActivityDrawn();
-        }
-    }
-
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + TAG);
         prefix += "  ";
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index acc67db..b457f8d 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -26,7 +26,6 @@
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
 import com.android.internal.policy.IKeyguardStateCallback;
-import com.android.server.policy.keyguard.KeyguardStateMonitor.OnShowingStateChangedCallback;
 
 import java.io.PrintWriter;
 
@@ -40,11 +39,9 @@
     private IKeyguardService mService;
     private String TAG = "KeyguardServiceWrapper";
 
-    public KeyguardServiceWrapper(Context context, IKeyguardService service,
-            OnShowingStateChangedCallback showingStateChangedCallback) {
+    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
         mService = service;
-        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service,
-                showingStateChangedCallback);
+        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
     }
 
     @Override // Binder interface
@@ -57,15 +54,6 @@
     }
 
     @Override // Binder interface
-    public void keyguardDone(boolean authenticated, boolean wakeup) {
-        try {
-            mService.keyguardDone(authenticated, wakeup);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
     public void setOccluded(boolean isOccluded, boolean animate) {
         try {
             mService.setOccluded(isOccluded, animate);
@@ -229,15 +217,6 @@
     }
 
     @Override // Binder interface
-    public void onActivityDrawn() {
-        try {
-            mService.onActivityDrawn();
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
     public IBinder asBinder() {
         return mService.asBinder();
     }
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 712b625..f19f0aa 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -49,13 +49,11 @@
     private int mCurrentUserId;
 
     private final LockPatternUtils mLockPatternUtils;
-    private final OnShowingStateChangedCallback mOnShowingStateChangedCallback;
 
-    public KeyguardStateMonitor(Context context, IKeyguardService service,
-            OnShowingStateChangedCallback showingStateChangedCallback) {
+    public KeyguardStateMonitor(Context context, IKeyguardService service) {
         mLockPatternUtils = new LockPatternUtils(context);
         mCurrentUserId = ActivityManager.getCurrentUser();
-        mOnShowingStateChangedCallback = showingStateChangedCallback;
+
         try {
             service.addStateMonitorCallback(this);
         } catch (RemoteException e) {
@@ -86,7 +84,6 @@
     @Override // Binder interface
     public void onShowingStateChanged(boolean showing) {
         mIsShowing = showing;
-        mOnShowingStateChangedCallback.onShowingStateChanged(showing);
     }
 
     @Override // Binder interface
@@ -126,8 +123,4 @@
         pw.println(prefix + "mTrusted=" + mTrusted);
         pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
     }
-
-    public interface OnShowingStateChangedCallback {
-        void onShowingStateChanged(boolean showing);
-    }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index bde65ed..670b9cc 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1283,8 +1283,7 @@
         }
 
         private static boolean isReportedWindowType(int windowType) {
-            return (windowType != WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
-                    && windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
+            return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
                     && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
                     && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
                     && windowType != WindowManager.LayoutParams.TYPE_DRAG
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index cd46165..862c145 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -135,6 +135,21 @@
     public static final int TRANSIT_ACTIVITY_RELAUNCH = 18;
     /** A task is being docked from recents. */
     public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;
+    /** Keyguard is going away */
+    public static final int TRANSIT_KEYGUARD_GOING_AWAY = 20;
+    /** Keyguard is going away with showing an activity behind that requests wallpaper */
+    public static final int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
+    /** Keyguard is being occluded */
+    public static final int TRANSIT_KEYGUARD_OCCLUDE = 22;
+    /** Keyguard is being unoccluded */
+    public static final int TRANSIT_KEYGUARD_UNOCCLUDE = 23;
+
+    /** Transition flag: Keyguard is going away, but keeping the notification shade open */
+    public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE = 0x1;
+    /** Transition flag: Keyguard is going away, but doesn't want an animation for it */
+    public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION = 0x2;
+    /** Transition flag: Keyguard is going away while it was showing the system wallpaper. */
+    public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER = 0x4;
 
     /** Fraction of animation at which the recents thumbnail stays completely transparent */
     private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
@@ -162,6 +177,7 @@
     private final WindowManagerService mService;
 
     private int mNextAppTransition = TRANSIT_UNSET;
+    private int mNextAppTransitionFlags = 0;
     private int mLastUsedAppTransition = TRANSIT_UNSET;
     private String mLastOpeningApp;
     private String mLastClosingApp;
@@ -286,8 +302,9 @@
         return mNextAppTransition;
      }
 
-    private void setAppTransition(int transit) {
+    private void setAppTransition(int transit, int flags) {
         mNextAppTransition = transit;
+        mNextAppTransitionFlags |= flags;
         setLastAppTransition(TRANSIT_UNSET, null, null);
     }
 
@@ -372,27 +389,33 @@
         return false;
     }
 
-    void goodToGo(AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator,
-            ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps) {
-        int appTransition = mNextAppTransition;
+    /**
+     * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
+     *         layout pass needs to be done
+     */
+    int goodToGo(int transit, AppWindowAnimator topOpeningAppAnimator,
+            AppWindowAnimator topClosingAppAnimator, ArraySet<AppWindowToken> openingApps,
+            ArraySet<AppWindowToken> closingApps) {
         mNextAppTransition = TRANSIT_UNSET;
+        mNextAppTransitionFlags = 0;
         mAppTransitionState = APP_STATE_RUNNING;
-        notifyAppTransitionStartingLocked(
+        int redoLayout = notifyAppTransitionStartingLocked(transit,
                 topOpeningAppAnimator != null ? topOpeningAppAnimator.mAppToken.token : null,
                 topClosingAppAnimator != null ? topClosingAppAnimator.mAppToken.token : null,
                 topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
                 topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
         mService.getDefaultDisplayContentLocked().getDockedDividerController()
-                .notifyAppTransitionStarting(openingApps, appTransition);
+                .notifyAppTransitionStarting(openingApps, transit);
 
         // Prolong the start for the transition when docking a task from recents, unless recents
         // ended it already then we don't need to wait.
-        if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) {
+        if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) {
             for (int i = openingApps.size() - 1; i >= 0; i--) {
                 final AppWindowAnimator appAnimator = openingApps.valueAt(i).mAppAnimator;
                 appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START);
             }
         }
+        return redoLayout;
     }
 
     /**
@@ -413,10 +436,11 @@
     }
 
     void freeze() {
-        setAppTransition(AppTransition.TRANSIT_UNSET);
+        final int transit = mNextAppTransition;
+        setAppTransition(AppTransition.TRANSIT_UNSET, 0 /* flags */);
         clear();
         setReady();
-        notifyAppTransitionCancelledLocked();
+        notifyAppTransitionCancelledLocked(transit);
     }
 
     void registerListenerLocked(AppTransitionListener listener) {
@@ -435,18 +459,20 @@
         }
     }
 
-    private void notifyAppTransitionCancelledLocked() {
+    private void notifyAppTransitionCancelledLocked(int transit) {
         for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionCancelledLocked();
+            mListeners.get(i).onAppTransitionCancelledLocked(transit);
         }
     }
 
-    private void notifyAppTransitionStartingLocked(IBinder openToken,
+    private int notifyAppTransitionStartingLocked(int transit, IBinder openToken,
             IBinder closeToken, Animation openAnimation, Animation closeAnimation) {
+        int redoLayout = 0;
         for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionStartingLocked(openToken, closeToken, openAnimation,
-                    closeAnimation);
+            redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, openToken,
+                    closeToken, openAnimation, closeAnimation);
         }
+        return redoLayout;
     }
 
     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
@@ -1406,7 +1432,8 @@
     boolean canSkipFirstFrame() {
         return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
                 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
-                && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL;
+                && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
+                && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY;
     }
 
     /**
@@ -1435,7 +1462,13 @@
             @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform,
             int taskId) {
         Animation a;
-        if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
+        if (isKeyguardGoingAwayTransit(transit) && enter) {
+            a = loadKeyguardExitAnimation(transit);
+        } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
+            a = null;
+        } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
+            a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
+        } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
                 || transit == TRANSIT_TASK_OPEN
                 || transit == TRANSIT_TASK_TO_FRONT)) {
             a = loadAnimationRes(lp, enter
@@ -1590,14 +1623,30 @@
         return a;
     }
 
+    private Animation loadKeyguardExitAnimation(int transit) {
+        if ((mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) {
+            return null;
+        }
+        final boolean toShade =
+                (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0;
+        return mService.mPolicy.createHiddenByKeyguardExit(
+                transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade);
+    }
+
     int getAppStackClipMode() {
         return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
                 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
+                || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY
+                || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
                 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
                 ? STACK_CLIP_NONE
                 : STACK_CLIP_AFTER_ANIM;
     }
 
+    public int getTransitFlags() {
+        return mNextAppTransitionFlags;
+    }
+
     void postAnimationCallback() {
         if (mNextAppTransitionCallback != null) {
             mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
@@ -1819,6 +1868,18 @@
             case TRANSIT_DOCK_TASK_FROM_RECENTS: {
                 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
             }
+            case TRANSIT_KEYGUARD_GOING_AWAY: {
+                return "TRANSIT_KEYGUARD_GOING_AWAY";
+            }
+            case TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
+                return "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
+            }
+            case TRANSIT_KEYGUARD_OCCLUDE: {
+                return "TRANSIT_KEYGUARD_OCCLUDE";
+            }
+            case TRANSIT_KEYGUARD_UNOCCLUDE: {
+                return "TRANSIT_KEYGUARD_UNOCCLUDE";
+            }
             default: {
                 return "<UNKNOWN>";
             }
@@ -1933,22 +1994,24 @@
      * @return true if transition is not running and should not be skipped, false if transition is
      *         already running
      */
-    boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent) {
+    boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent, int flags,
+            boolean forceOverride) {
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
                 + " transit=" + appTransitionToString(transit)
                 + " " + this
                 + " alwaysKeepCurrent=" + alwaysKeepCurrent
                 + " Callers=" + Debug.getCallers(3));
-        if (!isTransitionSet() || mNextAppTransition == TRANSIT_NONE) {
-            setAppTransition(transit);
+        if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
+                || mNextAppTransition == TRANSIT_NONE) {
+            setAppTransition(transit, flags);
         } else if (!alwaysKeepCurrent) {
             if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
                 // Opening a new task always supersedes a close for the anim.
-                setAppTransition(transit);
+                setAppTransition(transit, flags);
             } else if (transit == TRANSIT_ACTIVITY_OPEN
                     && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
                 // Opening a new activity always supersedes a close for the anim.
-                setAppTransition(transit);
+                setAppTransition(transit, flags);
             }
         }
         boolean prepared = prepare();
@@ -1960,6 +2023,20 @@
     }
 
     /**
+     * @return true if {@param transit} is representing a transition in which Keyguard is going
+     *         away, false otherwise
+     */
+    public static boolean isKeyguardGoingAwayTransit(int transit) {
+        return transit == TRANSIT_KEYGUARD_GOING_AWAY
+                || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+    }
+
+    private static boolean isKeyguardTransit(int transit) {
+        return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE
+                || transit == TRANSIT_KEYGUARD_UNOCCLUDE;
+    }
+
+    /**
      * @return whether the specified {@param uiMode} is the TV mode.
      */
     private boolean isTvUiMode(int uiMode) {
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index e774259..e1b598a 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -17,6 +17,8 @@
 package com.android.server.wm;
 
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+
+import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -95,6 +97,8 @@
     // that if recents doesn't tell us to remove the prolonged animation, we will get rid of it
     // when new animation is set.
     private boolean mClearProlongedAnimation;
+    private int mTransit;
+    private int mTransitFlags;
 
     /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */
     ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<>();
@@ -114,15 +118,16 @@
         mAnimator = mService.mAnimator;
     }
 
-    public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame,
-            int stackClip) {
+    public void setAnimation(Animation anim, int width, int height, int parentWidth,
+            int parentHeight, boolean skipFirstFrame, int stackClip, int transit,
+            int transitFlags) {
         if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
                 + ": " + anim + " wxh=" + width + "x" + height
                 + " hasContentToDisplay=" + mAppToken.hasContentToDisplay());
         animation = anim;
         animating = false;
         if (!anim.isInitialized()) {
-            anim.initialize(width, height, width, height);
+            anim.initialize(width, height, parentWidth, parentHeight);
         }
         anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
         anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
@@ -144,7 +149,9 @@
         hasTransformation = true;
         mStackClip = stackClip;
 
-        this.mSkipFirstFrame = skipFirstFrame;
+        mSkipFirstFrame = skipFirstFrame;
+        mTransit = transit;
+        mTransitFlags = transitFlags;
 
         if (!mAppToken.fillsParent()) {
             anim.setBackgroundColor(0);
@@ -185,12 +192,22 @@
             mAppToken.clearAllDrawn();
         }
         mStackClip = STACK_CLIP_BEFORE_ANIM;
+        mTransit = TRANSIT_UNSET;
+        mTransitFlags = 0;
     }
 
     public boolean isAnimating() {
         return animation != null || mAppToken.inPendingTransaction;
     }
 
+    public int getTransit() {
+        return mTransit;
+    }
+
+    int getTransitFlags() {
+        return mTransitFlags;
+    }
+
     public void clearThumbnail() {
         if (thumbnail != null) {
             thumbnail.hide();
@@ -216,6 +233,7 @@
             toAppAnimator.updateLayers();
             updateLayers();
             toAppAnimator.usingTransferredAnimation = true;
+            toAppAnimator.mTransit = mTransit;
         }
         if (transferWinAnimator != null) {
             mAllAppWinAnimators.remove(transferWinAnimator);
@@ -435,6 +453,8 @@
         if (animating || animation != null) {
             pw.print(prefix); pw.print("animating="); pw.println(animating);
             pw.print(prefix); pw.print("animation="); pw.println(animation);
+            pw.print(prefix); pw.print("mTransit="); pw.println(mTransit);
+            pw.print(prefix); pw.print("mTransitFlags="); pw.println(mTransitFlags);
         }
         if (hasTransformation) {
             pw.print(prefix); pw.print("XForm: ");
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e3588ff..a44c8aa 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -19,6 +19,8 @@
 import static android.app.ActivityManager.StackId;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -152,6 +154,9 @@
     int mRotationAnimationHint;
     private int mPendingRelaunchCount;
 
+    private boolean mLastContainsShowWhenLockedWindow;
+    private boolean mLastContainsDismissKeyguardWindow;
+
     private ArrayList<WindowSurfaceController.SurfaceControlWithBackground> mSurfaceViewBackgrounds =
         new ArrayList<>();
 
@@ -718,6 +723,13 @@
         if (gotReplacementWindow) {
             mService.scheduleWindowReplacementTimeouts(this);
         }
+        checkKeyguardFlagsChanged();
+    }
+
+    @Override
+    void removeChild(WindowState child) {
+        super.removeChild(child);
+        checkKeyguardFlagsChanged();
     }
 
     private boolean waitingForReplacement() {
@@ -808,21 +820,6 @@
         }
     }
 
-    /**
-     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
-     */
-    void overridePlayingAppAnimations(Animation a) {
-        if (mAppAnimator.isAnimating()) {
-            final WindowState win = findMainWindow();
-            if (win == null) {
-                return;
-            }
-            final int width = win.mContainingFrame.width();
-            final int height = win.mContainingFrame.height();
-            mAppAnimator.setAnimation(a, width, height, false, STACK_CLIP_NONE);
-        }
-    }
-
     void resetJustMovedInStack() {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             (mChildren.get(i)).resetJustMovedInStack();
@@ -1224,6 +1221,35 @@
         mFillsParent = fillsParent;
     }
 
+    boolean containsDismissKeyguardWindow() {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean containsShowWhenLockedWindow() {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void checkKeyguardFlagsChanged() {
+        final boolean containsDismissKeyguard = containsDismissKeyguardWindow();
+        final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
+        if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
+                || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
+            mService.notifyKeyguardFlagsChanged(null /* callback */);
+        }
+        mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
+        mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
+    }
+
     @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8db8118..1960285 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -62,31 +62,23 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
-import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
-import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
-import static com.android.server.wm.WindowAnimator.KEYGUARD_ANIMATING_OUT;
-import static com.android.server.wm.WindowAnimator.KEYGUARD_ANIM_TIMEOUT_MS;
-import static com.android.server.wm.WindowAnimator.KEYGUARD_NOT_SHOWN;
-import static com.android.server.wm.WindowAnimator.KEYGUARD_SHOWN;
+
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
+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_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -105,8 +97,6 @@
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
-import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
-import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
 
 import android.annotation.NonNull;
@@ -133,8 +123,6 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
 
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputMethodClient;
@@ -467,24 +455,7 @@
             }
             mService.mLastWindowForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
 
-            if (policy.isKeyguardLocked()) {
-                // The screen is locked and no top system window is requesting an orientation.
-                // Return either the orientation of the show-when-locked app (if there is any) or
-                // the orientation of the keyguard. No point in searching from the rest of apps.
-                WindowState winShowWhenLocked = (WindowState) policy.getWinShowWhenLockedLw();
-                AppWindowToken appShowWhenLocked = winShowWhenLocked == null
-                        ? null : winShowWhenLocked.mAppToken;
-                if (appShowWhenLocked != null) {
-                    int req = appShowWhenLocked.getOrientation();
-                    if (req == SCREEN_ORIENTATION_BEHIND) {
-                        req = mService.mLastKeyguardForcedOrientation;
-                    }
-                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Done at " + appShowWhenLocked
-                            + " -- show when locked, return " + req);
-                    return req;
-                }
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                        "No one is requesting an orientation when the screen is locked");
+            if (policy.isKeyguardShowingAndNotOccluded()) {
                 return mService.mLastKeyguardForcedOrientation;
             }
         }
@@ -639,7 +610,7 @@
             win.getTouchableRegion(mTmpRegion);
             mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
         }
-        if (getDockedStackVisibleForUserLocked() != null) {
+        if (getDockedStackLocked() != null) {
             mDividerControllerLocked.getTouchRegion(mTmpRect);
             mTmpRegion.set(mTmpRect);
             mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -991,11 +962,10 @@
 
     /**
      * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not
-     * visible, as long as it's not hidden because the current user doesn't have any tasks there.
+     * visible.
      */
-    TaskStack getDockedStackVisibleForUserLocked() {
-        final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
-        return (stack != null && stack.isVisible(true /* ignoreKeyguard */)) ? stack : null;
+    TaskStack getDockedStackIgnoringVisibility() {
+        return mService.mStackIdToStack.get(DOCKED_STACK_ID);
     }
 
     /** Find the visible, touch-deliverable window under the given point */
@@ -2082,6 +2052,20 @@
         }
     }
 
+    /**
+     * Starts the Keyguard exit animation on all windows that don't belong to an app token.
+     */
+    void startKeyguardExitOnNonAppWindows(boolean onWallpaper, boolean goingToShade) {
+        final WindowManagerPolicy policy = mService.mPolicy;
+        for (int i = mWindows.size() - 1; i >= 0; i--) {
+            final WindowState window = mWindows.get(i);
+            if (window.mAppToken == null && policy.canBeHiddenByKeyguardLw(window)) {
+                window.mWinAnimator.setAnimation(
+                        policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
+            }
+        }
+    }
+
     boolean checkWaitingForWindows() {
 
         boolean haveBootMsg = false;
@@ -2137,59 +2121,10 @@
     }
 
     void updateWindowsForAnimator(WindowAnimator animator) {
-        final WindowManagerPolicy policy = animator.mPolicy;
-        final int keyguardGoingAwayFlags = animator.mKeyguardGoingAwayFlags;
-        final boolean keyguardGoingAwayToShade =
-                (keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0;
-        final boolean keyguardGoingAwayNoAnimation =
-                (keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0;
-        final boolean keyguardGoingAwayWithWallpaper =
-                (keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0;
-
-        if (animator.mKeyguardGoingAway) {
-            for (int i = mWindows.size() - 1; i >= 0; i--) {
-                WindowState win = mWindows.get(i);
-                if (!policy.isKeyguardHostWindow(win.mAttrs)) {
-                    continue;
-                }
-                final WindowStateAnimator winAnimator = win.mWinAnimator;
-                if (policy.isKeyguardShowingAndNotOccluded()) {
-                    if (!winAnimator.mAnimating) {
-                        if (DEBUG_KEYGUARD) Slog.d(TAG,
-                                "updateWindowsForAnimator: creating delay animation");
-
-                        // Create a new animation to delay until keyguard is gone on its own.
-                        winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
-                        winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
-                        winAnimator.mAnimationIsEntrance = false;
-                        winAnimator.mAnimationStartTime = -1;
-                        winAnimator.mKeyguardGoingAwayAnimation = true;
-                        winAnimator.mKeyguardGoingAwayWithWallpaper
-                                = keyguardGoingAwayWithWallpaper;
-                    }
-                } else {
-                    if (DEBUG_KEYGUARD) Slog.d(TAG,
-                            "updateWindowsForAnimator: StatusBar is no longer keyguard");
-                    animator.mKeyguardGoingAway = false;
-                    winAnimator.clearAnimation();
-                }
-                break;
-            }
-        }
-
-        animator.mForceHiding = KEYGUARD_NOT_SHOWN;
-
-        boolean wallpaperInUnForceHiding = false;
-        boolean startingInUnForceHiding = false;
-        ArrayList<WindowStateAnimator> unForceHiding = null;
-        WindowState wallpaper = null;
         final WallpaperController wallpaperController = mWallpaperController;
         for (int i = mWindows.size() - 1; i >= 0; i--) {
             WindowState win = mWindows.get(i);
             WindowStateAnimator winAnimator = win.mWinAnimator;
-            final int flags = win.mAttrs.flags;
-            boolean canBeForceHidden = policy.canBeForceHidden(win, win.mAttrs);
-            boolean shouldBeForceHidden = animator.shouldForceHide(win);
             if (winAnimator.hasSurface()) {
                 final boolean wasAnimating = winAnimator.mWasAnimating;
                 final boolean nowAnimating = winAnimator.stepAnimationLocked(animator.mCurrentTime);
@@ -2208,129 +2143,6 @@
                                 "updateWindowsAndWallpaperLocked 2", pendingLayoutChanges);
                     }
                 }
-
-                if (policy.isForceHiding(win.mAttrs)) {
-                    if (!wasAnimating && nowAnimating) {
-                        if (DEBUG_KEYGUARD || DEBUG_ANIM || DEBUG_VISIBILITY) Slog.v(TAG,
-                                "Animation started that could impact force hide: " + win);
-                        animator.mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
-                        pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                        if (DEBUG_LAYOUT_REPEATS) {
-                            mService.mWindowPlacerLocked.debugLayoutRepeats(
-                                    "updateWindowsAndWallpaperLocked 3", pendingLayoutChanges);
-                        }
-                        mService.mFocusMayChange = true;
-                    } else if (animator.mKeyguardGoingAway && !nowAnimating) {
-                        // Timeout!!
-                        Slog.e(TAG, "Timeout waiting for animation to startup");
-                        policy.startKeyguardExitAnimation(0, 0);
-                        animator.mKeyguardGoingAway = false;
-                    }
-                    if (win.isReadyForDisplay()) {
-                        if (nowAnimating && win.mWinAnimator.mKeyguardGoingAwayAnimation) {
-                            animator.mForceHiding = KEYGUARD_ANIMATING_OUT;
-                        } else {
-                            animator.mForceHiding = win.isDrawnLw()
-                                    ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
-                        }
-                    }
-                    if (DEBUG_KEYGUARD || DEBUG_VISIBILITY) Slog.v(TAG,
-                            "Force hide " + animator.forceHidingToString()
-                                    + " hasSurface=" + win.mHasSurface
-                                    + " policyVis=" + win.mPolicyVisibility
-                                    + " destroying=" + win.mDestroying
-                                    + " parentHidden=" + win.isParentWindowHidden()
-                                    + " vis=" + win.mViewVisibility
-                                    + " hidden=" + win.mToken.hidden
-                                    + " anim=" + win.mWinAnimator.mAnimation);
-                } else if (canBeForceHidden) {
-                    if (shouldBeForceHidden) {
-                        if (!win.hideLw(false, false)) {
-                            // Was already hidden
-                            continue;
-                        }
-                        if (DEBUG_KEYGUARD || DEBUG_VISIBILITY) Slog.v(TAG,
-                                "Now policy hidden: " + win);
-                    } else {
-                        final Animation postKeyguardExitAnimation =
-                                animator.mPostKeyguardExitAnimation;
-                        boolean applyExistingExitAnimation = postKeyguardExitAnimation != null
-                                && !postKeyguardExitAnimation.hasEnded()
-                                && !winAnimator.mKeyguardGoingAwayAnimation
-                                && win.hasDrawnLw()
-                                && !win.isChildWindow()
-                                && !win.mIsImWindow
-                                && isDefaultDisplay;
-
-                        // If the window is already showing and we don't need to apply an existing
-                        // Keyguard exit animation, skip.
-                        if (!win.showLw(false, false) && !applyExistingExitAnimation) {
-                            continue;
-                        }
-                        final boolean visibleNow = win.isVisibleNow();
-                        if (!visibleNow) {
-                            // Couldn't really show, must showLw() again when win becomes visible.
-                            win.hideLw(false, false);
-                            continue;
-                        }
-                        if (DEBUG_KEYGUARD || DEBUG_VISIBILITY) Slog.v(TAG,
-                                "Now policy shown: " + win);
-                        if ((animator.mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
-                                && !win.isChildWindow()) {
-                            if (unForceHiding == null) {
-                                unForceHiding = new ArrayList<>();
-                            }
-                            unForceHiding.add(winAnimator);
-                            if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
-                                wallpaperInUnForceHiding = true;
-                            }
-                            if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
-                                startingInUnForceHiding = true;
-                            }
-                        } else if (applyExistingExitAnimation) {
-                            // We're already in the middle of an animation. Use the existing
-                            // animation to bring in this window.
-                            if (DEBUG_KEYGUARD) Slog.v(TAG,
-                                    "Applying existing Keyguard exit animation to new window: win="
-                                            + win);
-
-                            final Animation a = policy.createForceHideEnterAnimation(false,
-                                    keyguardGoingAwayToShade);
-                            winAnimator.setAnimation(a, postKeyguardExitAnimation.getStartTime(),
-                                    STACK_CLIP_BEFORE_ANIM);
-                            winAnimator.mKeyguardGoingAwayAnimation = true;
-                            winAnimator.mKeyguardGoingAwayWithWallpaper
-                                    = keyguardGoingAwayWithWallpaper;
-                        }
-                        final WindowState currentFocus = mService.mCurrentFocus;
-                        if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
-                            // We are showing on top of the current
-                            // focus, so re-evaluate focus to make
-                            // sure it is correct.
-                            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG,
-                                    "updateWindowsForAnimator: setting mFocusMayChange true");
-                            mService.mFocusMayChange = true;
-                        }
-                    }
-                    if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
-                        animator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
-                        pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                        if (DEBUG_LAYOUT_REPEATS) {
-                            mService.mWindowPlacerLocked.debugLayoutRepeats(
-                                    "updateWindowsAndWallpaperLocked 4", pendingLayoutChanges);
-                        }
-                    }
-                }
-            }
-
-            // If the window doesn't have a surface, the only thing we care about is the correct
-            // policy visibility.
-            else if (canBeForceHidden) {
-                if (shouldBeForceHidden) {
-                    win.hideLw(false, false);
-                } else {
-                    win.showLw(false, false);
-                }
             }
 
             final AppWindowToken atoken = win.mAppToken;
@@ -2355,77 +2167,7 @@
                     appAnimator.thumbnailLayer = winAnimator.mAnimLayer;
                 }
             }
-            if (win.mIsWallpaper) {
-                wallpaper = win;
-            }
         } // end forall windows
-
-        // If we have windows that are being shown due to them no longer being force-hidden, apply
-        // the appropriate animation to them if animations are not disabled.
-        if (unForceHiding != null) {
-            if (!keyguardGoingAwayNoAnimation) {
-                boolean first = true;
-                for (int i=unForceHiding.size()-1; i>=0; i--) {
-                    final WindowStateAnimator winAnimator = unForceHiding.get(i);
-                    final Animation a = policy.createForceHideEnterAnimation(
-                            wallpaperInUnForceHiding && !startingInUnForceHiding,
-                            keyguardGoingAwayToShade);
-                    if (a != null) {
-                        if (DEBUG_KEYGUARD) Slog.v(TAG,
-                                "Starting keyguard exit animation on window " + winAnimator.mWin);
-                        winAnimator.setAnimation(a, STACK_CLIP_BEFORE_ANIM);
-                        winAnimator.mKeyguardGoingAwayAnimation = true;
-                        winAnimator.mKeyguardGoingAwayWithWallpaper
-                                = keyguardGoingAwayWithWallpaper;
-                        if (first) {
-                            animator.mPostKeyguardExitAnimation = a;
-                            animator.mPostKeyguardExitAnimation.setStartTime(animator.mCurrentTime);
-                            first = false;
-                        }
-                    }
-                }
-            } else if (animator.mKeyguardGoingAway) {
-                policy.startKeyguardExitAnimation(animator.mCurrentTime, 0 /* duration */);
-                animator.mKeyguardGoingAway = false;
-            }
-
-
-            // Wallpaper is going away in un-force-hide motion, animate it as well.
-            if (!wallpaperInUnForceHiding && wallpaper != null && !keyguardGoingAwayNoAnimation) {
-                if (DEBUG_KEYGUARD) Slog.d(TAG,
-                        "updateWindowsForAnimator: wallpaper animating away");
-                final Animation a = policy.createForceHideWallpaperExitAnimation(
-                        keyguardGoingAwayToShade);
-                if (a != null) {
-                    wallpaper.mWinAnimator.setAnimation(a);
-                }
-            }
-        }
-
-        if (animator.mPostKeyguardExitAnimation != null) {
-            // We're in the midst of a keyguard exit animation.
-            if (animator.mKeyguardGoingAway) {
-                policy.startKeyguardExitAnimation(animator.mCurrentTime +
-                                animator.mPostKeyguardExitAnimation.getStartOffset(),
-                        animator.mPostKeyguardExitAnimation.getDuration());
-                animator.mKeyguardGoingAway = false;
-            }
-            // mPostKeyguardExitAnimation might either be ended normally, cancelled, or "orphaned",
-            // meaning that the window it was running on was removed. We check for hasEnded() for
-            // ended normally and cancelled case, and check the time for the "orphaned" case.
-            else if (animator.mPostKeyguardExitAnimation.hasEnded()
-                    || animator.mCurrentTime - animator.mPostKeyguardExitAnimation.getStartTime()
-                    > animator.mPostKeyguardExitAnimation.getDuration()) {
-                // Done with the animation, reset.
-                if (DEBUG_KEYGUARD) Slog.v(TAG, "Done with Keyguard exit animations.");
-                animator.mPostKeyguardExitAnimation = null;
-            }
-        }
-
-        final WindowState winShowWhenLocked = (WindowState) policy.getWinShowWhenLockedLw();
-        if (winShowWhenLocked != null) {
-            animator.mLastShowWinWhenLocked = winShowWhenLocked;
-        }
     }
 
     void updateWallpaperForAnimator(WindowAnimator animator) {
@@ -2591,18 +2333,12 @@
         final WindowManagerPolicy policy = mService.mPolicy;
         for (int winNdx = mWindows.size() - 1; winNdx >= 0; --winNdx) {
             final WindowState win = mWindows.get(winNdx);
-            final boolean isForceHiding = policy.isForceHiding(win.mAttrs);
             final boolean keyguard = policy.isKeyguardHostWindow(win.mAttrs);
-            if (win.isVisibleLw() && (win.mAppToken != null || isForceHiding || keyguard)) {
+            if (win.isVisibleLw() && (win.mAppToken != null || keyguard)) {
                 win.mWinAnimator.mDrawState = DRAW_PENDING;
                 // Force add to mResizingWindows.
                 win.mLastContentInsets.set(-1, -1, -1, -1);
                 mService.mWaitingForDrawn.add(win);
-
-                // No need to wait for the windows below Keyguard.
-                if (isForceHiding) {
-                    return;
-                }
             }
         }
     }
@@ -2672,9 +2408,8 @@
                 mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
                 for (int i = mWindows.size() - 1; i >= 0; i--) {
                     final WindowState w = mWindows.get(i);
-                    if (w.mHasSurface) {
-                        mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow());
-                    }
+                    mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(),
+                            mService.mInputMethodTarget);
                 }
                 pendingLayoutChanges |= mService.mPolicy.finishPostLayoutPolicyLw();
                 if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
@@ -2855,7 +2590,7 @@
 
             // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid
             // wasting time and funky changes while a window is animating away.
-            final boolean gone = (behindDream && mService.mPolicy.canBeForceHidden(win, win.mAttrs))
+            final boolean gone = (behindDream && mService.mPolicy.canBeHiddenByKeyguardLw(win))
                     || win.isGoneForLayoutLw();
 
             if (DEBUG_LAYOUT && !win.mLayoutAttached) {
@@ -2927,7 +2662,7 @@
                 // If this view is GONE, then skip it -- keep the current frame, and let the caller
                 // know so they can ignore it if they want.  (We do the normal layout for INVISIBLE
                 // windows, since that means "perform layout as normal, just don't display").
-                if (attachedBehindDream && mService.mPolicy.canBeForceHidden(win, win.mAttrs)) {
+                if (attachedBehindDream && mService.mPolicy.canBeHiddenByKeyguardLw(win)) {
                     continue;
                 }
                 if ((win.mViewVisibility != GONE && win.mRelayoutCalled) || !win.mHaveFrame
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 530fb1b..743caf8 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -44,7 +44,6 @@
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.IDockedStackListener;
-import android.view.SurfaceControl;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
@@ -57,7 +56,6 @@
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
 /**
  * Keeps information about the docked stack divider.
@@ -283,7 +281,7 @@
         if (mWindow == null) {
             return;
         }
-        TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
+        TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
 
         // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
         final boolean visible = stack != null;
@@ -536,7 +534,7 @@
     }
 
     private void checkMinimizeChanged(boolean animate) {
-        if (mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
+        if (mDisplayContent.getDockedStackIgnoringVisibility() == null) {
             return;
         }
         final TaskStack homeStack = mDisplayContent.getHomeStack();
@@ -683,7 +681,7 @@
     }
 
     private boolean setMinimizedDockedStack(boolean minimized) {
-        final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
+        final TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
         notifyDockedStackMinimizedChanged(minimized, 0);
         return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
     }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a28dc10..26f79a9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -483,6 +483,7 @@
                     appToken.voiceInteraction);
 
             mService.mOpeningApps.remove(appToken);
+            mService.mUnknownAppVisibilityController.appRemoved(appToken);
             appToken.waitingToShow = false;
             if (mService.mClosingApps.contains(appToken)) {
                 delayed = true;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7f543f9..b889db2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -350,7 +350,7 @@
         return mFillsParent
                 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
                 || displayContent == null
-                || displayContent.getDockedStackVisibleForUserLocked() != null;
+                || displayContent.getDockedStackIgnoringVisibility() != null;
     }
 
     /** Original bounds of the task if applicable, otherwise fullscreen rect. */
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 4d8f29d..fff2981 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -871,7 +871,7 @@
             mAdjustImeAmount = adjustAmount;
             mAdjustDividerAmount = adjustDividerAmount;
             updateAdjustedBounds();
-            return isVisible(true /* ignoreKeyguard */);
+            return isVisible();
         } else {
             return false;
         }
@@ -907,7 +907,7 @@
         if (minimizeAmount != mMinimizeAmount) {
             mMinimizeAmount = minimizeAmount;
             updateAdjustedBounds();
-            return isVisible(true /* ignoreKeyguard */);
+            return isVisible();
         } else {
             return false;
         }
@@ -1218,21 +1218,6 @@
         }
     }
 
-    boolean isVisible() {
-        return isVisible(false /* ignoreKeyguard */);
-    }
-
-    boolean isVisible(boolean ignoreKeyguard) {
-        final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
-                && !mService.mAnimator.mKeyguardGoingAway;
-        if (!ignoreKeyguard && keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
-            // The keyguard is showing and the stack shouldn't show on top of the keyguard.
-            return false;
-        }
-
-        return super.isVisible();
-    }
-
     boolean hasTaskForUser(int userId) {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final Task task = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
new file mode 100644
index 0000000..2f49c82
--- /dev/null
+++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
@@ -0,0 +1,139 @@
+/*
+ * 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.annotation.NonNull;
+import android.util.ArrayMap;
+
+import com.android.server.wm.WindowManagerService.H;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the set of {@link AppWindowToken}s for which we don't know yet whether it's visible or
+ * not. This happens when starting an activity while the lockscreen is showing. In that case, the
+ * keyguard flags an app might set influence it's visibility, so we wait until this is resolved to
+ * start the transition to avoid flickers.
+ */
+class UnknownAppVisibilityController {
+
+    /**
+     * We are currently waiting until the app is done resuming.
+     */
+    private static final int UNKNOWN_STATE_WAITING_RESUME = 1;
+
+    /**
+     * The activity has finished resuming, and we are waiting on the next relayout.
+     */
+    private static final int UNKNOWN_STATE_WAITING_RELAYOUT = 2;
+
+    /**
+     * The client called {@link Session#relayout} with the appropriate Keyguard flags and we are
+     * waiting until activity manager has updated the visibilities of all the apps.
+     */
+    private static final int UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE = 3;
+
+    // Set of apps for which we don't know yet whether it's visible or not, depending on what kind
+    // of lockscreen flags the app might set during its first relayout.
+    private final ArrayMap<AppWindowToken, Integer> mUnknownApps = new ArrayMap<>();
+
+    private final WindowManagerService mService;
+
+    UnknownAppVisibilityController(WindowManagerService service) {
+        mService = service;
+    }
+
+    boolean allResolved() {
+        return mUnknownApps.isEmpty();
+    }
+
+    void clear() {
+        mUnknownApps.clear();
+    }
+
+    String getDebugMessage() {
+        final StringBuilder builder = new StringBuilder();
+        for (int i = mUnknownApps.size() - 1; i >= 0; i--) {
+            builder.append("app=").append(mUnknownApps.keyAt(i))
+                    .append(" state=").append(mUnknownApps.valueAt(i));
+            if (i != 0) {
+                builder.append(' ');
+            }
+        }
+        return builder.toString();
+    }
+
+    void appRemoved(@NonNull AppWindowToken appWindow) {
+        mUnknownApps.remove(appWindow);
+    }
+
+    /**
+     * Notifies that {@param appWindow} has been launched behind Keyguard, and we need to wait until
+     * it is resumed and relaid out to resolve the visibility.
+     */
+    void notifyLaunched(@NonNull AppWindowToken appWindow) {
+        mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_RESUME);
+    }
+
+    /**
+     * Notifies that {@param appWindow} has finished resuming.
+     */
+    void notifyAppResumedFinished(@NonNull AppWindowToken appWindow) {
+        if (mUnknownApps.containsKey(appWindow)
+                && mUnknownApps.get(appWindow) == UNKNOWN_STATE_WAITING_RESUME) {
+            mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_RELAYOUT);
+        }
+    }
+
+    /**
+     * Notifies that {@param appWindow} has relaid out.
+     */
+    void notifyRelayouted(@NonNull AppWindowToken appWindow) {
+        if (!mUnknownApps.containsKey(appWindow)) {
+            return;
+        }
+        int state = mUnknownApps.get(appWindow);
+        if (state == UNKNOWN_STATE_WAITING_RELAYOUT) {
+            mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE);
+            mService.notifyKeyguardFlagsChanged(this::notifyVisibilitiesUpdated);
+        }
+    }
+
+    private void notifyVisibilitiesUpdated() {
+        boolean changed = false;
+        for (int i = mUnknownApps.size() - 1; i >= 0; i--) {
+            if (mUnknownApps.valueAt(i) == UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE) {
+                mUnknownApps.removeAt(i);
+                changed = true;
+            }
+        }
+        if (changed) {
+            mService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        if (mUnknownApps.isEmpty()) {
+            return;
+        }
+        pw.println(prefix + "Unknown visibilities:");
+        for (int i = mUnknownApps.size() - 1; i >= 0; i--) {
+            pw.println(prefix + "  app=" + mUnknownApps.keyAt(i)
+                    + " state=" + mUnknownApps.valueAt(i));
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index c9f1ffc..250d381 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -18,9 +18,12 @@
 
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+
+import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -39,6 +42,7 @@
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.WindowManager;
+import android.view.animation.Animation;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -126,6 +130,16 @@
         return isWallpaperVisible(mWallpaperTarget);
     }
 
+    /**
+     * Starts {@param a} on all wallpaper windows.
+     */
+    void startWallpaperAnimation(Animation a) {
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            final WindowToken token = mWallpaperTokens.get(curTokenNdx);
+            token.startAnimation(a);
+        }
+    }
+
     private boolean isWallpaperVisible(WindowState wallpaperTarget) {
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
                 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
@@ -383,6 +397,7 @@
         boolean inFreeformSpace = false;
         boolean replacing = false;
         boolean keyguardGoingAwayWithWallpaper = false;
+        boolean needsShowWhenLockedWallpaper = false;
 
         for (int i = windows.size() - 1; i >= 0; i--) {
             w = windows.get(i);
@@ -413,7 +428,19 @@
 
             replacing |= w.mWillReplaceWindow;
             keyguardGoingAwayWithWallpaper |= (w.mAppToken != null
-                    && w.mWinAnimator.mKeyguardGoingAwayWithWallpaper);
+                    && AppTransition.isKeyguardGoingAwayTransit(
+                            w.mAppToken.mAppAnimator.getTransit())
+                    && (w.mAppToken.mAppAnimator.getTransitFlags()
+                            & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
+
+            if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
+                    && mService.mPolicy.isKeyguardLocked()
+                    && mService.mPolicy.isKeyguardOccluded()) {
+                // The lowest show when locked window decides whether we need to put the wallpaper
+                // behind.
+                needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
+                        || (w.mAppToken != null && !w.mAppToken.fillsParent());
+            }
 
             final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
             if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
@@ -447,14 +474,19 @@
             // appear and can determine the visibility, to avoid flickering.
             result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
 
-        } else if (keyguardGoingAwayWithWallpaper) {
-            // If the app is executing an animation because the keyguard is going away (and the
-            // keyguard was showing the wallpaper) keep the wallpaper during the animation so it
-            // doesn't flicker out by having it be its own target.
+        } else if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
+            // Keep the wallpaper during Keyguard exit but also when it's needed for a
+            // non-fullscreen show when locked activity.
             result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
         }
     }
 
+    private boolean isFullscreen(WindowManager.LayoutParams attrs) {
+        return attrs.x == 0 && attrs.y == 0
+                && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
+                && attrs.height == WindowManager.LayoutParams.MATCH_PARENT;
+    }
+
     /** Updates the target wallpaper if needed and returns true if an update happened. */
     private boolean updateWallpaperWindowsTarget(
             ReadOnlyWindowList windows, FindWallpaperTargetResult result) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 4c62245..993a918 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -17,11 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -39,7 +35,6 @@
 import android.view.Choreographer;
 import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
-import android.view.animation.Animation;
 
 import java.io.PrintWriter;
 
@@ -50,9 +45,6 @@
 public class WindowAnimator {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM;
 
-    /** How long to give statusbar to clear the private keyguard flag when animating out */
-    static final long KEYGUARD_ANIM_TIMEOUT_MS = 1000;
-
     final WindowManagerService mService;
     final Context mContext;
     final WindowManagerPolicy mPolicy;
@@ -86,37 +78,10 @@
 
     boolean mInitialized = false;
 
-    boolean mKeyguardGoingAway;
-    int mKeyguardGoingAwayFlags;
-    boolean mKeyguardAnimatingIn;
-
-    /** Use one animation for all entering activities after keyguard is dismissed. */
-    Animation mPostKeyguardExitAnimation;
-
-    // forceHiding states.
-    static final int KEYGUARD_NOT_SHOWN     = 0;
-    static final int KEYGUARD_SHOWN         = 1;
-    static final int KEYGUARD_ANIMATING_OUT = 2;
-    int mForceHiding = KEYGUARD_NOT_SHOWN;
-
     // When set to true the animator will go over all windows after an animation frame is posted and
     // check if some got replaced and can be removed.
     private boolean mRemoveReplacedWindows = false;
 
-    private final AppTokenList mTmpExitingAppTokens = new AppTokenList();
-
-    /** The window that was previously hiding the Keyguard. */
-    WindowState mLastShowWinWhenLocked;
-
-    String forceHidingToString() {
-        switch (mForceHiding) {
-            case KEYGUARD_NOT_SHOWN:    return "KEYGUARD_NOT_SHOWN";
-            case KEYGUARD_SHOWN:        return "KEYGUARD_SHOWN";
-            case KEYGUARD_ANIMATING_OUT:return "KEYGUARD_ANIMATING_OUT";
-            default: return "KEYGUARD STATE UNKNOWN " + mForceHiding;
-        }
-    }
-
     WindowAnimator(final WindowManagerService service) {
         mService = service;
         mContext = service.mContext;
@@ -153,63 +118,6 @@
         mDisplayContentsAnimators.delete(displayId);
     }
 
-    /**
-     * @return The window that is currently hiding the Keyguard, or if it was hiding the Keyguard,
-     *         and it's still animating.
-     */
-    private WindowState getWinShowWhenLockedOrAnimating() {
-        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
-        if (winShowWhenLocked != null) {
-            return winShowWhenLocked;
-        }
-        if (mLastShowWinWhenLocked != null && mLastShowWinWhenLocked.isOnScreen()
-                && mLastShowWinWhenLocked.isAnimatingLw()
-                && (mLastShowWinWhenLocked.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
-            return mLastShowWinWhenLocked;
-        }
-        return null;
-    }
-
-    boolean shouldForceHide(WindowState win) {
-        final WindowState imeTarget = mService.mInputMethodTarget;
-        final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() &&
-                ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0
-                        || !mPolicy.canBeForceHidden(imeTarget, imeTarget.mAttrs));
-
-        final WindowState winShowWhenLocked = getWinShowWhenLockedOrAnimating();
-        final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
-                null : winShowWhenLocked.mAppToken;
-
-        boolean allowWhenLocked = false;
-        // Show IME over the keyguard if the target allows it
-        allowWhenLocked |= (win.mIsImWindow || imeTarget == win) && showImeOverKeyguard;
-        // Show SHOW_WHEN_LOCKED windows that turn on the screen
-        allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && win.mTurnOnScreen;
-
-        if (appShowWhenLocked != null) {
-            allowWhenLocked |= appShowWhenLocked == win.mAppToken
-                    // Show all SHOW_WHEN_LOCKED windows if some apps are shown over lockscreen
-                    || (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
-                    // Show error dialogs over apps that are shown on lockscreen
-                    || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
-        }
-
-        // Allow showing a window that dismisses Keyguard if the policy allows it. This is used for
-        // when the policy knows that the Keyguard can be dismissed without user interaction to
-        // provide a smooth transition in that case.
-        allowWhenLocked |= (win.mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0
-                && mPolicy.canShowDismissingWindowWhileLockedLw();
-
-        // Only hide windows if the keyguard is active and not animating away.
-        boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded()
-                && mForceHiding != KEYGUARD_ANIMATING_OUT
-                && !mKeyguardAnimatingIn;
-        boolean hideDockDivider = win.mAttrs.type == TYPE_DOCK_DIVIDER
-                && win.getDisplayContent().getDockedStackLocked() == null;
-        return keyguardOn && !allowWhenLocked && (win.getDisplayId() == DEFAULT_DISPLAY)
-                || hideDockDivider;
-    }
-
     /** Locked on mService.mWindowMap. */
     private void animateLocked(long frameTimeNs) {
         if (!mInitialized) {
@@ -388,7 +296,6 @@
         if (dumpAll) {
             pw.print(prefix); pw.print("mAnimTransactionSequence=");
                     pw.print(mAnimTransactionSequence);
-                    pw.print(" mForceHiding="); pw.println(forceHidingToString());
             pw.print(prefix); pw.print("mCurrentTime=");
                     pw.println(TimeUtils.formatUptime(mCurrentTime));
         }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index db61c3e..e30ebcb 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -413,12 +413,6 @@
         }
     }
 
-    void overridePlayingAppAnimations(Animation a) {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            mChildren.get(i).overridePlayingAppAnimations(a);
-        }
-    }
-
     void setOrientation(int orientation) {
         mOrientation = orientation;
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1357c47..2fef928 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -178,10 +178,12 @@
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
@@ -218,7 +220,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
@@ -518,8 +519,6 @@
     int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
     boolean mAltOrientation = false;
 
-    private boolean mKeyguardWaitingForActivityDrawn;
-
     int mDockedStackCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
     Rect mDockedStackCreateBounds;
 
@@ -584,6 +583,9 @@
     final ArraySet<AppWindowToken> mOpeningApps = new ArraySet<>();
     final ArraySet<AppWindowToken> mClosingApps = new ArraySet<>();
 
+    final UnknownAppVisibilityController mUnknownAppVisibilityController =
+            new UnknownAppVisibilityController(this);
+
     boolean mIsTouchDevice;
 
     final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
@@ -889,7 +891,7 @@
             = new WindowManagerInternal.AppTransitionListener() {
 
         @Override
-        public void onAppTransitionCancelledLocked() {
+        public void onAppTransitionCancelledLocked(int transit) {
             mH.sendEmptyMessage(H.NOTIFY_APP_TRANSITION_CANCELLED);
         }
 
@@ -1926,6 +1928,10 @@
                         | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
                     win.mLayoutNeeded = true;
                 }
+                if (win.mAppToken != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
+                        || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
+                    win.mAppToken.checkKeyguardFlagsChanged();
+                }
             }
 
             if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
@@ -2069,6 +2075,10 @@
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
             }
 
+            if (win.mAppToken != null) {
+                mUnknownAppVisibilityController.notifyRelayouted(win.mAppToken);
+            }
+
             win.setDisplayLayoutNeeded();
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             configChanged = updateOrientationFromAppTokensLocked(false, displayId);
@@ -2351,8 +2361,10 @@
                 if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
                 final int containingWidth = frame.width();
                 final int containingHeight = frame.height();
-                atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight,
-                        mAppTransition.canSkipFirstFrame(), mAppTransition.getAppStackClipMode());
+                atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight, width,
+                        height, mAppTransition.canSkipFirstFrame(),
+                        mAppTransition.getAppStackClipMode(),
+                        transit, mAppTransition.getTransitFlags());
             }
         } else {
             atoken.mAppAnimator.clearAnimation();
@@ -2738,20 +2750,28 @@
         }
     }
 
+    @Override
+    public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
+        prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
+    }
+
     /**
      * @param transit What kind of transition is happening. Use one of the constants
      *                AppTransition.TRANSIT_*.
      * @param alwaysKeepCurrent If true and a transition is already set, new transition will NOT
      *                          be set.
+     * @param flags Additional flags for the app transition, Use a combination of the constants
+     *              AppTransition.TRANSIT_FLAG_*.
+     * @param forceOverride Always override the transit, not matter what was set previously.
      */
-    @Override
-    public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
+    public void prepareAppTransition(int transit, boolean alwaysKeepCurrent, int flags,
+            boolean forceOverride) {
         if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
         }
         synchronized(mWindowMap) {
-            boolean prepared = mAppTransition.prepareAppTransitionLocked(
-                    transit, alwaysKeepCurrent);
+            boolean prepared = mAppTransition.prepareAppTransitionLocked(transit, alwaysKeepCurrent,
+                    flags, forceOverride);
             if (prepared && okToDisplay()) {
                 mSkipAppTransitionAnimation = false;
             }
@@ -3186,6 +3206,19 @@
         }
     }
 
+    /**
+     * 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()")) {
@@ -3475,8 +3508,8 @@
     }
 
     @Override
-    public void overridePlayingAppAnimationsLw(Animation a) {
-        getDefaultDisplayContentLocked().overridePlayingAppAnimations(a);
+    public void notifyShowingDreamChanged() {
+        notifyKeyguardFlagsChanged(null /* callback */);
     }
 
     /**
@@ -3616,6 +3649,46 @@
         }
     }
 
+    /**
+     * @return true if the activity contains windows that have
+     *         {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set
+     */
+    public boolean containsShowWhenLockedWindow(IBinder token) {
+        synchronized (mWindowMap) {
+            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
+            return wtoken != null && wtoken.containsShowWhenLockedWindow();
+        }
+    }
+
+    /**
+     * @return true if the activity contains windows that have
+     *         {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set
+     */
+    public boolean containsDismissKeyguardWindow(IBinder token) {
+        synchronized (mWindowMap) {
+            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
+            return wtoken != null && wtoken.containsDismissKeyguardWindow();
+        }
+    }
+
+    /**
+     * Notifies activity manager that some Keyguard flags have changed and that it needs to
+     * reevaluate the visibilities of the activities.
+     * @param callback Runnable to be called when activity manager is done reevaluating visibilities
+     */
+    void notifyKeyguardFlagsChanged(@Nullable Runnable callback) {
+        final Runnable wrappedCallback = callback != null
+                ? () -> { synchronized (mWindowMap) { callback.run(); } }
+                : null;
+        mH.obtainMessage(H.NOTIFY_KEYGUARD_FLAGS_CHANGED, wrappedCallback).sendToTarget();
+    }
+
+    public boolean isKeyguardTrusted() {
+        synchronized (mWindowMap) {
+            return mPolicy.isKeyguardTrustedLw();
+        }
+    }
+
     // -------------------------------------------------------------
     // Misc IWindowSession methods
     // -------------------------------------------------------------
@@ -3752,6 +3825,12 @@
         }
     }
 
+    public boolean isShowingDream() {
+        synchronized (mWindowMap) {
+            return mPolicy.isShowingDreamLw();
+        }
+    }
+
     @Override
     public void dismissKeyguard() {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
@@ -3765,51 +3844,11 @@
 
     @Override
     public void keyguardGoingAway(int flags) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
-        }
-        if (DEBUG_KEYGUARD) Slog.d(TAG_WM,
-                "keyguardGoingAway: flags=0x" + Integer.toHexString(flags));
-        synchronized (mWindowMap) {
-            mAnimator.mKeyguardGoingAway = true;
-            mAnimator.mKeyguardGoingAwayFlags = flags;
-            mWindowPlacerLocked.requestTraversal();
-        }
     }
 
-    public void keyguardWaitingForActivityDrawn() {
-        if (DEBUG_KEYGUARD) Slog.d(TAG_WM, "keyguardWaitingForActivityDrawn");
+    public void onKeyguardOccludedChanged(boolean occluded) {
         synchronized (mWindowMap) {
-            mKeyguardWaitingForActivityDrawn = true;
-        }
-    }
-
-    public void notifyActivityDrawnForKeyguard() {
-        if (DEBUG_KEYGUARD) Slog.d(TAG_WM, "notifyActivityDrawnForKeyguard: waiting="
-                + mKeyguardWaitingForActivityDrawn + " Callers=" + Debug.getCallers(5));
-        synchronized (mWindowMap) {
-            if (mKeyguardWaitingForActivityDrawn) {
-                mPolicy.notifyActivityDrawnForKeyguardLw();
-                mKeyguardWaitingForActivityDrawn = false;
-            }
-        }
-    }
-
-    @Override
-    public void setKeyguardAnimatingIn(boolean animating) {
-        if (!checkCallingPermission(Manifest.permission.CONTROL_KEYGUARD,
-                "keyguardAnimatingIn()")) {
-            throw new SecurityException("Requires CONTROL_KEYGUARD permission");
-        }
-        synchronized (mWindowMap) {
-            mAnimator.mKeyguardAnimatingIn = animating;
-        }
-    }
-
-    public boolean isKeyguardAnimatingIn() {
-        synchronized (mWindowMap) {
-            return mAnimator.mKeyguardAnimatingIn;
+            mPolicy.onKeyguardOccludedChangedLw(occluded);
         }
     }
 
@@ -6014,7 +6053,7 @@
         public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
         public static final int RESTORE_POINTER_ICON = 55;
-
+        public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -6650,6 +6689,9 @@
                     }
                 }
                 break;
+                case NOTIFY_KEYGUARD_FLAGS_CHANGED: {
+                    mAmInternal.notifyKeyguardFlagsChanged((Runnable) msg.obj);
+                }
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
@@ -7688,6 +7730,15 @@
         }
     }
 
+    public void notifyAppResumedFinished(IBinder token) {
+        synchronized (mWindowMap) {
+            final AppWindowToken appWindow = mRoot.getAppWindowToken(token);
+            if (appWindow != null) {
+                mUnknownAppVisibilityController.notifyAppResumedFinished(appWindow);
+            }
+        }
+    }
+
     @Override
     public int getDockedDividerInsetsLw() {
         return getDefaultDisplayContentLocked().getDockedDividerController().getContentInsets();
@@ -7878,6 +7929,7 @@
                 pw.println();
 
         mInputMonitor.dump(pw, "  ");
+        mUnknownAppVisibilityController.dump(pw, "  ");
 
         if (dumpAll) {
             pw.print("  mSystemDecorLayer="); pw.print(mSystemDecorLayer);
@@ -8316,7 +8368,7 @@
     public int getDockedStackSide() {
         synchronized (mWindowMap) {
             final TaskStack dockedStack = getDefaultDisplayContentLocked()
-                    .getDockedStackVisibleForUserLocked();
+                    .getDockedStackIgnoringVisibility();
             return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 51fc9f0..534a3d2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -87,6 +87,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
@@ -1211,7 +1212,8 @@
         return displayContent != null ? displayContent.getDisplayInfo() : null;
     }
 
-    int getDisplayId() {
+    @Override
+    public int getDisplayId() {
         final DisplayContent displayContent = getDisplayContent();
         if (displayContent == null) {
             return -1;
@@ -2711,13 +2713,7 @@
             return false;
         }
 
-        Task task = getTask();
-        if (task == null || task.inHomeStack()) {
-            // Don't save surfaces for home stack apps. These usually resume and draw
-            // first frame very fast. Saving surfaces are mostly a waste of memory.
-            return false;
-        }
-
+        final Task task = getTask();
         final AppWindowToken taskTop = task.getTopVisibleAppToken();
         if (taskTop != null && taskTop != mAppToken) {
             // Don't save if the window is not the topmost window.
@@ -3751,6 +3747,7 @@
         return null;
     }
 
+    @Override
     public int getRotationAnimationHint() {
         if (mAppToken != null) {
             return mAppToken.mRotationAnimationHint;
@@ -3759,6 +3756,11 @@
         }
     }
 
+    @Override
+    public boolean isInputMethodWindow() {
+        return mIsImWindow;
+    }
+
     // This must be called while inside a transaction.
     boolean performShowLocked() {
         if (isHiddenFromUserLocked()) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2aeb50b..a428cce 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -187,9 +187,6 @@
 
     private boolean mAnimationStartDelayed;
 
-    boolean mKeyguardGoingAwayAnimation;
-    boolean mKeyguardGoingAwayWithWallpaper;
-
     /** The pixel format of the underlying SurfaceControl */
     int mSurfaceFormat;
 
@@ -294,8 +291,6 @@
             mLocalAnimating = false;
             mAnimation.cancel();
             mAnimation = null;
-            mKeyguardGoingAwayAnimation = false;
-            mKeyguardGoingAwayWithWallpaper = false;
             mStackClip = STACK_CLIP_BEFORE_ANIM;
         }
     }
@@ -451,8 +446,6 @@
             + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
 
         mAnimating = false;
-        mKeyguardGoingAwayAnimation = false;
-        mKeyguardGoingAwayWithWallpaper = false;
         mLocalAnimating = false;
         if (mAnimation != null) {
             mAnimation.cancel();
@@ -1268,11 +1261,6 @@
             return;
         }
 
-        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
-        if (w == winShowWhenLocked && mPolicy.isKeyguardShowingOrOccluded()) {
-            return;
-        }
-
         final TaskStack stack = task.mStack;
         stack.getDimBounds(mTmpStackBounds);
         final Rect surfaceInsets = w.getAttrs().surfaceInsets;
@@ -1688,17 +1676,9 @@
      * @return true if an animation has been loaded.
      */
     boolean applyAnimationLocked(int transit, boolean isEntrance) {
-        if ((mLocalAnimating && mAnimationIsEntrance == isEntrance)
-                || mKeyguardGoingAwayAnimation) {
+        if (mLocalAnimating && mAnimationIsEntrance == isEntrance) {
             // If we are trying to apply an animation, but already running
             // an animation of the same type, then just leave that one alone.
-
-            // If we are in a keyguard exit animation, and the window should animate away, modify
-            // keyguard exit animation such that it also fades out.
-            if (mAnimation != null && mKeyguardGoingAwayAnimation
-                    && transit == WindowManagerPolicy.TRANSIT_PREVIEW_DONE) {
-                applyFadeoutDuringKeyguardExitAnimation();
-            }
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 63820e5..f2682ba 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -11,6 +11,11 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
+import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_CLOSE;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
@@ -347,13 +352,16 @@
         final AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
                 topClosingApp.mAppAnimator;
 
-        mService.mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator,
-                mService.mOpeningApps, mService.mClosingApps);
+        final int flags = mService.mAppTransition.getTransitFlags();
+        int layoutRedo = mService.mAppTransition.goodToGo(transit, openingAppAnimator,
+                closingAppAnimator, mService.mOpeningApps, mService.mClosingApps);
+        handleNonAppWindowsInTransition(transit, flags);
         mService.mAppTransition.postAnimationCallback();
         mService.mAppTransition.clear();
 
         mService.mOpeningApps.clear();
         mService.mClosingApps.clear();
+        mService.mUnknownAppVisibilityController.clear();
 
         // This has changed the visibility of windows, so perform
         // a new layout to get them all up-to-date.
@@ -369,11 +377,10 @@
         mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                 true /*updateInputWindows*/);
         mService.mFocusMayChange = false;
-        mService.notifyActivityDrawnForKeyguard();
 
         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
 
-        return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
+        return layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
     }
 
     private AppWindowToken handleOpeningApps(int transit, LayoutParams animLp,
@@ -472,6 +479,26 @@
         }
     }
 
+    private void handleNonAppWindowsInTransition(int transit, int flags) {
+        if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
+            if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
+                    && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
+                Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
+                        (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
+                if (anim != null) {
+                    mService.getDefaultDisplayContentLocked().mWallpaperController
+                            .startWallpaperAnimation(anim);
+                }
+            }
+        }
+        if (transit == TRANSIT_KEYGUARD_GOING_AWAY
+                || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
+            mService.getDefaultDisplayContentLocked().startKeyguardExitOnNonAppWindows(
+                    transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+                    (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
+        }
+    }
+
     private boolean transitionGoodToGo(int appsCount) {
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                 "Checking " + appsCount + " opening apps (frozen="
@@ -529,6 +556,14 @@
                 return false;
             }
 
+            if (!mService.mUnknownAppVisibilityController.allResolved()) {
+                if (DEBUG_APP_TRANSITIONS) {
+                    Slog.v(TAG, "unknownApps is not empty: "
+                            + mService.mUnknownAppVisibilityController.getDebugMessage());
+                }
+                return false;
+            }
+
             // If the wallpaper is visible, we need to check it's ready too.
             boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
                     mWallpaperControllerLocked.wallpaperTransitionReady();
@@ -551,6 +586,7 @@
                 ? null : wallpaperTarget;
         final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
         final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
+        boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                 "New wallpaper target=" + wallpaperTarget
                         + ", oldWallpaper=" + oldWallpaper
@@ -575,6 +611,10 @@
             }
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "New transit: " + AppTransition.appTransitionToString(transit));
+        } else if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
+            transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "New transit: " + AppTransition.appTransitionToString(transit));
         } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
                 && !openingApps.contains(oldWallpaper.mAppToken)
                 && closingApps.contains(oldWallpaper.mAppToken)) {
@@ -595,6 +635,15 @@
         return transit;
     }
 
+    private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
+        for (int i = apps.size() - 1; i >= 0; i--) {
+            if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private void processApplicationsAnimatingInPlace(int transit) {
         if (transit == TRANSIT_TASK_IN_PLACE) {
             // Find the focused window
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 38f25e0..cf1a98a 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,20 +16,11 @@
 
 package com.android.server.wm;
 
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Slog;
-import android.view.DisplayInfo;
-
-import java.io.PrintWriter;
 import java.util.Comparator;
-
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
+
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
@@ -39,6 +30,16 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.DisplayInfo;
+import android.view.animation.Animation;
+
+import java.io.PrintWriter;
+
 /**
  * Container of a set of related windows in the window manager. Often this is an AppWindowToken,
  * which is the handle for an Activity that it uses to display windows. For nested windows, there is
@@ -337,6 +338,16 @@
         }
     }
 
+    /**
+     * Starts {@param anim} on all children.
+     */
+    void startAnimation(Animation anim) {
+        for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
+            final WindowState windowState = mChildren.get(ndx);
+            windowState.mWinAnimator.setAnimation(anim);
+        }
+    }
+
     boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windowList,
             WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible, int dw, int dh,
             int wallpaperAnimLayerAdj) {
@@ -390,10 +401,8 @@
             // is currently on screen, i.e. not hidden by policy.
             int insertionIndex = 0;
             if (visible && wallpaperTarget != null) {
-                final int type = wallpaperTarget.mAttrs.type;
                 final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
-                if (((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || type == TYPE_KEYGUARD_SCRIM)
-                        && !mService.isKeyguardAnimatingIn()) {
+                if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                     insertionIndex = Math.min(windowList.indexOf(wallpaperTarget),
                             findLowestWindowOnScreen(windowList));
                 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
new file mode 100644
index 0000000..77f96ca
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
@@ -0,0 +1,66 @@
+/*
+ * 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 com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
+import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link AppTransition}.
+ *
+ * runtest frameworks-services -c com.android.server.wm.AppTransitionTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class AppTransitionTests {
+
+    private WindowManagerService mWm;
+
+    @Before
+    public void setUp() throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        mWm = TestWindowManagerPolicy.getWindowManagerService(context);
+    }
+
+    @Test
+    public void testKeyguardOverride() throws Exception {
+        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+    }
+
+    @Test
+    public void testForceOverride() throws Exception {
+        mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */,
+                0 /* flags */, true /* forceOverride */);
+        assertEquals(TRANSIT_ACTIVITY_OPEN, mWm.mAppTransition.getAppTransition());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 03cbb43..3e7d272 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -55,7 +55,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
@@ -115,11 +114,6 @@
     }
 
     @Override
-    public boolean canShowDismissingWindowWhileLockedLw() {
-        return false;
-    }
-
-    @Override
     public void setInitialDisplaySize(Display display, int width, int height, int density) {
 
     }
@@ -196,9 +190,6 @@
             case TYPE_INPUT_METHOD_DIALOG:
                 // on-screen keyboards and other such input method user interfaces go here.
                 return 13;
-            case TYPE_KEYGUARD_SCRIM:
-                // the safety window that shows behind keyguard while keyguard is starting
-                return 14;
             case TYPE_STATUS_BAR_SUB_PANEL:
                 return 15;
             case TYPE_STATUS_BAR:
@@ -299,27 +290,16 @@
     }
 
     @Override
-    public boolean isForceHiding(WindowManager.LayoutParams attrs) {
-        return false;
-    }
-
-    @Override
     public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
         return false;
     }
 
     @Override
-    public boolean canBeForceHidden(WindowState win,
-            WindowManager.LayoutParams attrs) {
+    public boolean canBeHiddenByKeyguardLw(WindowState win) {
         return false;
     }
 
     @Override
-    public WindowState getWinShowWhenLockedLw() {
-        return null;
-    }
-
-    @Override
     public View addStartingWindow(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
             int logo, int windowFlags, Configuration overrideConfig) {
@@ -359,13 +339,13 @@
     }
 
     @Override
-    public Animation createForceHideEnterAnimation(boolean onWallpaper,
+    public Animation createHiddenByKeyguardExit(boolean onWallpaper,
             boolean goingToNotificationShade) {
         return null;
     }
 
     @Override
-    public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade) {
+    public Animation createKeyguardWallpaperExit(boolean goingToNotificationShade) {
         return null;
     }
 
@@ -432,8 +412,7 @@
 
     @Override
     public void applyPostLayoutPolicyLw(WindowState win,
-            WindowManager.LayoutParams attrs, WindowState attached) {
-
+            WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget) {
     }
 
     @Override
@@ -523,7 +502,12 @@
     }
 
     @Override
-    public boolean isKeyguardShowingOrOccluded() {
+    public boolean isKeyguardOccluded() {
+        return false;
+    }
+
+    @Override
+    public boolean isKeyguardTrustedLw() {
         return false;
     }
 
@@ -543,16 +527,20 @@
     }
 
     @Override
-    public void notifyActivityDrawnForKeyguardLw() {
-
+    public boolean isKeyguardDrawnLw() {
+        return false;
     }
 
     @Override
-    public boolean isKeyguardDrawnLw() {
+    public boolean isShowingDreamLw() {
         return false;
     }
 
     @Override
+    public void onKeyguardOccludedChangedLw(boolean occluded) {
+    }
+
+    @Override
     public int rotationForOrientationLw(int orientation,
             int lastRotation) {
         return 0;
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
new file mode 100644
index 0000000..36bd13a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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 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;
+import android.platform.test.annotations.Presubmit;
+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;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+
+/**
+ * Test class for {@link AppTransition}.
+ *
+ * runtest frameworks-services -c com.android.server.wm.UnknownVisibilityControllerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class UnknownAppVisibilityControllerTest {
+
+    private WindowManagerService mWm;
+    private @Mock ActivityManagerInternal mAm;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        final Context context = InstrumentationRegistry.getTargetContext();
+        LocalServices.addService(ActivityManagerInternal.class, mAm);
+        doAnswer((InvocationOnMock invocationOnMock) -> {
+            invocationOnMock.getArgumentAt(0, Runnable.class).run();
+            return null;
+        }).when(mAm).notifyKeyguardFlagsChanged(any());
+        mWm = TestWindowManagerPolicy.getWindowManagerService(context);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+    }
+
+    @Test
+    public void testFlow() throws Exception {
+        AppWindowToken token = createAppToken();
+        mWm.mUnknownAppVisibilityController.notifyLaunched(token);
+        mWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
+        mWm.mUnknownAppVisibilityController.notifyRelayouted(token);
+
+        // Make sure our handler processed the message.
+        Thread.sleep(100);
+        assertTrue(mWm.mUnknownAppVisibilityController.allResolved());
+    }
+
+    @Test
+    public void testMultiple() throws Exception {
+        AppWindowToken token1 = createAppToken();
+        AppWindowToken token2 = createAppToken();
+        mWm.mUnknownAppVisibilityController.notifyLaunched(token1);
+        mWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
+        mWm.mUnknownAppVisibilityController.notifyLaunched(token2);
+        mWm.mUnknownAppVisibilityController.notifyRelayouted(token1);
+        mWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token2);
+        mWm.mUnknownAppVisibilityController.notifyRelayouted(token2);
+
+        // Make sure our handler processed the message.
+        Thread.sleep(100);
+        assertTrue(mWm.mUnknownAppVisibilityController.allResolved());
+    }
+
+    @Test
+    public void testClear() throws Exception {
+        AppWindowToken token = createAppToken();
+        mWm.mUnknownAppVisibilityController.notifyLaunched(token);
+        mWm.mUnknownAppVisibilityController.clear();;
+        assertTrue(mWm.mUnknownAppVisibilityController.allResolved());
+    }
+
+    @Test
+    public void testAppRemoved() throws Exception {
+        AppWindowToken token = createAppToken();
+        mWm.mUnknownAppVisibilityController.notifyLaunched(token);
+        mWm.mUnknownAppVisibilityController.appRemoved(token);
+        assertTrue(mWm.mUnknownAppVisibilityController.allResolved());
+    }
+
+    private AppWindowToken createAppToken() {
+        return new AppWindowToken(mWm, mock(IApplicationToken.class), false,
+                mWm.getDefaultDisplayContentLocked());
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 9ec546e..c86f5c3 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -524,10 +524,6 @@
     }
 
     @Override
-    public void setKeyguardAnimatingIn(boolean animating) throws RemoteException {
-    }
-
-    @Override
     public void setSwitchingUser(boolean switching) throws RemoteException {
     }