diff --git a/Android.mk b/Android.mk index a437950a406e5..8eabdd623fbc1 100644 --- a/Android.mk +++ b/Android.mk @@ -343,6 +343,7 @@ LOCAL_SRC_FILES += \ 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/com/android/internal/widget/ICheckCredentialProgressCallback.aidl b/core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl new file mode 100644 index 0000000000000..79717cf2b0c9f --- /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 05b839df9fa47..9fa558e89ae79 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 @@ interface ILockSettings { 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 713f56f46266c..df9b0ddc18047 100644 --- a/core/java/com/android/internal/widget/LockPatternChecker.java +++ b/core/java/com/android/internal/widget/LockPatternChecker.java @@ -14,6 +14,13 @@ public final class LockPatternChecker { * 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 @@ public final class LockPatternChecker { @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 @@ public final class LockPatternChecker { @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 2e0dfa5fa7312..eff116b7570ce 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.Message; 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 @@ public class LockPatternUtils { 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 class LockPatternUtils { */ public boolean checkPattern(List 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 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 @@ public class LockPatternUtils { * @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) { @@ -1475,6 +1501,33 @@ public class LockPatternUtils { 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 60eaad2699eea..038e08d758eb0 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -137,12 +137,21 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout 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 7ea767c004fb5..4f5152aca6f38 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java @@ -36,6 +36,7 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { 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 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { private View mDivider; private int mDisappearYTranslation; private View[][] mViews; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; public KeyguardPINView(Context context) { this(context, null); @@ -56,8 +58,14 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { 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 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { 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 e07049262c6ec..84b90c44c1a69 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java @@ -55,9 +55,13 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit // 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 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit 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 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit 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 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit @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 94d9550f77e41..dec1fd229e9f0 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.Intent; 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.Message; 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.HashMap; 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private boolean mGoingToSleep; private boolean mBouncer; private boolean mBootCompleted; + private boolean mUserUnlocked; // Device provisioning state private boolean mDeviceProvisioned; @@ -202,6 +203,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private AlarmManager mAlarmManager; private List mSubscriptionInfo; private TrustManager mTrustManager; + private UserManager mUserManager; private int mFingerprintRunningState = FINGERPRINT_STATE_STOPPED; private final Handler mHandler = new Handler() { @@ -554,6 +556,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { && !hasFingerprintUnlockTimedOut(sCurrentUser); } + public boolean isUserUnlocked() { + return mUserUnlocked; + } + public StrongAuthTracker getStrongAuthTracker() { return mStrongAuthTracker; } @@ -1058,6 +1064,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { if (mFpm != null) { mFpm.addLockoutResetCallback(mLockoutResetCallback); } + + mUserManager = context.getSystemService(UserManager.class); } private void updateFingerprintListeningState() { @@ -1390,6 +1398,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private void handleKeyguardReset() { if (DEBUG) Log.d(TAG, "handleKeyguardReset"); updateFingerprintListeningState(); + mUserUnlocked = mUserManager.isUserUnlocked(getCurrentUser()); } /** 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 ee88b0041b7d1..b3e86b5dcdaa6 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 @@ public class KeyguardBouncer { 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/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 135c294987cf6..e7b57c5e88ac8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -30,6 +30,7 @@ import android.view.animation.DecelerateInterpolator; 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; @@ -46,10 +47,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, 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; 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; @@ -59,6 +63,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, private final ScrimView mScrimInFront; private final UnlockMethodCache mUnlockMethodCache; private final View mHeadsUpScrim; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private float mScrimBehindAlpha = SCRIM_BEHIND_ALPHA; private float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD; @@ -99,6 +104,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mHeadsUpScrim = headsUpScrim; final Context context = scrimBehind.getContext(); mUnlockMethodCache = UnlockMethodCache.getInstance(context); + mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context); updateHeadsUpScrim(false); } @@ -162,11 +168,19 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, 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() { @@ -211,6 +225,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, return mDozeInFrontAlpha; } + private float getScrimInFrontAlpha() { + return mKeyguardUpdateMonitor.isUserUnlocked() + ? SCRIM_IN_FRONT_ALPHA + : SCRIM_IN_FRONT_ALPHA_LOCKED; + } private void scheduleUpdate() { if (mUpdatePending) return; @@ -250,10 +269,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, 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) { - setScrimInFrontColor(SCRIM_IN_FRONT_ALPHA); + setScrimInFrontColor(getScrimInFrontAlpha()); setScrimBehindColor(0f); } else { float fraction = Math.max(0, Math.min(mFraction, 1)); @@ -371,7 +390,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } private 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 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 8d0d9cb27cea2..3691a42447ac1 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 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb 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; @@ -274,9 +279,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb /** * 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 8e0114a0815cf..ee2c09b510cef 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.Log; 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 @@ public class LockSettingsService extends ILockSettings.Stub { 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 @@ public class LockSettingsService extends ILockSettings.Stub { 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 @@ public class LockSettingsService extends ILockSettings.Stub { 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 @@ public class LockSettingsService extends ILockSettings.Stub { } @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 class LockSettingsService extends ILockSettings.Stub { public String adjustForKeystore(String pattern) { return LockPatternUtils.patternStringToBaseZero(pattern); } - } + }, + progressCallback ); if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK @@ -1264,15 +1271,15 @@ public class LockSettingsService extends ILockSettings.Stub { } @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 @@ public class LockSettingsService extends ILockSettings.Stub { 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 @@ public class LockSettingsService extends ILockSettings.Stub { // 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 @@ public class LockSettingsService extends ILockSettings.Stub { } 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 class LockSettingsService extends ILockSettings.Stub { 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 @@ -1395,6 +1407,10 @@ public class LockSettingsService extends ILockSettings.Stub { 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 +1466,7 @@ public class LockSettingsService extends ILockSettings.Stub { try { if (mLockPatternUtils.isLockPatternEnabled(userId)) { - if (checkPattern(password, userId).getResponseCode() + if (checkPattern(password, userId, null /* progressCallback */).getResponseCode() == GateKeeperResponse.RESPONSE_OK) { return true; } @@ -1460,7 +1476,7 @@ public class LockSettingsService extends ILockSettings.Stub { try { if (mLockPatternUtils.isLockPasswordEnabled(userId)) { - if (checkPassword(password, userId).getResponseCode() + if (checkPassword(password, userId, null /* progressCallback */).getResponseCode() == GateKeeperResponse.RESPONSE_OK) { return true; }