Wake-and-unlock fixes
- Created separate path for fingerprint devices - Restored NPV animation for fingerprint - Created keyguard bypass mode - Fixed issue where bypass wouldn't dismiss lock screen Fixes: 136568545 Bug: 134952761 Test: atest BiometricUnlockControllerTest Test: unlock with SIM PIN Test: face unlock from LS (no bypass) Test: face unlock from AOD2 (no bypass) Test: face unlock from bouncer (no bypass) Test: face unlock from shade (no bypass) Test: face unlock from LS (bypass) Test: face unlock from AOD2 (bypass) Test: face unlock from bouncer (bypass) Test: face unlock from shade (bypass) Test: fingerprint unlock from encrypted LS Test: fingerprint unlock from LS Test: fingerprint unlock from AOD2 Test: fingerprint unlock from bouncer Test: fingerprint unlock from shade Change-Id: I28052dcb7d9701beb1eeecb6312e55e96d748614
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.metrics.LogMaker;
|
||||
@@ -39,6 +40,8 @@ import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.statusbar.NotificationMediaManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Controller which coordinates all the biometric unlocking actions with the UI.
|
||||
@@ -50,6 +53,20 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
|
||||
private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
|
||||
private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
|
||||
|
||||
@IntDef(prefix = { "MODE_" }, value = {
|
||||
MODE_NONE,
|
||||
MODE_WAKE_AND_UNLOCK,
|
||||
MODE_WAKE_AND_UNLOCK_PULSING,
|
||||
MODE_SHOW_BOUNCER,
|
||||
MODE_ONLY_WAKE,
|
||||
MODE_UNLOCK_COLLAPSING,
|
||||
MODE_UNLOCK_FADING,
|
||||
MODE_DISMISS_BOUNCER,
|
||||
MODE_WAKE_AND_UNLOCK_FROM_DREAM
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface WakeAndUnlockMode {}
|
||||
|
||||
/**
|
||||
* Mode in which we don't need to wake up the device when we authenticate.
|
||||
*/
|
||||
@@ -81,13 +98,24 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
|
||||
/**
|
||||
* Mode in which fingerprint unlocks the device.
|
||||
*/
|
||||
public static final int MODE_UNLOCK = 5;
|
||||
public static final int MODE_UNLOCK_COLLAPSING = 5;
|
||||
|
||||
/**
|
||||
* Mode in which fingerprint wakes and unlocks the device from a dream.
|
||||
*/
|
||||
public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 6;
|
||||
|
||||
/**
|
||||
* Faster mode of dismissing the lock screen when we cross fade to an app
|
||||
* (used for keyguard bypass.)
|
||||
*/
|
||||
public static final int MODE_UNLOCK_FADING = 7;
|
||||
|
||||
/**
|
||||
* When bouncer is visible and will be dismissed.
|
||||
*/
|
||||
public static final int MODE_DISMISS_BOUNCER = 8;
|
||||
|
||||
/**
|
||||
* How much faster we collapse the lockscreen when authenticating with biometric.
|
||||
*/
|
||||
@@ -240,8 +268,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
|
||||
startWakeAndUnlock(calculateMode(biometricSourceType));
|
||||
}
|
||||
|
||||
public void startWakeAndUnlock(int mode) {
|
||||
// TODO(b/62444020): remove when this bug is fixed
|
||||
public void startWakeAndUnlock(@WakeAndUnlockMode int mode) {
|
||||
Log.v(TAG, "startWakeAndUnlock(" + mode + ")");
|
||||
boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
|
||||
mMode = mode;
|
||||
@@ -277,18 +304,16 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
|
||||
wakeUp.run();
|
||||
}
|
||||
switch (mMode) {
|
||||
case MODE_UNLOCK:
|
||||
Trace.beginSection("MODE_UNLOCK");
|
||||
if (!wasDeviceInteractive) {
|
||||
mPendingShowBouncer = true;
|
||||
} else {
|
||||
mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
|
||||
false /* strongAuth */);
|
||||
}
|
||||
case MODE_DISMISS_BOUNCER:
|
||||
case MODE_UNLOCK_FADING:
|
||||
Trace.beginSection("MODE_DISMISS_BOUNCER or MODE_UNLOCK_FADING");
|
||||
mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
|
||||
false /* strongAuth */);
|
||||
Trace.endSection();
|
||||
break;
|
||||
case MODE_UNLOCK_COLLAPSING:
|
||||
case MODE_SHOW_BOUNCER:
|
||||
Trace.beginSection("MODE_SHOW_BOUNCER");
|
||||
Trace.beginSection("MODE_UNLOCK_COLLAPSING or MODE_SHOW_BOUNCER");
|
||||
if (!wasDeviceInteractive) {
|
||||
mPendingShowBouncer = true;
|
||||
} else {
|
||||
@@ -368,49 +393,38 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
|
||||
return mMode;
|
||||
}
|
||||
|
||||
private int calculateMode(BiometricSourceType biometricSourceType) {
|
||||
private @WakeAndUnlockMode int calculateMode(BiometricSourceType biometricSourceType) {
|
||||
if (biometricSourceType == BiometricSourceType.FACE
|
||||
|| biometricSourceType == BiometricSourceType.IRIS) {
|
||||
return calculateModeForPassiveAuth();
|
||||
} else {
|
||||
return calculateModeForFingerprint();
|
||||
}
|
||||
}
|
||||
|
||||
private @WakeAndUnlockMode int calculateModeForFingerprint() {
|
||||
boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
|
||||
boolean deviceDreaming = mUpdateMonitor.isDreaming();
|
||||
boolean face = biometricSourceType == BiometricSourceType.FACE;
|
||||
boolean faceStayingOnKeyguard = face && !mKeyguardBypassController.getBypassEnabled();
|
||||
|
||||
if (!mUpdateMonitor.isDeviceInteractive()) {
|
||||
if (!mStatusBarKeyguardViewManager.isShowing()) {
|
||||
return MODE_ONLY_WAKE;
|
||||
} else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
|
||||
// Let's not wake-up to lock screen when not bypassing, otherwise the notification
|
||||
// would move as the user tried to tap it.
|
||||
return faceStayingOnKeyguard ? MODE_NONE : MODE_WAKE_AND_UNLOCK_PULSING;
|
||||
} else if (!face && (unlockingAllowed || !mUnlockMethodCache.isMethodSecure())) {
|
||||
return MODE_WAKE_AND_UNLOCK_PULSING;
|
||||
} else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) {
|
||||
return MODE_WAKE_AND_UNLOCK;
|
||||
} else if (face) {
|
||||
if (!(mDozeScrimController.isPulsing() && !unlockingAllowed)) {
|
||||
Log.wtf(TAG, "Face somehow arrived when the device was not interactive");
|
||||
}
|
||||
if (faceStayingOnKeyguard) {
|
||||
// We could theoretically return MODE_NONE, but this means that the device
|
||||
// would be not interactive, unlocked, and the user would not see the device
|
||||
// state.
|
||||
return MODE_ONLY_WAKE;
|
||||
} else {
|
||||
// Wake-up fading out nicely
|
||||
return MODE_WAKE_AND_UNLOCK_PULSING;
|
||||
}
|
||||
} else {
|
||||
return MODE_SHOW_BOUNCER;
|
||||
}
|
||||
}
|
||||
if (unlockingAllowed && deviceDreaming && !faceStayingOnKeyguard) {
|
||||
if (unlockingAllowed && deviceDreaming) {
|
||||
return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
|
||||
}
|
||||
if (mStatusBarKeyguardViewManager.isShowing()) {
|
||||
if ((mStatusBarKeyguardViewManager.isBouncerShowing())
|
||||
&& unlockingAllowed) {
|
||||
return MODE_UNLOCK;
|
||||
if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
|
||||
return MODE_DISMISS_BOUNCER;
|
||||
} else if (unlockingAllowed) {
|
||||
return faceStayingOnKeyguard ? MODE_ONLY_WAKE : MODE_UNLOCK;
|
||||
} else if (face) {
|
||||
return faceStayingOnKeyguard ? MODE_NONE : MODE_SHOW_BOUNCER;
|
||||
return MODE_UNLOCK_COLLAPSING;
|
||||
} else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
|
||||
return MODE_SHOW_BOUNCER;
|
||||
}
|
||||
@@ -418,6 +432,49 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
|
||||
return MODE_NONE;
|
||||
}
|
||||
|
||||
private @WakeAndUnlockMode int calculateModeForPassiveAuth() {
|
||||
boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
|
||||
boolean deviceDreaming = mUpdateMonitor.isDreaming();
|
||||
boolean bypass = mKeyguardBypassController.getBypassEnabled();
|
||||
|
||||
if (!mUpdateMonitor.isDeviceInteractive()) {
|
||||
if (!mStatusBarKeyguardViewManager.isShowing()) {
|
||||
return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
|
||||
} else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
|
||||
// Let's not wake-up to lock screen when not bypassing, otherwise the notification
|
||||
// would move as the user tried to tap it.
|
||||
return bypass ? MODE_WAKE_AND_UNLOCK_PULSING : MODE_NONE;
|
||||
} else {
|
||||
if (!(mDozeScrimController.isPulsing() && !unlockingAllowed)) {
|
||||
Log.wtf(TAG, "Face somehow arrived when the device was not interactive");
|
||||
}
|
||||
if (bypass) {
|
||||
// Wake-up fading out nicely
|
||||
return MODE_WAKE_AND_UNLOCK_PULSING;
|
||||
} else {
|
||||
// We could theoretically return MODE_NONE, but this means that the device
|
||||
// would be not interactive, unlocked, and the user would not see the device
|
||||
// state.
|
||||
return MODE_ONLY_WAKE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unlockingAllowed && deviceDreaming) {
|
||||
return bypass ? MODE_WAKE_AND_UNLOCK_FROM_DREAM : MODE_ONLY_WAKE;
|
||||
}
|
||||
if (mStatusBarKeyguardViewManager.isShowing()) {
|
||||
if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
|
||||
return bypass && !mKeyguardBypassController.canPlaySubtleWindowAnimations()
|
||||
? MODE_UNLOCK_COLLAPSING : MODE_UNLOCK_FADING;
|
||||
} else if (unlockingAllowed) {
|
||||
return bypass ? MODE_UNLOCK_FADING : MODE_NONE;
|
||||
} else {
|
||||
return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
|
||||
}
|
||||
}
|
||||
return MODE_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
|
||||
mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
|
||||
@@ -504,7 +561,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
|
||||
* on or off.
|
||||
*/
|
||||
public boolean isBiometricUnlock() {
|
||||
return isWakeAndUnlock() || mMode == MODE_UNLOCK;
|
||||
return isWakeAndUnlock() || mMode == MODE_UNLOCK_COLLAPSING || mMode == MODE_UNLOCK_FADING;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -345,6 +345,13 @@ public class KeyguardBouncer {
|
||||
&& mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #show(boolean)} was called but we're not showing yet.
|
||||
*/
|
||||
public boolean willShowSoon() {
|
||||
return mShowingSoon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} when bouncer's pre-hide animation already started but isn't completely
|
||||
* hidden yet, {@code false} otherwise.
|
||||
|
||||
@@ -138,6 +138,20 @@ class KeyguardBypassController {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* If shorter animations should be played when unlocking.
|
||||
*/
|
||||
fun canPlaySubtleWindowAnimations(): Boolean {
|
||||
if (bypassEnabled) {
|
||||
return when {
|
||||
statusBarStateController.state != StatusBarState.KEYGUARD -> false
|
||||
qSExpanded -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun onStartedGoingToSleep() {
|
||||
pendingUnlockType = null
|
||||
}
|
||||
|
||||
@@ -677,6 +677,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
return mBouncer.isShowing();
|
||||
}
|
||||
|
||||
/**
|
||||
* When bouncer is fully visible or {@link KeyguardBouncer#show(boolean)} was called but
|
||||
* animation didn't finish yet.
|
||||
*/
|
||||
public boolean bouncerIsOrWillBeShowing() {
|
||||
return mBouncer.isShowing() || mBouncer.willShowSoon();
|
||||
}
|
||||
|
||||
public boolean isFullscreenBouncer() {
|
||||
return mBouncer.isFullscreenBouncer();
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
||||
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
|
||||
when(mUnlockMethodCache.isUnlockingWithFacePossible()).thenReturn(true);
|
||||
when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
|
||||
when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
|
||||
mContext.addMockSystemService(PowerManager.class, mPowerManager);
|
||||
mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
|
||||
mDependency.injectTestDependency(StatusBarWindowController.class,
|
||||
@@ -120,13 +121,13 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
||||
BiometricSourceType.FINGERPRINT);
|
||||
|
||||
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
|
||||
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
|
||||
verify(mStatusBarKeyguardViewManager).animateCollapsePanels(anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBiometricAuthenticated_whenFingerprintOnBouncer_dismissBouncer() {
|
||||
when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
|
||||
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
|
||||
when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
|
||||
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
|
||||
BiometricSourceType.FINGERPRINT);
|
||||
|
||||
@@ -140,6 +141,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
||||
BiometricSourceType.FACE);
|
||||
|
||||
verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
|
||||
verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -151,6 +153,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
||||
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
|
||||
BiometricSourceType.FACE);
|
||||
|
||||
verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
|
||||
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
|
||||
}
|
||||
|
||||
@@ -181,7 +184,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void onBiometricAuthenticated_whenFaceOnBouncer_dismissBouncer() {
|
||||
when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
|
||||
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
|
||||
when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
|
||||
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
|
||||
BiometricSourceType.FACE);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user