Merge changes Idfd40156,Ic903fc25

* changes:
  Make user-switch transitions customizable
  Add support for custom user-switch UI
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 3fcc253..cfd016e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -749,6 +749,15 @@
     }
 
     /**
+     * @return Whether guest user is always ephemeral
+     * @hide
+     */
+    public static boolean isGuestUserEphemeral() {
+        return Resources.getSystem()
+                .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
+    }
+
+    /**
      * Returns whether switching users is currently allowed.
      * <p>For instance switching users is not allowed if the current user is in a phone call,
      * or system user hasn't been unlocked yet
@@ -871,6 +880,16 @@
     }
 
     /**
+     * Checks if a user is a guest user.
+     * @return whether user is a guest user.
+     * @hide
+     */
+    public boolean isGuestUser(int id) {
+        UserInfo user = getUserInfo(id);
+        return user != null && user.isGuest();
+    }
+
+    /**
      * Checks if the calling app is running as a guest user.
      * @return whether the caller is a guest user.
      * @hide
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 3d786f1..7de7d8a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -210,6 +210,19 @@
     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);
+
     void closeSystemDialogs(String reason);
 
     // These can only be called with the SET_ANIMATON_SCALE permission.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 87595f9..f1fa216 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1347,6 +1347,15 @@
     public void setCurrentUserLw(int newUserId);
 
     /**
+     * For a given user-switch operation, this will be called once with switching=true before the
+     * user-switch and once with switching=false afterwards (or if the user-switch was cancelled).
+     * This gives the policy a chance to alter its behavior for the duration of a user-switch.
+     *
+     * @param switching true if a user-switch is in progress
+     */
+    void setSwitchingUser(boolean switching);
+
+    /**
      * Print the WindowManagerPolicy's state into the given stream.
      *
      * @param prefix Text to print at the front of each line.
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 83d75fb..02e8af0 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -80,6 +80,7 @@
     void setKeyguardEnabled(boolean enabled);
     void onSystemReady();
     void doKeyguardTimeout(in Bundle options);
+    void setSwitchingUser(boolean switching);
     void setCurrentUser(int userId);
     void onBootCompleted();
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 13e1ba7d..d15b175 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2540,4 +2540,9 @@
 
     <string name="config_networkOverLimitComponent" translatable="false">com.android.systemui/com.android.systemui.net.NetworkOverLimitActivity</string>
     <string name="config_dataUsageSummaryComponent" translatable="false">com.android.settings/com.android.settings.Settings$DataUsageSummaryActivity</string>
+
+    <!-- Flag specifying whether user-switch operations have custom UI. When false, user-switch
+         UI is handled by ActivityManagerService -->
+    <bool name="config_customUserSwitchUi">false</bool>
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index df8d61a..384e9850 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1482,6 +1482,7 @@
   <java-symbol type="bool" name="config_allowAllRotations" />
   <java-symbol type="bool" name="config_annoy_dianne" />
   <java-symbol type="bool" name="config_carDockEnablesAccelerometer" />
+  <java-symbol type="bool" name="config_customUserSwitchUi" />
   <java-symbol type="bool" name="config_deskDockEnablesAccelerometer" />
   <java-symbol type="bool" name="config_disableMenuKeyInLockScreen" />
   <java-symbol type="bool" name="config_enableCarDockHomeLaunch" />
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1b83ccd..daa1d88 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1185,9 +1185,6 @@
      * Handle {@link #MSG_USER_SWITCHING}
      */
     protected void handleUserSwitching(int userId, IRemoteCallback reply) {
-        mSwitchingUser = true;
-        updateFingerprintListeningState();
-
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -1204,9 +1201,6 @@
      * Handle {@link #MSG_USER_SWITCH_COMPLETE}
      */
     protected void handleUserSwitchComplete(int userId) {
-        mSwitchingUser = false;
-        updateFingerprintListeningState();
-
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -1511,6 +1505,15 @@
         sendUpdates(callback);
     }
 
+    public boolean isSwitchingUser() {
+        return mSwitchingUser;
+    }
+
+    public void setSwitchingUser(boolean switching) {
+        mSwitchingUser = switching;
+        updateFingerprintListeningState();
+    }
+
     private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
         // Notify listener of the current state
         callback.onRefreshBatteryInfo(mBatteryStatus);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 84901ee..7ec6a03 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -178,6 +178,12 @@
         }
 
         @Override // Binder interface
+        public void setSwitchingUser(boolean switching) {
+            checkPermission();
+            mKeyguardViewMediator.setSwitchingUser(switching);
+        }
+
+        @Override // Binder interface
         public void setCurrentUser(int userId) {
             checkPermission();
             mKeyguardViewMediator.setCurrentUser(userId);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0dc5f74..8b592c2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -191,13 +191,18 @@
      */
     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.
+     */
+    public static final String OPTION_FORCE_SHOW = "force_show";
+
     /** The stream type that the lock sounds are tied to. */
     private int mUiSoundsStreamType;
 
     private AlarmManager mAlarmManager;
     private AudioManager mAudioManager;
     private StatusBarManager mStatusBarManager;
-    private boolean mSwitchingUser;
 
     private boolean mSystemReady;
     private boolean mBootCompleted;
@@ -349,7 +354,6 @@
             // We need to force a reset of the views, since lockNow (called by
             // ActivityManagerService) will not reconstruct the keyguard if it is already showing.
             synchronized (KeyguardViewMediator.this) {
-                mSwitchingUser = true;
                 resetKeyguardDonePendingLocked();
                 resetStateLocked();
                 adjustStatusBarLocked();
@@ -358,7 +362,6 @@
 
         @Override
         public void onUserSwitchComplete(int userId) {
-            mSwitchingUser = false;
             if (userId != UserHandle.USER_SYSTEM) {
                 UserInfo info = UserManager.get(mContext).getUserInfo(userId);
                 if (info != null && (info.isGuest() || info.isDemo())) {
@@ -1243,8 +1246,9 @@
                 return;
             }
 
+            boolean forceShow = options != null && options.getBoolean(OPTION_FORCE_SHOW, false);
             if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
-                    && !lockedOrMissing) {
+                    && !lockedOrMissing && !forceShow) {
                 if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
                 return;
             }
@@ -1364,8 +1368,16 @@
     }
 
     public boolean isSecure() {
-        return mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())
-            || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure();
+        return isSecure(KeyguardUpdateMonitor.getCurrentUser());
+    }
+
+    public boolean isSecure(int userId) {
+        return mLockPatternUtils.isSecure(userId)
+                || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure();
+    }
+
+    public void setSwitchingUser(boolean switching) {
+        KeyguardUpdateMonitor.getInstance(mContext).setSwitchingUser(switching);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index bc05ff1..706abdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -97,7 +97,7 @@
 
         final int activeUserId = ActivityManager.getCurrentUser();
         final boolean allowDismissKeyguard =
-                !(UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM)
+                !UserManager.isSplitSystemUser()
                 && activeUserId == keyguardUserId;
         // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
         // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 586741e..4638c85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -129,7 +129,9 @@
 
     public void setCurrentUser(int user) {
         if (user != mCurrentUserId) {
-            mCached = false;
+            if (mSelectedUser == null || user != mSelectedUser.getIdentifier()) {
+                mCached = false;
+            }
             mCurrentUserId = user;
         }
     }
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 6460b5f..e95cc6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -892,8 +892,7 @@
         mLightStatusBarController = new LightStatusBarController(mIconController,
                 mBatteryController);
         mKeyguardMonitor = new KeyguardMonitor(mContext);
-        mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
-                mHandler, this);
+            mUserSwitcherController = createUserSwitcherController();
         if (UserManager.get(mContext).isUserSwitcherEnabled()) {
             createUserSwitcher();
         }
@@ -1096,6 +1095,10 @@
                 mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
     }
 
+    protected UserSwitcherController createUserSwitcherController() {
+        return new UserSwitcherController(mContext, mKeyguardMonitor, mHandler, this);
+    }
+
     protected void inflateStatusBarWindow(Context context) {
         mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                 R.layout.super_status_bar, null);
@@ -3621,6 +3624,10 @@
         resetUserSetupObserver();
         setControllerUsers();
         clearCurrentMediaNotification();
+        setLockscreenUser(newUserId);
+    }
+
+    protected void setLockscreenUser(int newUserId) {
         mLockscreenWallpaper.setCurrentUser(newUserId);
         mScrimController.setCurrentUser(newUserId);
         updateMediaMetaData(true, false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index c883bba..c3becb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -50,6 +50,7 @@
 
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.util.UserIcons;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.R;
@@ -86,13 +87,13 @@
 
     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
 
-    private final Context mContext;
-    private final UserManager mUserManager;
+    protected final Context mContext;
+    protected final UserManager mUserManager;
     private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
     private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
             = new GuestResumeSessionReceiver();
     private final KeyguardMonitor mKeyguardMonitor;
-    private final Handler mHandler;
+    protected final Handler mHandler;
     private final ActivityStarter mActivityStarter;
 
     private ArrayList<UserRecord> mUsers = new ArrayList<>();
@@ -363,13 +364,23 @@
             id = record.info.id;
         }
 
-        if (ActivityManager.getCurrentUser() == id) {
+        int currUserId = ActivityManager.getCurrentUser();
+        if (currUserId == id) {
             if (record.isGuest) {
                 showExitGuestDialog(id);
             }
             return;
         }
 
+        if (UserManager.isGuestUserEphemeral()) {
+            // If switching from guest, we want to bring up the guest exit dialog instead of switching
+            UserInfo currUserInfo = mUserManager.getUserInfo(currUserId);
+            if (currUserInfo != null && currUserInfo.isGuest()) {
+                showExitGuestDialog(currUserId, record.resolveId());
+                return;
+            }
+        }
+
         switchToUserId(id);
     }
 
@@ -398,7 +409,7 @@
         return count;
     }
 
-    private void switchToUserId(int id) {
+    protected void switchToUserId(int id) {
         try {
             pauseRefreshUsers();
             ActivityManagerNative.getDefault().switchUser(id);
@@ -408,10 +419,21 @@
     }
 
     private void showExitGuestDialog(int id) {
+        int newId = UserHandle.USER_SYSTEM;
+        if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) {
+            UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
+            if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) {
+                newId = info.id;
+            }
+        }
+        showExitGuestDialog(id, newId);
+    }
+
+    protected void showExitGuestDialog(int id, int targetId) {
         if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
             mExitGuestDialog.cancel();
         }
-        mExitGuestDialog = new ExitGuestDialog(mContext, id);
+        mExitGuestDialog = new ExitGuestDialog(mContext, id, targetId);
         mExitGuestDialog.show();
     }
 
@@ -423,15 +445,8 @@
         mAddUserDialog.show();
     }
 
-    private void exitGuest(int id) {
-        int newId = UserHandle.USER_SYSTEM;
-        if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) {
-            UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
-            if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) {
-                newId = info.id;
-            }
-        }
-        switchToUserId(newId);
+    protected void exitGuest(int id, int targetId) {
+        switchToUserId(targetId);
         mUserManager.removeUser(id);
     }
 
@@ -830,8 +845,9 @@
             DialogInterface.OnClickListener {
 
         private final int mGuestId;
+        private final int mTargetId;
 
-        public ExitGuestDialog(Context context, int guestId) {
+        public ExitGuestDialog(Context context, int guestId, int targetId) {
             super(context);
             setTitle(R.string.guest_exit_guest_dialog_title);
             setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
@@ -841,6 +857,7 @@
                     context.getString(R.string.guest_exit_guest_dialog_remove), this);
             setCanceledOnTouchOutside(false);
             mGuestId = guestId;
+            mTargetId = targetId;
         }
 
         @Override
@@ -849,7 +866,7 @@
                 cancel();
             } else {
                 dismiss();
-                exitGuest(mGuestId);
+                exitGuest(mGuestId, mTargetId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index dbff4be..908b8e0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1533,6 +1533,7 @@
     static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69;
     static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 70;
     static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 71;
+    static final int START_USER_SWITCH_FG_MSG = 712;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1954,6 +1955,10 @@
                 thread.start();
                 break;
             }
+            case START_USER_SWITCH_FG_MSG: {
+                mUserController.startUserInForeground(msg.arg1);
+                break;
+            }
             case REPORT_USER_SWITCH_MSG: {
                 mUserController.dispatchUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
                 break;
@@ -13110,6 +13115,8 @@
                     com.android.internal.R.string.config_defaultPictureInPictureBounds));
             mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
                     com.android.internal.R.string.config_appsNotReportingCrashes));
+            mUserController.mUserSwitchUiEnabled = !res.getBoolean(
+                    com.android.internal.R.bool.config_customUserSwitchUi);
             if ((mConfiguration.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
                 mFullscreenThumbnailScale = (float) res
                     .getInteger(com.android.internal.R.integer.thumbnail_width_tv) /
@@ -21526,11 +21533,10 @@
     @Override
     public boolean switchUser(final int targetUserId) {
         enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId);
-        UserInfo currentUserInfo;
+        int currentUserId;
         UserInfo targetUserInfo;
         synchronized (this) {
-            int currentUserId = mUserController.getCurrentUserIdLocked();
-            currentUserInfo = mUserController.getUserInfo(currentUserId);
+            currentUserId = mUserController.getCurrentUserIdLocked();
             targetUserInfo = mUserController.getUserInfo(targetUserId);
             if (targetUserInfo == null) {
                 Slog.w(TAG, "No user info for user #" + targetUserId);
@@ -21551,9 +21557,17 @@
             }
             mUserController.setTargetUserIdLocked(targetUserId);
         }
-        Pair<UserInfo, UserInfo> userNames = new Pair<>(currentUserInfo, targetUserInfo);
-        mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG);
-        mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_UI_MSG, userNames));
+        if (mUserController.mUserSwitchUiEnabled) {
+            UserInfo currentUserInfo = mUserController.getUserInfo(currentUserId);
+            Pair<UserInfo, UserInfo> userNames = new Pair<>(currentUserInfo, targetUserInfo);
+            mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG);
+            mUiHandler.sendMessage(mHandler.obtainMessage(
+                    START_USER_SWITCH_UI_MSG, userNames));
+        } else {
+            mHandler.removeMessages(START_USER_SWITCH_FG_MSG);
+            mHandler.sendMessage(mHandler.obtainMessage(
+                    START_USER_SWITCH_FG_MSG, targetUserId, 0));
+        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a5245a2..35b7a43 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -161,6 +161,8 @@
     private final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
             = new RemoteCallbackList<>();
 
+    boolean mUserSwitchUiEnabled;
+
     /**
      * Currently active user switch callbacks.
      */
@@ -797,7 +799,7 @@
                     return false;
                 }
 
-                if (foreground) {
+                if (foreground && mUserSwitchUiEnabled) {
                     mInjector.getWindowManager().startFreezingScreen(
                             R.anim.screen_user_exit, R.anim.screen_user_enter);
                 }
@@ -827,7 +829,10 @@
                     mInjector.getWindowManager().setCurrentUser(userId, mCurrentProfileIds);
                     // Once the internal notion of the active user has switched, we lock the device
                     // with the option to show the user switcher on the keyguard.
-                    mInjector.getWindowManager().lockNow(null);
+                    if (mUserSwitchUiEnabled) {
+                        mInjector.getWindowManager().setSwitchingUser(true);
+                        mInjector.getWindowManager().lockNow(null);
+                    }
                 } else {
                     final Integer currentUserIdInt = mCurrentUserId;
                     updateCurrentProfileIdsLocked();
@@ -920,10 +925,11 @@
     /**
      * Start user, if its not already running, and bring it to foreground.
      */
-    boolean startUserInForeground(final int userId, Dialog dlg) {
-        boolean result = startUser(userId, /* foreground */ true);
-        dlg.dismiss();
-        return result;
+    void startUserInForeground(final int targetUserId) {
+        boolean success = startUser(targetUserId, /* foreground */ true);
+        if (!success) {
+            mInjector.getWindowManager().setSwitchingUser(false);
+        }
     }
 
     boolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) {
@@ -1036,6 +1042,7 @@
 
     /** Called on handler thread */
     void dispatchUserSwitchComplete(int userId) {
+        mInjector.getWindowManager().setSwitchingUser(false);
         final int observerCount = mUserSwitchObservers.beginBroadcast();
         for (int i = 0; i < observerCount; i++) {
             try {
@@ -1126,8 +1133,10 @@
 
     void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
         Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId);
-        synchronized (mLock) {
-            mInjector.getWindowManager().stopFreezingScreen();
+        if (mUserSwitchUiEnabled) {
+            synchronized (mLock) {
+                mInjector.getWindowManager().stopFreezingScreen();
+            }
         }
         uss.switching = false;
         mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 7022856..3e6934f 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -112,7 +112,8 @@
     void startUser() {
         synchronized (this) {
             if (!mStartedUser) {
-                mService.mUserController.startUserInForeground(mUserId, this);
+                mService.mUserController.startUserInForeground(mUserId);
+                dismiss();
                 mStartedUser = true;
                 final View decorView = getWindow().getDecorView();
                 if (decorView != null) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5385a50..60fbabf 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -7783,6 +7783,11 @@
     }
 
     @Override
+    public void setSwitchingUser(boolean switching) {
+        mKeyguardDelegate.setSwitchingUser(switching);
+    }
+
+    @Override
     public boolean canMagnifyWindow(int windowType) {
         switch (windowType) {
             case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
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 0c76aeb..ef6d92f 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -346,6 +346,12 @@
         mKeyguardState.currentUser = newUserId;
     }
 
+    public void setSwitchingUser(boolean switching) {
+        if (mKeyguardService != null) {
+            mKeyguardService.setSwitchingUser(switching);
+        }
+    }
+
     public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
         if (mKeyguardService != null) {
             mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration);
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 bea3167..0274cb5 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -189,6 +189,15 @@
     }
 
     @Override // Binder interface
+    public void setSwitchingUser(boolean switching) {
+        try {
+            mService.setSwitchingUser(switching);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
     public void setCurrentUser(int userId) {
         mKeyguardStateMonitor.setCurrentUser(userId);
         try {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 1010400..6515fbd 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -104,6 +104,7 @@
 
     boolean mKeyguardGoingAway;
     int mKeyguardGoingAwayFlags;
+    boolean mKeyguardAnimatingIn;
 
     /** Use one animation for all entering activities after keyguard is dismissed. */
     Animation mPostKeyguardExitAnimation;
@@ -241,7 +242,8 @@
 
         // Only hide windows if the keyguard is active and not animating away.
         boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded()
-                && mForceHiding != KEYGUARD_ANIMATING_OUT;
+                && mForceHiding != KEYGUARD_ANIMATING_OUT
+                && !mKeyguardAnimatingIn;
         boolean hideDockDivider = win.mAttrs.type == TYPE_DOCK_DIVIDER
                 && win.getDisplayContent().getDockedStackLocked() == null;
         return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY)
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c4196bb..8f7896e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -581,6 +581,7 @@
     int mLastDisplayFreezeDuration = 0;
     Object mLastFinishedFreezeSource = null;
     boolean mWaitingForConfig = false;
+    boolean mSwitchingUser = false;
 
     final static int WINDOWS_FREEZING_SCREENS_NONE = 0;
     final static int WINDOWS_FREEZING_SCREENS_ACTIVE = 1;
@@ -4508,6 +4509,35 @@
         }
     }
 
+    @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;
+        }
+    }
+
+    @Override
+    public void setSwitchingUser(boolean switching) {
+        if (!checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                "setSwitchingUser()")) {
+            throw new SecurityException("Requires INTERACT_ACROSS_USERS_FULL permission");
+        }
+        mPolicy.setSwitchingUser(switching);
+        synchronized (mWindowMap) {
+            mSwitchingUser = switching;
+        }
+    }
+
     void showGlobalActions() {
         mPolicy.showGlobalActions();
     }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index b54cbe1..00e71f2 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -623,12 +623,14 @@
             }
 
             // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
-            // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
+            // layer. For keyguard over wallpaper put the wallpaper under the keyguard unless
+            // the keyguard is still animating in.
             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) {
+                if (((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || type == TYPE_KEYGUARD_SCRIM)
+                        && !mService.isKeyguardAnimatingIn()) {
                     insertionIndex = windowList.indexOf(wallpaperTarget);
                 }
             }
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 aa97b35..8c6b007 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -663,6 +663,11 @@
     }
 
     @Override
+    public void setSwitchingUser(boolean switching) {
+
+    }
+
+    @Override
     public void dump(String prefix, PrintWriter writer, String[] args) {
 
     }