Merge changes from topic "require-screen-on-to-auth" into tm-qpr-dev

* changes:
  Fix keyguard logic for listening to sfps
  Implement SFPS “require screen on to auth”
This commit is contained in:
Joshua Mccloskey
2022-11-03 01:56:52 +00:00
committed by Android (Google) Code Review
11 changed files with 199 additions and 6 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

@@ -9792,6 +9792,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;
@@ -396,6 +400,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
protected Handler getHandler() { protected Handler getHandler() {
return mHandler; return mHandler;
} }
private final Handler mHandler; private final Handler mHandler;
private final IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback = private final IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback =
@@ -720,6 +725,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
/** /**
* Request to listen for face authentication when an app is occluding keyguard. * Request to listen for face authentication when an app is occluding keyguard.
*
* @param request if true and mKeyguardOccluded, request face auth listening, else default * @param request if true and mKeyguardOccluded, request face auth listening, else default
* to normal behavior. * to normal behavior.
* See {@link KeyguardUpdateMonitor#shouldListenForFace()} * See {@link KeyguardUpdateMonitor#shouldListenForFace()}
@@ -732,6 +738,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
/** /**
* Request to listen for fingerprint when an app is occluding keyguard. * Request to listen for fingerprint when an app is occluding keyguard.
*
* @param request if true and mKeyguardOccluded, request fingerprint listening, else default * @param request if true and mKeyguardOccluded, request fingerprint listening, else default
* to normal behavior. * to normal behavior.
* See {@link KeyguardUpdateMonitor#shouldListenForFingerprint(boolean)} * See {@link KeyguardUpdateMonitor#shouldListenForFingerprint(boolean)}
@@ -1946,6 +1953,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 +1996,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 +2238,35 @@ 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);
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 +2310,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
*/ */
@@ -2598,13 +2649,21 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
!(mFingerprintLockedOut && mBouncerIsOrWillBeShowing && mCredentialAttempted); !(mFingerprintLockedOut && mBouncerIsOrWillBeShowing && mCredentialAttempted);
final boolean isEncryptedOrLockdownForUser = isEncryptedOrLockdown(user); final boolean isEncryptedOrLockdownForUser = isEncryptedOrLockdown(user);
final boolean shouldListenUdfpsState = !isUdfps final boolean shouldListenUdfpsState = !isUdfps
|| (!userCanSkipBouncer || (!userCanSkipBouncer
&& !isEncryptedOrLockdownForUser && !isEncryptedOrLockdownForUser
&& userDoesNotHaveTrust); && userDoesNotHaveTrust);
final boolean shouldListen = shouldListenKeyguardState && shouldListenUserState boolean shouldListenSideFpsState = true;
&& shouldListenBouncerState && shouldListenUdfpsState && !isFingerprintLockedOut(); if (isSfpsSupported() && isSfpsEnrolled()) {
shouldListenSideFpsState =
mSfpsRequireScreenOnToAuthPrefEnabled ? isDeviceInteractive() : true;
}
boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
&& shouldListenBouncerState && shouldListenUdfpsState && !isFingerprintLockedOut()
&& shouldListenSideFpsState;
maybeLogListenerModelData( maybeLogListenerModelData(
new KeyguardFingerprintListenModel( new KeyguardFingerprintListenModel(
@@ -2626,6 +2685,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mKeyguardOccluded, mKeyguardOccluded,
mOccludingAppRequestingFp, mOccludingAppRequestingFp,
mIsPrimaryUser, mIsPrimaryUser,
shouldListenSideFpsState,
shouldListenForFingerprintAssistant, shouldListenForFingerprintAssistant,
mSwitchingUser, mSwitchingUser,
isUdfps, isUdfps,
@@ -3727,6 +3787,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) {
@@ -3799,6 +3864,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)
@@ -1135,6 +1157,64 @@ 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
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON));
when(mAuthController.getSfpsProps()).thenReturn(props);
when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
// 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 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
@@ -1804,7 +1884,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,