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:
Lucas Dupin
2019-07-02 15:22:54 -07:00
parent 95a52f6387
commit fa817a0975
5 changed files with 132 additions and 43 deletions

View File

@@ -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;
}
/**

View File

@@ -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.

View File

@@ -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
}

View File

@@ -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();
}

View File

@@ -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);