Merge "Added FingerprintInteractiveToAuthProvider"

This commit is contained in:
Joshua Mccloskey
2023-01-10 01:38:24 +00:00
committed by Android (Google) Code Review
6 changed files with 58 additions and 400 deletions

View File

@@ -140,6 +140,7 @@ import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -169,6 +170,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.Executor;
@@ -329,13 +331,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList();
private ContentObserver mDeviceProvisionedObserver;
private ContentObserver mSfpsRequireScreenOnToAuthPrefObserver;
private final ContentObserver mTimeFormatChangeObserver;
private boolean mSwitchingUser;
private boolean mDeviceInteractive;
private boolean mSfpsRequireScreenOnToAuthPrefEnabled;
private final SubscriptionManager mSubscriptionManager;
private final TelephonyListenerManager mTelephonyListenerManager;
private final TrustManager mTrustManager;
@@ -368,6 +368,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mLogoutEnabled;
private boolean mIsFaceEnrolled;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider;
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
@@ -2039,7 +2040,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Nullable FaceManager faceManager,
@Nullable FingerprintManager fingerprintManager,
@Nullable BiometricManager biometricManager,
FaceWakeUpTriggersConfig faceWakeUpTriggersConfig) {
FaceWakeUpTriggersConfig faceWakeUpTriggersConfig,
Optional<FingerprintInteractiveToAuthProvider> interactiveToAuthProvider) {
mContext = context;
mSubscriptionManager = subscriptionManager;
mUserTracker = userTracker;
@@ -2303,30 +2305,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Settings.System.getUriFor(Settings.System.TIME_12_24),
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;
mFingerprintInteractiveToAuthProvider = interactiveToAuthProvider.orElse(null);
}
private void initializeSimState() {
@@ -2721,8 +2700,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
boolean shouldListenSideFpsState = true;
if (isSideFps) {
final boolean interactiveToAuthEnabled =
mFingerprintInteractiveToAuthProvider != null &&
mFingerprintInteractiveToAuthProvider.isEnabled(getCurrentUser());
shouldListenSideFpsState =
mSfpsRequireScreenOnToAuthPrefEnabled ? isDeviceInteractive() : true;
interactiveToAuthEnabled ? isDeviceInteractive() : true;
}
boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
@@ -3837,11 +3819,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mContext.getContentResolver().unregisterContentObserver(mTimeFormatChangeObserver);
}
if (mSfpsRequireScreenOnToAuthPrefObserver != null) {
mContext.getContentResolver().unregisterContentObserver(
mSfpsRequireScreenOnToAuthPrefObserver);
}
try {
ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver);
} catch (RemoteException e) {
@@ -3919,8 +3896,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
pw.println(" sfpsEnrolled=" + isSfpsEnrolled());
pw.println(" shouldListenForSfps=" + shouldListenForFingerprint(false));
if (isSfpsEnrolled()) {
pw.println(" mSfpsRequireScreenOnToAuthPrefEnabled="
+ mSfpsRequireScreenOnToAuthPrefEnabled);
final boolean interactiveToAuthEnabled =
mFingerprintInteractiveToAuthProvider != null &&
mFingerprintInteractiveToAuthProvider
.isEnabled(getCurrentUser());
pw.println(" interactiveToAuthEnabled="
+ interactiveToAuthEnabled);
}
}
new DumpsysTableLogger(

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2023 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.systemui.biometrics;
/** Provides the status of the interactive to auth feature. */
public interface FingerprintInteractiveToAuthProvider {
/**
*
* @param userId the user Id.
* @return true if the InteractiveToAuthFeature is enabled, false if disabled.
*/
boolean isEnabled(int userId);
}

View File

@@ -31,6 +31,7 @@ import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.biometrics.UdfpsDisplayModeProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.biometrics.dagger.UdfpsModule;
@@ -221,6 +222,9 @@ public abstract class SystemUIModule {
@BindsOptionalOf
abstract AlternateUdfpsTouchProvider optionalUdfpsTouchProvider();
@BindsOptionalOf
abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider();
@SysUISingleton
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);

View File

@@ -117,6 +117,7 @@ import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated;
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.log.SessionTracker;
@@ -143,6 +144,7 @@ import org.mockito.internal.util.reflection.FieldSetter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -234,6 +236,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Mock
private GlobalSettings mGlobalSettings;
private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
@Mock
private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider;
private final int mCurrentUserId = 100;
@@ -1259,8 +1263,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
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();
when(mInteractiveToAuthProvider.isEnabled(anyInt())).thenReturn(false);
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_requireScreenOnToAuthEnabled, true);
@@ -1280,8 +1283,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
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();
when(mInteractiveToAuthProvider.isEnabled(anyInt())).thenReturn(false);
// THEN we shouldn't listen for sfps when screen off, because require screen on is enabled
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse();
@@ -2406,7 +2408,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mPowerManager, mTrustManager, mSubscriptionManager, mUserManager,
mDreamManager, mDevicePolicyManager, mSensorPrivacyManager, mTelephonyManager,
mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager,
mFaceWakeUpTriggersConfig);
mFaceWakeUpTriggersConfig, Optional.of(mInteractiveToAuthProvider));
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}

View File

@@ -16,15 +16,11 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired;
import android.hardware.biometrics.BiometricManager.Authenticators;
@@ -94,7 +90,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
private long mSideFpsLastAcquireStartTime;
private Runnable mAuthSuccessRunnable;
private final Clock mClock;
private boolean mDidFinishSfps;
FingerprintAuthenticationClient(
@NonNull Context context,
@@ -204,9 +199,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
@Override
protected void handleLifecycleAfterAuth(boolean authenticated) {
if (authenticated && !mDidFinishSfps) {
if (authenticated) {
mCallback.onClientFinished(this, true /* success */);
mDidFinishSfps = true;
}
}
@@ -216,13 +210,11 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
return false;
}
public void handleAuthenticate(
@Override
public void onAuthenticated(
BiometricAuthenticator.Identifier identifier,
boolean authenticated,
ArrayList<Byte> token) {
if (authenticated && mSensorProps.isAnySidefpsType()) {
Slog.i(TAG, "(sideFPS): No power press detected, sending auth");
}
super.onAuthenticated(identifier, authenticated, token);
if (authenticated) {
mState = STATE_STOPPED;
@@ -232,75 +224,14 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
}
}
@Override
public void onAuthenticated(
BiometricAuthenticator.Identifier identifier,
boolean authenticated,
ArrayList<Byte> token) {
mHandler.post(
() -> {
long delay = 0;
if (authenticated && mSensorProps.isAnySidefpsType()) {
delay = isKeyguard() ? mWaitForAuthKeyguard : mWaitForAuthBp;
if (mSideFpsLastAcquireStartTime != -1) {
delay = Math.max(0,
delay - (mClock.millis() - mSideFpsLastAcquireStartTime));
}
Slog.i(TAG, "(sideFPS) Auth succeeded, sideFps "
+ "waiting for power until: " + delay + "ms");
}
if (mHandler.hasMessages(MESSAGE_FINGER_UP)) {
Slog.i(TAG, "Finger up detected, sending auth");
delay = 0;
}
mAuthSuccessRunnable =
() -> handleAuthenticate(identifier, authenticated, token);
mHandler.postDelayed(
mAuthSuccessRunnable,
MESSAGE_AUTH_SUCCESS,
delay);
});
}
@Override
public void onAcquired(@FingerprintAcquired int acquiredInfo, int vendorCode) {
// For UDFPS, notify SysUI with acquiredInfo, so that the illumination can be turned off
// for most ACQUIRED messages. See BiometricFingerprintConstants#FingerprintAcquired
mSensorOverlays.ifUdfps(controller -> controller.onAcquired(getSensorId(), acquiredInfo));
super.onAcquired(acquiredInfo, vendorCode);
if (mSensorProps.isAnySidefpsType()) {
if (acquiredInfo == FINGERPRINT_ACQUIRED_START) {
mSideFpsLastAcquireStartTime = mClock.millis();
}
final boolean shouldLookForVendor =
mSkipWaitForPowerAcquireMessage == FINGERPRINT_ACQUIRED_VENDOR;
final boolean acquireMessageMatch = acquiredInfo == mSkipWaitForPowerAcquireMessage;
final boolean vendorMessageMatch = vendorCode == mSkipWaitForPowerVendorAcquireMessage;
final boolean ignorePowerPress =
acquireMessageMatch && (!shouldLookForVendor || vendorMessageMatch);
if (ignorePowerPress) {
Slog.d(TAG, "(sideFPS) onFingerUp");
mHandler.post(() -> {
if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) {
Slog.d(TAG, "(sideFPS) skipping wait for power");
mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
mHandler.post(mAuthSuccessRunnable);
} else {
mHandler.postDelayed(() -> {
}, MESSAGE_FINGER_UP, mFingerUpIgnoresPower);
}
});
}
}
PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId());
pt.incrementAcquireForUser(getTargetUserId(), isCryptoOperation());
}
@Override
@@ -495,22 +426,5 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
}
@Override
public void onPowerPressed() {
if (mSensorProps.isAnySidefpsType()) {
Slog.i(TAG, "(sideFPS): onPowerPressed");
mHandler.post(() -> {
if (mDidFinishSfps) {
return;
}
Slog.i(TAG, "(sideFPS): finishing auth");
// Ignore auths after a power has been detected
mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
// Do not call onError() as that will send an additional callback to coex.
mDidFinishSfps = true;
onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true);
stopHalOperation();
mSensorOverlays.hide(getSensorId());
});
}
}
public void onPowerPressed() { }
}

View File

@@ -41,7 +41,6 @@ import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -55,7 +54,6 @@ import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
@@ -398,274 +396,6 @@ public class FingerprintAuthenticationClientTest {
verify(mCancellationSignal).cancel();
}
@Test
public void fingerprintPowerIgnoresAuthInWindow() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
client.onPowerPressed();
client.onAuthenticated(new Fingerprint("friendly", 1 /* fingerId */, 2 /* deviceId */),
true /* authenticated */, new ArrayList<>());
mLooper.moveTimeForward(1000);
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(false));
verify(mCancellationSignal).cancel();
}
@Test
public void fingerprintAuthIgnoredWaitingForPower() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
client.onAuthenticated(new Fingerprint("friendly", 3 /* fingerId */, 4 /* deviceId */),
true /* authenticated */, new ArrayList<>());
client.onPowerPressed();
mLooper.moveTimeForward(1000);
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(false));
verify(mCancellationSignal).cancel();
}
@Test
public void fingerprintAuthFailsWhenAuthAfterPower() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
client.onPowerPressed();
mLooper.dispatchAll();
mLooper.moveTimeForward(1000);
mLooper.dispatchAll();
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
mLooper.dispatchAll();
mLooper.moveTimeForward(1000);
mLooper.dispatchAll();
verify(mCallback, never()).onClientFinished(any(), eq(true));
verify(mCallback).onClientFinished(any(), eq(false));
when(mHal.authenticateWithContext(anyLong(), any())).thenReturn(mCancellationSignal);
}
@Test
public void sideFingerprintDoesntSendAuthImmediately() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
mLooper.dispatchAll();
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
mLooper.dispatchAll();
verify(mCallback, never()).onClientFinished(any(), anyBoolean());
}
@Test
public void sideFingerprintSkipsWindowIfFingerUp() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
mLooper.dispatchAll();
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
client.onAcquired(FINGER_UP, 0);
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(true));
}
@Test
public void sideFingerprintSkipsWindowIfVendorMessageMatch() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
final int vendorAcquireMessage = 1234;
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsSkipWaitForPowerAcquireMessage,
FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR);
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsSkipWaitForPowerVendorAcquireMessage,
vendorAcquireMessage);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
mLooper.dispatchAll();
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR, vendorAcquireMessage);
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(true));
}
@Test
public void sideFingerprintDoesNotSkipWindowOnVendorErrorMismatch() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
final int vendorAcquireMessage = 1234;
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsSkipWaitForPowerAcquireMessage,
FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR);
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsSkipWaitForPowerVendorAcquireMessage,
vendorAcquireMessage);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
mLooper.dispatchAll();
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR, 1);
mLooper.dispatchAll();
verify(mCallback, never()).onClientFinished(any(), anyBoolean());
}
@Test
public void sideFingerprintSendsAuthIfFingerUp() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
mLooper.dispatchAll();
client.onAcquired(FINGER_UP, 0);
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(true));
}
@Test
public void sideFingerprintShortCircuitExpires() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
final int timeBeforeAuthSent = 500;
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsKeyguardPowerPressWindow, timeBeforeAuthSent);
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
mLooper.dispatchAll();
client.onAcquired(FINGER_UP, 0);
mLooper.dispatchAll();
mLooper.moveTimeForward(500);
mLooper.dispatchAll();
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
mLooper.dispatchAll();
verify(mCallback, never()).onClientFinished(any(), anyBoolean());
mLooper.moveTimeForward(500);
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(true));
}
@Test
public void sideFingerprintPowerWindowStartsOnAcquireStart() throws Exception {
final int powerWindow = 500;
final long authStart = 300;
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsBpPowerPressWindow, powerWindow);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
// Acquire start occurs at time = 0ms
when(mClock.millis()).thenReturn(0L);
client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_START, 0 /* vendorCode */);
// Auth occurs at time = 300
when(mClock.millis()).thenReturn(authStart);
// At this point the delay should be 500 - (300 - 0) == 200 milliseconds.
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
mLooper.dispatchAll();
verify(mCallback, never()).onClientFinished(any(), anyBoolean());
// After waiting 200 milliseconds, auth should succeed.
mLooper.moveTimeForward(powerWindow - authStart);
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(true));
}
@Test
public void sideFingerprintPowerWindowStartsOnLastAcquireStart() throws Exception {
final int powerWindow = 500;
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
mContext.getOrCreateTestableResources().addOverride(
R.integer.config_sidefpsBpPowerPressWindow, powerWindow);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
// Acquire start occurs at time = 0ms
when(mClock.millis()).thenReturn(0L);
client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_START, 0 /* vendorCode */);
// Auth reject occurs at time = 300ms
when(mClock.millis()).thenReturn(300L);
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
false /* authenticated */, new ArrayList<>());
mLooper.dispatchAll();
mLooper.moveTimeForward(300);
mLooper.dispatchAll();
verify(mCallback, never()).onClientFinished(any(), anyBoolean());
when(mClock.millis()).thenReturn(1300L);
client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_START, 0 /* vendorCode */);
// If code is correct, the new acquired start timestamp should be used
// and the code should only have to wait 500 - (1500-1300)ms.
when(mClock.millis()).thenReturn(1500L);
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
true /* authenticated */, new ArrayList<>());
mLooper.dispatchAll();
mLooper.moveTimeForward(299);
mLooper.dispatchAll();
verify(mCallback, never()).onClientFinished(any(), anyBoolean());
mLooper.moveTimeForward(1);
mLooper.dispatchAll();
verify(mCallback).onClientFinished(any(), eq(true));
}
@Test
public void sideFpsPowerPressCancelsIsntantly() throws Exception {
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
client.onPowerPressed();
mLooper.dispatchAll();
verify(mCallback, never()).onClientFinished(any(), eq(true));
verify(mCallback).onClientFinished(any(), eq(false));
}
private FingerprintAuthenticationClient createClient() throws RemoteException {
return createClient(100 /* version */, true /* allowBackgroundAuthentication */);
}