Implement SFPS “require screen on to auth”

Creates new setting on SFPS to require screen on before unlocking a
device. Also sets up toggles for this setting at the end of fingerprint
enrollment and on the fingerprint settings page, and adds test to verify
expected behavior.

Test: atest KeyguardUpdateMonitorTest#testStartsListeningForSfps_whenKeyguardIsVisible_ifRequireScreenOnToAuthEnabled
Fixes: 249169615
Fixes: 245343077
Fixes: 248530806
Change-Id: Ibc55dfa6667ec281add11a2665fceb073974ccb0
Merged-In: I4aa716fb5b288ef6f92a5c403a1fd5e586e889d0
This commit is contained in:
Grace Cheng
2022-09-29 22:04:00 +00:00
committed by Joshua Mccloskey
parent 3c10ee01a9
commit 584c7743be
11 changed files with 205 additions and 4 deletions

View File

@@ -918,7 +918,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
} }
} }
/** /**
* Forwards BiometricStateListener to FingerprintService * Forwards BiometricStateListener to FingerprintService
* @param listener new BiometricStateListener being added * @param listener new BiometricStateListener being added

View File

@@ -9775,6 +9775,13 @@ public final class Settings {
public static final String FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME = public static final String FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME =
"fingerprint_side_fps_auth_downtime"; "fingerprint_side_fps_auth_downtime";
/**
* Whether or not a SFPS device is required to be interactive for auth to unlock the device.
* @hide
*/
public static final String SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED =
"sfps_require_screen_on_to_auth_enabled";
/** /**
* Whether or not debugging is enabled. * Whether or not debugging is enabled.
* @hide * @hide

View File

@@ -4967,6 +4967,10 @@
<!-- If face auth sends the user directly to home/last open app, or stays on keyguard --> <!-- If face auth sends the user directly to home/last open app, or stays on keyguard -->
<bool name="config_faceAuthDismissesKeyguard">true</bool> <bool name="config_faceAuthDismissesKeyguard">true</bool>
<!-- Default value for whether a SFPS device is required to be interactive for fingerprint auth
to unlock the device. -->
<bool name="config_requireScreenOnToAuthEnabled">false</bool>
<!-- The component name for the default profile supervisor, which can be set as a profile owner <!-- The component name for the default profile supervisor, which can be set as a profile owner
even after user setup is complete. The defined component should be used for supervision purposes even after user setup is complete. The defined component should be used for supervision purposes
only. The component must be part of a system app. --> only. The component must be part of a system app. -->

View File

@@ -2723,6 +2723,7 @@
<java-symbol type="array" name="config_face_acquire_vendor_biometricprompt_ignorelist" /> <java-symbol type="array" name="config_face_acquire_vendor_biometricprompt_ignorelist" />
<java-symbol type="bool" name="config_faceAuthSupportsSelfIllumination" /> <java-symbol type="bool" name="config_faceAuthSupportsSelfIllumination" />
<java-symbol type="bool" name="config_faceAuthDismissesKeyguard" /> <java-symbol type="bool" name="config_faceAuthDismissesKeyguard" />
<java-symbol type="bool" name="config_requireScreenOnToAuthEnabled" />
<!-- Face config --> <!-- Face config -->
<java-symbol type="integer" name="config_faceMaxTemplatesPerUser" /> <java-symbol type="integer" name="config_faceMaxTemplatesPerUser" />

View File

@@ -122,6 +122,7 @@ public class SecureSettings {
Settings.Secure.FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW, Settings.Secure.FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW,
Settings.Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW, Settings.Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW,
Settings.Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME, Settings.Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME,
Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED,
Settings.Secure.ACTIVE_UNLOCK_ON_WAKE, Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT, Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,

View File

@@ -177,6 +177,7 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW, VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW,
NON_NEGATIVE_INTEGER_VALIDATOR); NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME, NON_NEGATIVE_INTEGER_VALIDATOR); VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SHOW_MEDIA_WHEN_BYPASSING, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.SHOW_MEDIA_WHEN_BYPASSING, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_UNLOCK_APP_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.FACE_UNLOCK_APP_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, BOOLEAN_VALIDATOR);

View File

@@ -35,6 +35,7 @@ data class KeyguardFingerprintListenModel(
val keyguardOccluded: Boolean, val keyguardOccluded: Boolean,
val occludingAppRequestingFp: Boolean, val occludingAppRequestingFp: Boolean,
val primaryUser: Boolean, val primaryUser: Boolean,
val shouldListenSfpsState: Boolean,
val shouldListenForFingerprintAssistant: Boolean, val shouldListenForFingerprintAssistant: Boolean,
val switchingUser: Boolean, val switchingUser: Boolean,
val udfps: Boolean, val udfps: Boolean,

View File

@@ -151,6 +151,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.Assert; import com.android.systemui.util.Assert;
import com.android.systemui.util.settings.SecureSettings;
import com.google.android.collect.Lists; import com.google.android.collect.Lists;
@@ -337,17 +338,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>> private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList(); mCallbacks = Lists.newArrayList();
private ContentObserver mDeviceProvisionedObserver; private ContentObserver mDeviceProvisionedObserver;
private ContentObserver mSfpsRequireScreenOnToAuthPrefObserver;
private final ContentObserver mTimeFormatChangeObserver; private final ContentObserver mTimeFormatChangeObserver;
private boolean mSwitchingUser; private boolean mSwitchingUser;
private boolean mDeviceInteractive; private boolean mDeviceInteractive;
private boolean mSfpsRequireScreenOnToAuthPrefEnabled;
private final SubscriptionManager mSubscriptionManager; private final SubscriptionManager mSubscriptionManager;
private final TelephonyListenerManager mTelephonyListenerManager; private final TelephonyListenerManager mTelephonyListenerManager;
private final TrustManager mTrustManager; private final TrustManager mTrustManager;
private final UserManager mUserManager; private final UserManager mUserManager;
private final DevicePolicyManager mDevicePolicyManager; private final DevicePolicyManager mDevicePolicyManager;
private final BroadcastDispatcher mBroadcastDispatcher; private final BroadcastDispatcher mBroadcastDispatcher;
private final SecureSettings mSecureSettings;
private final InteractionJankMonitor mInteractionJankMonitor; private final InteractionJankMonitor mInteractionJankMonitor;
private final LatencyTracker mLatencyTracker; private final LatencyTracker mLatencyTracker;
private final StatusBarStateController mStatusBarStateController; private final StatusBarStateController mStatusBarStateController;
@@ -1946,6 +1950,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Context context, Context context,
@Main Looper mainLooper, @Main Looper mainLooper,
BroadcastDispatcher broadcastDispatcher, BroadcastDispatcher broadcastDispatcher,
SecureSettings secureSettings,
DumpManager dumpManager, DumpManager dumpManager,
@Background Executor backgroundExecutor, @Background Executor backgroundExecutor,
@Main Executor mainExecutor, @Main Executor mainExecutor,
@@ -1988,6 +1993,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mStatusBarState = mStatusBarStateController.getState(); mStatusBarState = mStatusBarStateController.getState();
mLockPatternUtils = lockPatternUtils; mLockPatternUtils = lockPatternUtils;
mAuthController = authController; mAuthController = authController;
mSecureSettings = secureSettings;
dumpManager.registerDumpable(getClass().getName(), this); dumpManager.registerDumpable(getClass().getName(), this);
mSensorPrivacyManager = sensorPrivacyManager; mSensorPrivacyManager = sensorPrivacyManager;
mActiveUnlockConfig = activeUnlockConfiguration; mActiveUnlockConfig = activeUnlockConfiguration;
@@ -2229,9 +2235,37 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Settings.System.TIME_12_24))); Settings.System.TIME_12_24)));
} }
}; };
mContext.getContentResolver().registerContentObserver( mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.TIME_12_24), Settings.System.getUriFor(Settings.System.TIME_12_24),
false, mTimeFormatChangeObserver, UserHandle.USER_ALL); false, mTimeFormatChangeObserver, UserHandle.USER_ALL);
if (isSfpsSupported() && isSfpsEnrolled()) {
updateSfpsRequireScreenOnToAuthPref();
mSfpsRequireScreenOnToAuthPrefObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
updateSfpsRequireScreenOnToAuthPref();
}
};
mContext.getContentResolver().registerContentObserver(
mSecureSettings.getUriFor(
Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED),
false,
mSfpsRequireScreenOnToAuthPrefObserver,
getCurrentUser());
}
}
protected void updateSfpsRequireScreenOnToAuthPref() {
final int defaultSfpsRequireScreenOnToAuthValue =
mContext.getResources().getBoolean(
com.android.internal.R.bool.config_requireScreenOnToAuthEnabled) ? 1 : 0;
mSfpsRequireScreenOnToAuthPrefEnabled = mSecureSettings.getIntForUser(
Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED,
defaultSfpsRequireScreenOnToAuthValue,
getCurrentUser()) != 0;
} }
private void initializeSimState() { private void initializeSimState() {
@@ -2275,6 +2309,22 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
&& !mAuthController.getUdfpsProps().isEmpty(); && !mAuthController.getUdfpsProps().isEmpty();
} }
/**
* @return true if there's at least one sfps enrollment for the current user.
*/
public boolean isSfpsEnrolled() {
return mAuthController.isSfpsEnrolled(getCurrentUser());
}
/**
* @return true if sfps HW is supported on this device. Can return true even if the user has
* not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered.
*/
public boolean isSfpsSupported() {
return mAuthController.getSfpsProps() != null
&& !mAuthController.getSfpsProps().isEmpty();
}
/** /**
* @return true if there's at least one face enrolled * @return true if there's at least one face enrolled
*/ */
@@ -2605,8 +2655,22 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
&& !isEncryptedOrLockdownForUser && !isEncryptedOrLockdownForUser
&& userDoesNotHaveTrust); && userDoesNotHaveTrust);
final boolean shouldListen = shouldListenKeyguardState && shouldListenUserState boolean shouldListenSfpsState = true;
&& shouldListenBouncerState && shouldListenUdfpsState && !isFingerprintLockedOut(); // If mSfpsRequireScreenOnToAuthPrefEnabled, require screen on to listen to SFPS
if (isSfpsSupported() && isSfpsEnrolled() && mSfpsRequireScreenOnToAuthPrefEnabled) {
shouldListenSfpsState = isDeviceInteractive();
}
boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
&& shouldListenBouncerState && !isFingerprintLockedOut();
if (isUdfpsSupported()) {
shouldListen = shouldListen && shouldListenUdfpsState;
}
if (isSfpsSupported()) {
shouldListen = shouldListen && shouldListenSfpsState;
}
maybeLogListenerModelData( maybeLogListenerModelData(
new KeyguardFingerprintListenModel( new KeyguardFingerprintListenModel(
@@ -2628,6 +2692,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mKeyguardOccluded, mKeyguardOccluded,
mOccludingAppRequestingFp, mOccludingAppRequestingFp,
mIsPrimaryUser, mIsPrimaryUser,
shouldListenSfpsState,
shouldListenForFingerprintAssistant, shouldListenForFingerprintAssistant,
mSwitchingUser, mSwitchingUser,
isUdfps, isUdfps,
@@ -3729,6 +3794,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mContext.getContentResolver().unregisterContentObserver(mTimeFormatChangeObserver); mContext.getContentResolver().unregisterContentObserver(mTimeFormatChangeObserver);
} }
if (mSfpsRequireScreenOnToAuthPrefObserver != null) {
mContext.getContentResolver().unregisterContentObserver(
mSfpsRequireScreenOnToAuthPrefObserver);
}
try { try {
ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver); ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -3801,6 +3871,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
pw.println(" mBouncerIsOrWillBeShowing=" + mBouncerIsOrWillBeShowing); pw.println(" mBouncerIsOrWillBeShowing=" + mBouncerIsOrWillBeShowing);
pw.println(" mStatusBarState=" + StatusBarState.toString(mStatusBarState)); pw.println(" mStatusBarState=" + StatusBarState.toString(mStatusBarState));
pw.println(" mUdfpsBouncerShowing=" + mUdfpsBouncerShowing); pw.println(" mUdfpsBouncerShowing=" + mUdfpsBouncerShowing);
} else if (isSfpsSupported()) {
pw.println(" sfpsEnrolled=" + isSfpsEnrolled());
pw.println(" shouldListenForSfps=" + shouldListenForFingerprint(false));
pw.println(" mSfpsRequireScreenOnToAuthPrefEnabled="
+ mSfpsRequireScreenOnToAuthPrefEnabled);
} }
} }
if (mFaceManager != null && mFaceManager.isHardwareDetected()) { if (mFaceManager != null && mFaceManager.isHardwareDetected()) {

View File

@@ -150,6 +150,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
@Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps; @Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps;
@NonNull private final SparseBooleanArray mUdfpsEnrolledForUser; @NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
@NonNull private final SparseBooleanArray mSfpsEnrolledForUser;
@NonNull private final SensorPrivacyManager mSensorPrivacyManager; @NonNull private final SensorPrivacyManager mSensorPrivacyManager;
private final WakefulnessLifecycle mWakefulnessLifecycle; private final WakefulnessLifecycle mWakefulnessLifecycle;
private boolean mAllFingerprintAuthenticatorsRegistered; private boolean mAllFingerprintAuthenticatorsRegistered;
@@ -325,6 +326,16 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
} }
} }
} }
if (mSidefpsProps == null) {
Log.d(TAG, "handleEnrollmentsChanged, mSidefpsProps is null");
} else {
for (FingerprintSensorPropertiesInternal prop : mSidefpsProps) {
if (prop.sensorId == sensorId) {
mSfpsEnrolledForUser.put(userId, hasEnrollments);
}
}
}
for (Callback cb : mCallbacks) { for (Callback cb : mCallbacks) {
cb.onEnrollmentsChanged(); cb.onEnrollmentsChanged();
} }
@@ -677,6 +688,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
mWindowManager = windowManager; mWindowManager = windowManager;
mInteractionJankMonitor = jankMonitor; mInteractionJankMonitor = jankMonitor;
mUdfpsEnrolledForUser = new SparseBooleanArray(); mUdfpsEnrolledForUser = new SparseBooleanArray();
mSfpsEnrolledForUser = new SparseBooleanArray();
mOrientationListener = new BiometricDisplayListener( mOrientationListener = new BiometricDisplayListener(
context, context,
@@ -889,6 +901,11 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
return mUdfpsProps; return mUdfpsProps;
} }
@Nullable
public List<FingerprintSensorPropertiesInternal> getSfpsProps() {
return mSidefpsProps;
}
private String getErrorString(@Modality int modality, int error, int vendorCode) { private String getErrorString(@Modality int modality, int error, int vendorCode) {
switch (modality) { switch (modality) {
case TYPE_FACE: case TYPE_FACE:
@@ -1013,6 +1030,17 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
return mUdfpsEnrolledForUser.get(userId); return mUdfpsEnrolledForUser.get(userId);
} }
/**
* Whether the passed userId has enrolled SFPS.
*/
public boolean isSfpsEnrolled(int userId) {
if (mSidefpsController == null) {
return false;
}
return mSfpsEnrolledForUser.get(userId);
}
private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) { private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
mCurrentDialogArgs = args; mCurrentDialogArgs = args;

View File

@@ -72,6 +72,7 @@ private fun fingerprintModel(user: Int) = KeyguardFingerprintListenModel(
keyguardOccluded = false, keyguardOccluded = false,
occludingAppRequestingFp = false, occludingAppRequestingFp = false,
primaryUser = false, primaryUser = false,
shouldListenSfpsState = false,
shouldListenForFingerprintAssistant = false, shouldListenForFingerprintAssistant = false,
switchingUser = false, switchingUser = false,
udfps = false, udfps = false,

View File

@@ -20,6 +20,7 @@ import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
@@ -38,6 +39,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
@@ -53,6 +55,7 @@ import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager; import android.app.trust.TrustManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
@@ -60,18 +63,21 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.SensorProperties;
import android.hardware.face.FaceManager; import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties; import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.net.Uri;
import android.nfc.NfcAdapter; import android.nfc.NfcAdapter;
import android.os.Bundle; import android.os.Bundle;
import android.os.CancellationSignal; import android.os.CancellationSignal;
@@ -110,6 +116,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.settings.GlobalSettings; import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.settings.SecureSettings;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
@@ -181,6 +188,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Mock @Mock
private BroadcastDispatcher mBroadcastDispatcher; private BroadcastDispatcher mBroadcastDispatcher;
@Mock @Mock
private SecureSettings mSecureSettings;
@Mock
private TelephonyManager mTelephonyManager; private TelephonyManager mTelephonyManager;
@Mock @Mock
private SensorPrivacyManager mSensorPrivacyManager; private SensorPrivacyManager mSensorPrivacyManager;
@@ -214,6 +223,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private GlobalSettings mGlobalSettings; private GlobalSettings mGlobalSettings;
private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig; private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
private final int mCurrentUserId = 100; private final int mCurrentUserId = 100;
private final UserInfo mCurrentUserInfo = new UserInfo(mCurrentUserId, "Test user", 0); private final UserInfo mCurrentUserInfo = new UserInfo(mCurrentUserId, "Test user", 0);
@@ -223,6 +233,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Captor @Captor
private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor; private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor;
@Mock
private Uri mURI;
// Direct executor // Direct executor
private final Executor mBackgroundExecutor = Runnable::run; private final Executor mBackgroundExecutor = Runnable::run;
private final Executor mMainExecutor = Runnable::run; private final Executor mMainExecutor = Runnable::run;
@@ -305,6 +318,15 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper = TestableLooper.get(this); mTestableLooper = TestableLooper.get(this);
allowTestableLooperAsMainThread(); allowTestableLooperAsMainThread();
when(mSecureSettings.getUriFor(anyString())).thenReturn(mURI);
final ContentResolver contentResolver = mContext.getContentResolver();
ExtendedMockito.spyOn(contentResolver);
doNothing().when(contentResolver)
.registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class),
anyInt());
mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext); mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
verify(mBiometricManager) verify(mBiometricManager)
@@ -1136,6 +1158,67 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(true); assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(true);
} }
@Test
public void testStartsListeningForSfps_whenKeyguardIsVisible_ifRequireScreenOnToAuthEnabled()
throws RemoteException {
// SFPS supported and enrolled
setup_SfpsProps();
// WHEN require screen on to auth is disabled, and keyguard is not awake
when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).thenReturn(0);
mKeyguardUpdateMonitor.updateSfpsRequireScreenOnToAuthPref();
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_requireScreenOnToAuthEnabled, true);
// Preconditions for sfps auth to run
keyguardNotGoingAway();
currentUserIsPrimary();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
userNotCurrentlySwitching();
statusBarShadeIsLocked();
mTestableLooper.processAllMessages();
// THEN we should listen for sfps when screen off, because require screen on is disabled
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue();
// WHEN require screen on to auth is enabled, and keyguard is not awake
when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).thenReturn(1);
mKeyguardUpdateMonitor.updateSfpsRequireScreenOnToAuthPref();
// THEN we shouldn't listen for sfps when screen off, because require screen on is enabled
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse();
// Device now awake & keyguard is now interactive
deviceNotGoingToSleep();
deviceIsInteractive();
keyguardIsVisible();
// THEN we should listen for sfps when screen on, and require screen on is enabled
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue();
}
private void setup_SfpsProps() {
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON));
when(mAuthController.getSfpsProps()).thenReturn(props);
when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
}
private FingerprintSensorPropertiesInternal newFingerprintSensorPropertiesInternal(
@FingerprintSensorProperties.SensorType int sensorType) {
return new FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */,
new ArrayList<ComponentInfoInternal>(),
sensorType,
true /* resetLockoutRequiresHardwareAuthToken */);
}
@Test @Test
public void testShouldNotListenForUdfps_whenTrustEnabled() { public void testShouldNotListenForUdfps_whenTrustEnabled() {
// GIVEN a "we should listen for udfps" state // GIVEN a "we should listen for udfps" state
@@ -1805,7 +1888,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
protected TestableKeyguardUpdateMonitor(Context context) { protected TestableKeyguardUpdateMonitor(Context context) {
super(context, super(context,
TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(), TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(),
mBroadcastDispatcher, mDumpManager, mBroadcastDispatcher, mSecureSettings, mDumpManager,
mBackgroundExecutor, mMainExecutor, mBackgroundExecutor, mMainExecutor,
mStatusBarStateController, mLockPatternUtils, mStatusBarStateController, mLockPatternUtils,
mAuthController, mTelephonyListenerManager, mAuthController, mTelephonyListenerManager,