resolve merge conflicts of 0483184 to master

Change-Id: I8466c8d56b5685705591dad7cfb7d439b6dee3d7
diff --git a/Android.mk b/Android.mk
index 9513c3e..584e4d1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -343,6 +343,7 @@
 	core/java/com/android/internal/view/IInputMethodManager.aidl \
 	core/java/com/android/internal/view/IInputMethodSession.aidl \
 	core/java/com/android/internal/view/IInputSessionCallback.aidl \
+	core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl \
 	core/java/com/android/internal/widget/ILockSettings.aidl \
 	core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
 	core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index a0762b9..9cd70e6 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -72,7 +72,7 @@
      * information about that wallpaper.  Otherwise, if it is a static image,
      * simply return null.
      */
-    WallpaperInfo getWallpaperInfo();
+    WallpaperInfo getWallpaperInfo(int userId);
 
     /**
      * Clear the system wallpaper.
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 7f467f0..79f2a1e 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -51,6 +51,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.WindowManagerGlobal;
@@ -783,7 +784,7 @@
                 Log.w(TAG, "WallpaperService not running");
                 throw new RuntimeException(new DeadSystemException());
             } else {
-                return sGlobals.mService.getWallpaperInfo();
+                return sGlobals.mService.getWallpaperInfo(UserHandle.myUserId());
             }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl b/core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl
new file mode 100644
index 0000000..79717cf
--- /dev/null
+++ b/core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.internal.widget;
+
+/** {@hide} */
+oneway interface ICheckCredentialProgressCallback {
+    void onCredentialVerified();
+}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 05b839d..9fa558e 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.widget;
 
 import android.app.trust.IStrongAuthTracker;
+import com.android.internal.widget.ICheckCredentialProgressCallback;
 import com.android.internal.widget.VerifyCredentialResponse;
 
 /** {@hide} */
@@ -29,10 +30,12 @@
     String getString(in String key, in String defaultValue, in int userId);
     void setLockPattern(in String pattern, in String savedPattern, int userId);
     void resetKeyStore(int userId);
-    VerifyCredentialResponse checkPattern(in String pattern, int userId);
+    VerifyCredentialResponse checkPattern(in String pattern, int userId,
+            in ICheckCredentialProgressCallback progressCallback);
     VerifyCredentialResponse verifyPattern(in String pattern, long challenge, int userId);
     void setLockPassword(in String password, in String savedPassword, int userId);
-    VerifyCredentialResponse checkPassword(in String password, int userId);
+    VerifyCredentialResponse checkPassword(in String password, int userId,
+            in ICheckCredentialProgressCallback progressCallback);
     VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId);
     VerifyCredentialResponse verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, int userId);
     boolean checkVoldPassword(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java
index 713f56f..df9b0dd 100644
--- a/core/java/com/android/internal/widget/LockPatternChecker.java
+++ b/core/java/com/android/internal/widget/LockPatternChecker.java
@@ -14,6 +14,13 @@
      * Interface for a callback to be invoked after security check.
      */
     public interface OnCheckCallback {
+
+        /**
+         * Invoked as soon as possible we know that the credentials match. This will be called
+         * earlier than {@link #onChecked} but only if the credentials match.
+         */
+        default void onEarlyMatched() {}
+
         /**
          * Invoked when a security check is finished.
          *
@@ -92,7 +99,7 @@
             @Override
             protected Boolean doInBackground(Void... args) {
                 try {
-                    return utils.checkPattern(pattern, userId);
+                    return utils.checkPattern(pattern, userId, callback::onEarlyMatched);
                 } catch (RequestThrottledException ex) {
                     mThrottleTimeout = ex.getTimeoutMs();
                     return false;
@@ -199,7 +206,7 @@
             @Override
             protected Boolean doInBackground(Void... args) {
                 try {
-                    return utils.checkPassword(password, userId);
+                    return utils.checkPassword(password, userId, callback::onEarlyMatched);
                 } catch (RequestThrottledException ex) {
                     mThrottleTimeout = ex.getTimeoutMs();
                     return false;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b7ce7d7..04654f3 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -17,6 +17,7 @@
 package com.android.internal.widget;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.IStrongAuthTracker;
 import android.app.trust.TrustManager;
@@ -32,7 +33,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.IMountService;
@@ -149,6 +149,7 @@
     private DevicePolicyManager mDevicePolicyManager;
     private ILockSettings mLockSettingsService;
     private UserManager mUserManager;
+    private final Handler mHandler = new Handler();
 
     /**
      * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
@@ -341,10 +342,23 @@
      */
     public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
             throws RequestThrottledException {
+        return checkPattern(pattern, userId, null /* progressCallback */);
+    }
+
+    /**
+     * Check to see if a pattern matches the saved pattern.  If no pattern exists,
+     * always returns true.
+     * @param pattern The pattern to check.
+     * @return Whether the pattern matches the stored one.
+     */
+    public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId,
+            @Nullable CheckCredentialProgressCallback progressCallback)
+            throws RequestThrottledException {
         throwIfCalledOnMainThread();
         try {
             VerifyCredentialResponse response =
-                    getLockSettings().checkPattern(patternToString(pattern), userId);
+                    getLockSettings().checkPattern(patternToString(pattern), userId,
+                            wrapCallback(progressCallback));
 
             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
                 return true;
@@ -423,10 +437,22 @@
      * @return Whether the password matches the stored one.
      */
     public boolean checkPassword(String password, int userId) throws RequestThrottledException {
+        return checkPassword(password, userId, null /* progressCallback */);
+    }
+
+    /**
+     * Check to see if a password matches the saved password.  If no password exists,
+     * always returns true.
+     * @param password The password to check.
+     * @return Whether the password matches the stored one.
+     */
+    public boolean checkPassword(String password, int userId,
+            @Nullable CheckCredentialProgressCallback progressCallback)
+            throws RequestThrottledException {
         throwIfCalledOnMainThread();
         try {
             VerifyCredentialResponse response =
-                    getLockSettings().checkPassword(password, userId);
+                    getLockSettings().checkPassword(password, userId, wrapCallback(progressCallback));
             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
                 return true;
             } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
@@ -1481,6 +1507,33 @@
         return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0;
     }
 
+    private ICheckCredentialProgressCallback wrapCallback(
+            final CheckCredentialProgressCallback callback) {
+        if (callback == null) {
+            return null;
+        } else {
+            return new ICheckCredentialProgressCallback.Stub() {
+
+                @Override
+                public void onCredentialVerified() throws RemoteException {
+                    mHandler.post(callback::onEarlyMatched);
+                }
+            };
+        }
+    }
+
+    /**
+     * Callback to be notified about progress when checking credentials.
+     */
+    public interface CheckCredentialProgressCallback {
+
+        /**
+         * Called as soon as possible when we know that the credentials match but the user hasn't
+         * been fully unlocked.
+         */
+        void onEarlyMatched();
+    }
+
     /**
      * Tracks the global strong authentication state.
      */
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index cca9163..766eab7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -137,12 +137,21 @@
                 entry,
                 userId,
                 new LockPatternChecker.OnCheckCallback() {
+
+                    @Override
+                    public void onEarlyMatched() {
+                        onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
+                                true /* isValidPassword */);
+                    }
+
                     @Override
                     public void onChecked(boolean matched, int timeoutMs) {
                         setPasswordEntryInputEnabled(true);
                         mPendingLockCheck = null;
-                        onPasswordChecked(userId, matched, timeoutMs,
-                                true /* isValidPassword */);
+                        if (!matched) {
+                            onPasswordChecked(userId, false /* matched */, timeoutMs,
+                                    true /* isValidPassword */);
+                        }
                     }
                 });
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index 7ea767c..4f5152a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -36,6 +36,7 @@
 
     private final AppearAnimationUtils mAppearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtils;
+    private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
     private ViewGroup mContainer;
     private ViewGroup mRow0;
     private ViewGroup mRow1;
@@ -44,6 +45,7 @@
     private View mDivider;
     private int mDisappearYTranslation;
     private View[][] mViews;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     public KeyguardPINView(Context context) {
         this(context, null);
@@ -56,8 +58,14 @@
                 125, 0.6f /* translationScale */,
                 0.45f /* delayScale */, AnimationUtils.loadInterpolator(
                         mContext, android.R.interpolator.fast_out_linear_in));
+        mDisappearAnimationUtilsLocked = new DisappearAnimationUtils(context,
+                (long) (125 * KeyguardPatternView.DISAPPEAR_MULTIPLIER_LOCKED),
+                0.6f /* translationScale */,
+                0.45f /* delayScale */, AnimationUtils.loadInterpolator(
+                        mContext, android.R.interpolator.fast_out_linear_in));
         mDisappearYTranslation = getResources().getDimensionPixelSize(
                 R.dimen.disappear_y_translation);
+        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
     }
 
     @Override
@@ -136,7 +144,10 @@
         setTranslationY(0);
         AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
                 mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator());
-        mDisappearAnimationUtils.startAnimation2d(mViews,
+        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
+                ? mDisappearAnimationUtils
+                : mDisappearAnimationUtilsLocked;
+        disappearAnimationUtils.startAnimation2d(mViews,
                 new Runnable() {
                     @Override
                     public void run() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 23015b5..69eb538 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -55,9 +55,13 @@
     // how many cells the user has to cross before we poke the wakelock
     private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
 
+    // How much we scale up the duration of the disappear animation when the current user is locked
+    public static final float DISAPPEAR_MULTIPLIER_LOCKED = 1.5f;
+
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final AppearAnimationUtils mAppearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtils;
+    private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
 
     private CountDownTimer mCountdownTimer = null;
     private LockPatternUtils mLockPatternUtils;
@@ -109,6 +113,10 @@
                 125, 1.2f /* translationScale */,
                 0.6f /* delayScale */, AnimationUtils.loadInterpolator(
                         mContext, android.R.interpolator.fast_out_linear_in));
+        mDisappearAnimationUtilsLocked = new DisappearAnimationUtils(context,
+                (long) (125 * DISAPPEAR_MULTIPLIER_LOCKED), 1.2f /* translationScale */,
+                0.6f /* delayScale */, AnimationUtils.loadInterpolator(
+                mContext, android.R.interpolator.fast_out_linear_in));
         mDisappearYTranslation = getResources().getDimensionPixelSize(
                 R.dimen.disappear_y_translation);
     }
@@ -239,11 +247,21 @@
                     pattern,
                     userId,
                     new LockPatternChecker.OnCheckCallback() {
+
+                        @Override
+                        public void onEarlyMatched() {
+                            onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,
+                                    true /* isValidPattern */);
+                        }
+
                         @Override
                         public void onChecked(boolean matched, int timeoutMs) {
                             mLockPatternView.enableInput();
                             mPendingLockCheck = null;
-                            onPatternChecked(userId, matched, timeoutMs, true);
+                            if (!matched) {
+                                onPatternChecked(userId, false /* matched */, timeoutMs,
+                                        true /* isValidPattern */);
+                            }
                         }
                     });
             if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
@@ -390,25 +408,30 @@
 
     @Override
     public boolean startDisappearAnimation(final Runnable finishRunnable) {
+        float durationMultiplier = mKeyguardUpdateMonitor.isUserUnlocked()
+                ? 1f
+                : DISAPPEAR_MULTIPLIER_LOCKED;
         mLockPatternView.clearPattern();
         enableClipping(false);
         setTranslationY(0);
-        AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 300 /* duration */,
+        AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */,
+                (long) (300 * durationMultiplier),
                 -mDisappearAnimationUtils.getStartTranslation(),
                 mDisappearAnimationUtils.getInterpolator());
-        mDisappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        enableClipping(true);
-                        if (finishRunnable != null) {
-                            finishRunnable.run();
-                        }
+
+        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
+                ? mDisappearAnimationUtils
+                : mDisappearAnimationUtilsLocked;
+        disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
+                () -> {
+                    enableClipping(true);
+                    if (finishRunnable != null) {
+                        finishRunnable.run();
                     }
                 }, KeyguardPatternView.this);
         if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
             mDisappearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0,
-                    200,
+                    (long) (200 * durationMultiplier),
                     - mDisappearAnimationUtils.getStartTranslation() * 3,
                     false /* appearing */,
                     mDisappearAnimationUtils.getInterpolator(),
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 94d9550..dec1fd2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -16,6 +16,16 @@
 
 package com.android.keyguard;
 
+import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
+import static android.os.BatteryManager.BATTERY_STATUS_FULL;
+import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
+import static android.os.BatteryManager.EXTRA_HEALTH;
+import static android.os.BatteryManager.EXTRA_LEVEL;
+import static android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT;
+import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
+import static android.os.BatteryManager.EXTRA_PLUGGED;
+import static android.os.BatteryManager.EXTRA_STATUS;
+
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
@@ -29,7 +39,6 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
-import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -42,6 +51,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
@@ -69,16 +79,6 @@
 import java.util.List;
 import java.util.Map.Entry;
 
-import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
-import static android.os.BatteryManager.BATTERY_STATUS_FULL;
-import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
-import static android.os.BatteryManager.EXTRA_HEALTH;
-import static android.os.BatteryManager.EXTRA_LEVEL;
-import static android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT;
-import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
-import static android.os.BatteryManager.EXTRA_PLUGGED;
-import static android.os.BatteryManager.EXTRA_STATUS;
-
 /**
  * Watches for updates that may be interesting to the keyguard, and provides
  * the up to date information as well as a registration for callbacks that care
@@ -176,6 +176,7 @@
     private boolean mGoingToSleep;
     private boolean mBouncer;
     private boolean mBootCompleted;
+    private boolean mUserUnlocked;
 
     // Device provisioning state
     private boolean mDeviceProvisioned;
@@ -202,6 +203,7 @@
     private AlarmManager mAlarmManager;
     private List<SubscriptionInfo> mSubscriptionInfo;
     private TrustManager mTrustManager;
+    private UserManager mUserManager;
     private int mFingerprintRunningState = FINGERPRINT_STATE_STOPPED;
 
     private final Handler mHandler = new Handler() {
@@ -554,6 +556,10 @@
                 && !hasFingerprintUnlockTimedOut(sCurrentUser);
     }
 
+    public boolean isUserUnlocked() {
+        return mUserUnlocked;
+    }
+
     public StrongAuthTracker getStrongAuthTracker() {
         return mStrongAuthTracker;
     }
@@ -1058,6 +1064,8 @@
         if (mFpm != null) {
             mFpm.addLockoutResetCallback(mLockoutResetCallback);
         }
+
+        mUserManager = context.getSystemService(UserManager.class);
     }
 
     private void updateFingerprintListeningState() {
@@ -1390,6 +1398,7 @@
     private void handleKeyguardReset() {
         if (DEBUG) Log.d(TAG, "handleKeyguardReset");
         updateFingerprintListeningState();
+        mUserUnlocked = mUserManager.isUserUnlocked(getCurrentUser());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index b5561bd..21f68f5 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.QSTileHost;
@@ -94,7 +95,7 @@
     }
 
     public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
-            View headsUpScrim) {
+            View headsUpScrim, LockscreenWallpaper lockscreenWallpaper) {
         return new ScrimController(scrimBehind, scrimInFront, headsUpScrim);
     }
 
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 e109812..bc05ff1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -234,7 +234,6 @@
         mKeyguardView.setViewMediatorCallback(mCallback);
         mContainer.addView(mRoot, mContainer.getChildCount());
         mRoot.setVisibility(View.INVISIBLE);
-        mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
     }
 
     protected void removeView() {
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 f233e50..d969451 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -789,11 +789,15 @@
         mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
         mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
 
+        if (ENABLE_LOCKSCREEN_WALLPAPER) {
+            mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
+        }
+
         ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
         ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
         View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
         mScrimController = SystemUIFactory.getInstance().createScrimController(
-                scrimBehind, scrimInFront, headsUpScrim);
+                scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper);
         if (mScrimSrcModeEnabled) {
             Runnable runnable = new Runnable() {
                 @Override
@@ -823,10 +827,6 @@
                 mKeyguardBottomArea.getLockIcon());
         mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
 
-        if (ENABLE_LOCKSCREEN_WALLPAPER) {
-            mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
-        }
-
         // set the initial view visibility
         setAreThereNotifications();
 
@@ -3522,6 +3522,7 @@
         setControllerUsers();
         clearCurrentMediaNotification();
         mLockscreenWallpaper.setCurrentUser(newUserId);
+        mScrimController.setCurrentUser(newUserId);
         updateMediaMetaData(true, false);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 94ede0c..40abaa4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -31,6 +31,7 @@
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
@@ -47,10 +48,13 @@
     public static final long ANIMATION_DURATION = 220;
     public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
             = new PathInterpolator(0f, 0, 0.7f, 1f);
+    public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED
+            = new PathInterpolator(0.3f, 0f, 0.8f, 1f);
     private static final float SCRIM_BEHIND_ALPHA = 0.62f;
-    private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f;
-    private static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
+    protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f;
+    protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
     private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
+    private static final float SCRIM_IN_FRONT_ALPHA_LOCKED = 0.85f;
     private static final int TAG_KEY_ANIM = R.id.scrim;
     private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target;
     private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
@@ -60,6 +64,7 @@
     private final ScrimView mScrimInFront;
     private final UnlockMethodCache mUnlockMethodCache;
     private final View mHeadsUpScrim;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     protected float mScrimBehindAlpha = SCRIM_BEHIND_ALPHA;
     protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
@@ -101,6 +106,7 @@
         mHeadsUpScrim = headsUpScrim;
         final Context context = scrimBehind.getContext();
         mUnlockMethodCache = UnlockMethodCache.getInstance(context);
+        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
         updateHeadsUpScrim(false);
     }
 
@@ -109,6 +115,13 @@
         scheduleUpdate();
     }
 
+    protected void setScrimBehindValues(float scrimBehindAlphaKeyguard,
+            float scrimBehindAlphaUnlocking) {
+        mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
+        mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking;
+        scheduleUpdate();
+    }
+
     public void onTrackingStarted() {
         mExpanding = true;
         mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
@@ -151,11 +164,19 @@
         mAnimateChange = true;
         mSkipFirstFrame = skipFirstFrame;
         mOnAnimationFinished = onAnimationFinished;
-        scheduleUpdate();
 
-        // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
-        // the changes we just scheduled.
-        onPreDraw();
+        if (mKeyguardUpdateMonitor.isUserUnlocked()) {
+            scheduleUpdate();
+
+            // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
+            // the changes we just scheduled.
+            onPreDraw();
+        } else {
+
+            // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
+            // with too many things in this case, in order to not skip the initial frames.
+            mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
+        }
     }
 
     public void abortKeyguardFadingOut() {
@@ -200,6 +221,12 @@
         return mDozeInFrontAlpha;
     }
 
+    private float getScrimInFrontAlpha() {
+        return mKeyguardUpdateMonitor.isUserUnlocked()
+                ? SCRIM_IN_FRONT_ALPHA
+                : SCRIM_IN_FRONT_ALPHA_LOCKED;
+    }
+
     protected void scheduleUpdate() {
         if (mUpdatePending) return;
 
@@ -239,10 +266,10 @@
             float fraction = 1 - behindFraction;
             fraction = (float) Math.pow(fraction, 0.8f);
             behindFraction = (float) Math.pow(behindFraction, 0.8f);
-            setScrimInFrontColor(fraction * SCRIM_IN_FRONT_ALPHA);
+            setScrimInFrontColor(fraction * getScrimInFrontAlpha());
             setScrimBehindColor(behindFraction * mScrimBehindAlphaKeyguard);
         } else if (mBouncerShowing && !mBouncerIsKeyguard) {
-            setScrimInFrontColor(SCRIM_IN_FRONT_ALPHA);
+            setScrimInFrontColor(getScrimInFrontAlpha());
             setScrimBehindColor(0f);
         } else if (mBouncerShowing) {
             setScrimInFrontColor(0f);
@@ -365,7 +392,13 @@
     }
 
     protected Interpolator getInterpolator() {
-        return mAnimateKeyguardFadingOut ? KEYGUARD_FADE_OUT_INTERPOLATOR : mInterpolator;
+        if (mAnimateKeyguardFadingOut && !mKeyguardUpdateMonitor.isUserUnlocked()) {
+            return KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED;
+        } else if (mAnimateKeyguardFadingOut) {
+            return KEYGUARD_FADE_OUT_INTERPOLATOR;
+        } else {
+            return mInterpolator;
+        }
     }
 
     @Override
@@ -536,4 +569,8 @@
                 R.dimen.heads_up_scrim_height);
         mHeadsUpScrim.setLayoutParams(layoutParams);
     }
+
+    public void setCurrentUser(int currentUser) {
+        // Don't care in the base class.
+    }
 }
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 f1d2fe9..79d274e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -53,6 +53,11 @@
 
     private static final long WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS = 200;
 
+    // Duration of the Keyguard dismissal animation in case the user is currently locked. This is to
+    // make everything a bit slower to bridge a gap until the user is unlocked and home screen has
+    // dranw its first frame.
+    private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
+
     private static String TAG = "StatusBarKeyguardViewManager";
 
     protected final Context mContext;
@@ -277,9 +282,12 @@
     /**
      * Hides the keyguard view
      */
-    public void hide(long startTime, final long fadeoutDuration) {
+    public void hide(long startTime, long fadeoutDuration) {
         mShowing = false;
 
+        if (!KeyguardUpdateMonitor.getInstance(mContext).isUserUnlocked()) {
+            fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
+        }
         long uptimeMillis = SystemClock.uptimeMillis();
         long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis);
 
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 8e0114a..e28fa73 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -69,6 +69,7 @@
 import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.widget.ICheckCredentialProgressCallback;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.VerifyCredentialResponse;
@@ -760,7 +761,7 @@
     private void unlockChildProfile(int profileHandle) throws RemoteException {
         try {
             doVerifyPassword(getDecryptedPasswordForTiedProfile(profileHandle), false,
-                    0 /* no challenge */, profileHandle);
+                    0 /* no challenge */, profileHandle, null /* progressCallback */);
         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
                 | NoSuchAlgorithmException | NoSuchPaddingException
                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
@@ -947,7 +948,7 @@
             CredentialHash willStore
                 = new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
             setUserKeyProtection(userId, pattern,
-                doVerifyPattern(pattern, willStore, true, 0, userId));
+                doVerifyPattern(pattern, willStore, true, 0, userId, null /* progressCallback */));
             mStorage.writePatternHash(enrolledHandle, userId);
             fixateNewestUserKeyAuth(userId);
             onUserLockChanged(userId);
@@ -1007,7 +1008,8 @@
             CredentialHash willStore
                 = new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
             setUserKeyProtection(userId, password,
-                doVerifyPassword(password, willStore, true, 0, userId));
+                doVerifyPassword(password, willStore, true, 0, userId,
+                        null /* progressCallback */));
             mStorage.writePasswordHash(enrolledHandle, userId);
             fixateNewestUserKeyAuth(userId);
             onUserLockChanged(userId);
@@ -1205,25 +1207,29 @@
     }
 
     @Override
-    public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
-        return doVerifyPattern(pattern, false, 0, userId);
+    public VerifyCredentialResponse checkPattern(String pattern, int userId,
+            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+        return doVerifyPattern(pattern, false, 0, userId, progressCallback);
     }
 
     @Override
     public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
             throws RemoteException {
-        return doVerifyPattern(pattern, true, challenge, userId);
+        return doVerifyPattern(pattern, true, challenge, userId, null /* progressCallback */);
     }
 
     private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,
-            long challenge, int userId) throws RemoteException {
+            long challenge, int userId, ICheckCredentialProgressCallback progressCallback)
+            throws RemoteException {
        checkPasswordReadPermission(userId);
        CredentialHash storedHash = mStorage.readPatternHash(userId);
-       return doVerifyPattern(pattern, storedHash, hasChallenge, challenge, userId);
+       return doVerifyPattern(pattern, storedHash, hasChallenge, challenge, userId,
+               progressCallback);
     }
 
     private VerifyCredentialResponse doVerifyPattern(String pattern, CredentialHash storedHash,
-            boolean hasChallenge, long challenge, int userId) throws RemoteException {
+            boolean hasChallenge, long challenge, int userId,
+            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
        boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
 
        String patternToVerify;
@@ -1252,7 +1258,8 @@
                    public String adjustForKeystore(String pattern) {
                        return LockPatternUtils.patternStringToBaseZero(pattern);
                    }
-               }
+               },
+               progressCallback
        );
 
        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
@@ -1264,15 +1271,15 @@
     }
 
     @Override
-    public VerifyCredentialResponse checkPassword(String password, int userId)
-            throws RemoteException {
-        return doVerifyPassword(password, false, 0, userId);
+    public VerifyCredentialResponse checkPassword(String password, int userId,
+            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+        return doVerifyPassword(password, false, 0, userId, progressCallback);
     }
 
     @Override
     public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
             throws RemoteException {
-        return doVerifyPassword(password, true, challenge, userId);
+        return doVerifyPassword(password, true, challenge, userId, null /* progressCallback */);
     }
 
     @Override
@@ -1285,8 +1292,10 @@
         final int parentProfileId = mUserManager.getProfileParent(userId).id;
         // Unlock parent by using parent's challenge
         final VerifyCredentialResponse parentResponse = isPattern
-                ? doVerifyPattern(password, true, challenge, parentProfileId)
-                : doVerifyPassword(password, true, challenge, parentProfileId);
+                ? doVerifyPattern(password, true, challenge, parentProfileId,
+                        null /* progressCallback */)
+                : doVerifyPassword(password, true, challenge, parentProfileId,
+                        null /* progressCallback */);
         if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
             // Failed, just return parent's response
             return parentResponse;
@@ -1296,7 +1305,7 @@
             // Unlock work profile, and work profile with unified lock must use password only
             return doVerifyPassword(getDecryptedPasswordForTiedProfile(userId), true,
                     challenge,
-                    userId);
+                    userId, null /* progressCallback */);
         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
                 | NoSuchAlgorithmException | NoSuchPaddingException
                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
@@ -1307,14 +1316,17 @@
     }
 
     private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
-            long challenge, int userId) throws RemoteException {
+            long challenge, int userId, ICheckCredentialProgressCallback progressCallback)
+            throws RemoteException {
        checkPasswordReadPermission(userId);
        CredentialHash storedHash = mStorage.readPasswordHash(userId);
-       return doVerifyPassword(password, storedHash, hasChallenge, challenge, userId);
+       return doVerifyPassword(password, storedHash, hasChallenge, challenge, userId,
+               progressCallback);
     }
 
     private VerifyCredentialResponse doVerifyPassword(String password, CredentialHash storedHash,
-            boolean hasChallenge, long challenge, int userId) throws RemoteException {
+            boolean hasChallenge, long challenge, int userId,
+            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
        return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
                new CredentialUtil() {
                    @Override
@@ -1332,12 +1344,12 @@
                    public String adjustForKeystore(String password) {
                        return password;
                    }
-               }
-       );
+               }, progressCallback);
     }
 
     private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
-            String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil)
+            String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil,
+            ICheckCredentialProgressCallback progressCallback)
                 throws RemoteException {
         if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
             // don't need to pass empty credentials to GateKeeper
@@ -1394,7 +1406,13 @@
         }
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+
+
             // credential has matched
+
+            if (progressCallback != null) {
+                progressCallback.onCredentialVerified();
+            }
             unlockKeystore(credential, userId);
 
             Slog.i(TAG, "Unlocking user " + userId +
@@ -1450,7 +1468,7 @@
 
         try {
             if (mLockPatternUtils.isLockPatternEnabled(userId)) {
-                if (checkPattern(password, userId).getResponseCode()
+                if (checkPattern(password, userId, null /* progressCallback */).getResponseCode()
                         == GateKeeperResponse.RESPONSE_OK) {
                     return true;
                 }
@@ -1460,7 +1478,7 @@
 
         try {
             if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
-                if (checkPassword(password, userId).getResponseCode()
+                if (checkPassword(password, userId, null /* progressCallback */).getResponseCode()
                         == GateKeeperResponse.RESPONSE_OK) {
                     return true;
                 }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 7907ea5..2800227 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1282,8 +1282,9 @@
     }
 
     @Override
-    public WallpaperInfo getWallpaperInfo() {
-        int userId = UserHandle.getCallingUserId();
+    public WallpaperInfo getWallpaperInfo(int userId) {
+        userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(userId);
             if (wallpaper != null && wallpaper.connection != null) {