Merge "SideFPS UX updates" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
2ff2a64cfe
@@ -156,6 +156,11 @@ public interface BiometricConstants {
|
||||
*/
|
||||
int BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED = 18;
|
||||
|
||||
/**
|
||||
* A power press stopped this biometric operation.
|
||||
* @hide
|
||||
*/
|
||||
int BIOMETRIC_ERROR_POWER_PRESSED = 19;
|
||||
/**
|
||||
* This constant is only used by SystemUI. It notifies SystemUI that authentication was paused
|
||||
* because the authentication attempt was unsuccessful.
|
||||
|
||||
@@ -70,6 +70,7 @@ public interface BiometricFaceConstants {
|
||||
BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
|
||||
BIOMETRIC_ERROR_RE_ENROLL,
|
||||
FACE_ERROR_UNKNOWN,
|
||||
BIOMETRIC_ERROR_POWER_PRESSED,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface FaceError {}
|
||||
@@ -183,6 +184,12 @@ public interface BiometricFaceConstants {
|
||||
*/
|
||||
int FACE_ERROR_UNKNOWN = 17;
|
||||
|
||||
/**
|
||||
* A power press stopped this biometric operation.
|
||||
* @hide
|
||||
*/
|
||||
int BIOMETRIC_ERROR_POWER_PRESSED = 19;
|
||||
|
||||
/**
|
||||
* Vendor codes received from the HAL start at 0. Codes that the framework exposes to keyguard
|
||||
* append this value for some reason. We should probably remove this and just send the actual
|
||||
|
||||
@@ -61,7 +61,8 @@ public interface BiometricFingerprintConstants {
|
||||
BIOMETRIC_ERROR_RE_ENROLL,
|
||||
BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
|
||||
FINGERPRINT_ERROR_UNKNOWN,
|
||||
FINGERPRINT_ERROR_BAD_CALIBRATION})
|
||||
FINGERPRINT_ERROR_BAD_CALIBRATION,
|
||||
BIOMETRIC_ERROR_POWER_PRESSED})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface FingerprintError {}
|
||||
|
||||
@@ -187,6 +188,12 @@ public interface BiometricFingerprintConstants {
|
||||
*/
|
||||
int FINGERPRINT_ERROR_BAD_CALIBRATION = 18;
|
||||
|
||||
/**
|
||||
* A power press stopped this biometric operation.
|
||||
* @hide
|
||||
*/
|
||||
int BIOMETRIC_ERROR_POWER_PRESSED = 19;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -46,6 +46,14 @@ public abstract class BiometricStateListener extends IBiometricStateListener.Stu
|
||||
public @interface State {
|
||||
}
|
||||
|
||||
// The sensor received a touch.
|
||||
public static final int ACTION_SENSOR_TOUCH = 0;
|
||||
|
||||
@IntDef({ACTION_SENSOR_TOUCH})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines behavior in response to state update
|
||||
* @param newState new state of the biometric sensor
|
||||
@@ -53,6 +61,13 @@ public abstract class BiometricStateListener extends IBiometricStateListener.Stu
|
||||
public void onStateChanged(@BiometricStateListener.State int newState) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoked when a biometric action has occurred.
|
||||
*/
|
||||
public void onBiometricAction(@BiometricStateListener.Action int action) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when enrollment state changes for the specified user
|
||||
*/
|
||||
|
||||
@@ -22,5 +22,6 @@ package android.hardware.biometrics;
|
||||
*/
|
||||
oneway interface IBiometricStateListener {
|
||||
void onStateChanged(int newState);
|
||||
void onBiometricAction(int action);
|
||||
void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
private static final int MSG_FINGERPRINT_DETECTED = 107;
|
||||
private static final int MSG_UDFPS_POINTER_DOWN = 108;
|
||||
private static final int MSG_UDFPS_POINTER_UP = 109;
|
||||
private static final int MSG_POWER_BUTTON_PRESSED = 110;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -983,6 +984,16 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is triggered by SideFpsEventHandler
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
public void onPowerPressed() {
|
||||
Slog.i(TAG, "onPowerPressed");
|
||||
mHandler.obtainMessage(MSG_POWER_BUTTON_PRESSED).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if there is at least one fingerprint enrolled.
|
||||
*
|
||||
@@ -1196,6 +1207,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
case MSG_UDFPS_POINTER_UP:
|
||||
sendUdfpsPointerUp(msg.arg1 /* sensorId */);
|
||||
break;
|
||||
case MSG_POWER_BUTTON_PRESSED:
|
||||
sendPowerPressed();
|
||||
break;
|
||||
default:
|
||||
Slog.w(TAG, "Unknown message: " + msg.what);
|
||||
|
||||
@@ -1325,6 +1339,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
mAuthenticationCallback.onUdfpsPointerUp(sensorId);
|
||||
}
|
||||
|
||||
private void sendPowerPressed() {
|
||||
try {
|
||||
mService.onPowerPressed();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error sending power press", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -1461,6 +1483,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
case FINGERPRINT_ERROR_BAD_CALIBRATION:
|
||||
return context.getString(
|
||||
com.android.internal.R.string.fingerprint_error_bad_calibration);
|
||||
case BIOMETRIC_ERROR_POWER_PRESSED:
|
||||
return context.getString(
|
||||
com.android.internal.R.string.fingerprint_error_power_pressed);
|
||||
case FINGERPRINT_ERROR_VENDOR: {
|
||||
String[] msgArray = context.getResources().getStringArray(
|
||||
com.android.internal.R.array.fingerprint_error_vendor);
|
||||
|
||||
@@ -171,4 +171,7 @@ interface IFingerprintService {
|
||||
|
||||
// Registers BiometricStateListener.
|
||||
void registerBiometricStateListener(IBiometricStateListener listener);
|
||||
|
||||
// Sends a power button pressed event to all listeners.
|
||||
oneway void onPowerPressed();
|
||||
}
|
||||
|
||||
@@ -9703,6 +9703,43 @@ public final class Settings {
|
||||
@Readable
|
||||
public static final String FACE_UNLOCK_RE_ENROLL = "face_unlock_re_enroll";
|
||||
|
||||
/**
|
||||
* The time (in millis) to wait for a power button before sending a
|
||||
* successful auth in to keyguard(for side fingerprint)
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String FINGERPRINT_SIDE_FPS_KG_POWER_WINDOW =
|
||||
"fingerprint_side_fps_kg_power_window";
|
||||
|
||||
/**
|
||||
* The time (in millis) to wait for a power button before sending
|
||||
* a successful auth in biometric prompt(for side fingerprint)
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW =
|
||||
"fingerprint_side_fps_bp_power_window";
|
||||
|
||||
/**
|
||||
* The time (in millis) that a finger tap will wait for a power button
|
||||
* before dismissing the power dialog during enrollment(for side
|
||||
* fingerprint)
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW =
|
||||
"fingerprint_side_fps_enroll_tap_window";
|
||||
|
||||
/**
|
||||
* The time (in millis) that a power event will ignore future authentications
|
||||
* (for side fingerprint)
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME =
|
||||
"fingerprint_side_fps_auth_downtime";
|
||||
|
||||
/**
|
||||
* Whether or not debugging is enabled.
|
||||
* @hide
|
||||
|
||||
@@ -3498,6 +3498,22 @@
|
||||
<!-- Specify if the fingerprint hardware support gestures-->
|
||||
<bool name="config_fingerprintSupportsGestures">false</bool>
|
||||
|
||||
<!-- The time (in millis) to wait for a power button before sending
|
||||
a successful auth in biometric prompt(for side fingerprint) -->
|
||||
<integer name="config_sidefpsBpPowerPressWindow">300</integer>
|
||||
|
||||
<!-- The time (in millis) to wait for a power button before sending a
|
||||
successful auth in to keyguard(for side fingerprint) -->
|
||||
<integer name="config_sidefpsKeyguardPowerPressWindow">300</integer>
|
||||
|
||||
<!-- The time (in millis) that a power event will ignore future authentications
|
||||
(for side fingerprint) -->
|
||||
<integer name="config_sidefpsPostAuthDowntime">400</integer>
|
||||
|
||||
<!-- The time (in millis) that a finger tap will wait for a power button
|
||||
before dismissing the power dialog during enrollment(for side fingerprint) -->
|
||||
<integer name="config_sidefpsEnrollPowerPressWindow">300</integer>
|
||||
|
||||
<!-- This config is used to force VoiceInteractionService to start on certain low ram devices.
|
||||
It declares the package name of VoiceInteractionService that should be started. -->
|
||||
<string translatable="false" name="config_forceVoiceInteractionServicePackage"></string>
|
||||
|
||||
@@ -1751,6 +1751,8 @@
|
||||
<string name="fingerprint_error_security_update_required">Sensor temporarily disabled.</string>
|
||||
<!-- Generic error message shown when fingerprint needs calibration [CHAR LIMIT=150] -->
|
||||
<string name="fingerprint_error_bad_calibration">Can\u2019t use fingerprint sensor. Visit a repair provider</string>
|
||||
<!-- Generic error message shown when the power button has been pressed. [CHAR LIMIT=150] -->
|
||||
<string name="fingerprint_error_power_pressed">Power button pressed</string>
|
||||
|
||||
<!-- Template to be used to name enrolled fingerprints by default. -->
|
||||
<string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string>
|
||||
|
||||
@@ -2622,10 +2622,15 @@
|
||||
<java-symbol type="string" name="fingerprint_recalibrate_notification_name" />
|
||||
<java-symbol type="string" name="fingerprint_recalibrate_notification_title" />
|
||||
<java-symbol type="string" name="fingerprint_recalibrate_notification_content" />
|
||||
<java-symbol type="string" name="fingerprint_error_power_pressed" />
|
||||
|
||||
<!-- Fingerprint config -->
|
||||
<java-symbol type="integer" name="config_fingerprintMaxTemplatesPerUser"/>
|
||||
<java-symbol type="bool" name="config_fingerprintSupportsGestures"/>
|
||||
<java-symbol type="integer" name="config_sidefpsBpPowerPressWindow"/>
|
||||
<java-symbol type="integer" name="config_sidefpsKeyguardPowerPressWindow"/>
|
||||
<java-symbol type="integer" name="config_sidefpsPostAuthDowntime"/>
|
||||
<java-symbol type="integer" name="config_sidefpsEnrollPowerPressWindow"/>
|
||||
|
||||
<!-- Face authentication messages -->
|
||||
<java-symbol type="string" name="face_recalibrate_notification_name" />
|
||||
|
||||
@@ -118,6 +118,10 @@ public class SecureSettings {
|
||||
Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
|
||||
Settings.Secure.FACE_UNLOCK_APP_ENABLED,
|
||||
Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
|
||||
Settings.Secure.FINGERPRINT_SIDE_FPS_KG_POWER_WINDOW,
|
||||
Settings.Secure.FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW,
|
||||
Settings.Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW,
|
||||
Settings.Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME,
|
||||
Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
|
||||
Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
|
||||
Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
|
||||
|
||||
@@ -172,6 +172,11 @@ public class SecureSettingsValidators {
|
||||
Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, NON_NEGATIVE_INTEGER_VALIDATOR);
|
||||
VALIDATORS.put(Secure.FACE_UNLOCK_KEYGUARD_ENABLED, BOOLEAN_VALIDATOR);
|
||||
VALIDATORS.put(Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, BOOLEAN_VALIDATOR);
|
||||
VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_KG_POWER_WINDOW, NON_NEGATIVE_INTEGER_VALIDATOR);
|
||||
VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW, NON_NEGATIVE_INTEGER_VALIDATOR);
|
||||
VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW,
|
||||
NON_NEGATIVE_INTEGER_VALIDATOR);
|
||||
VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME, NON_NEGATIVE_INTEGER_VALIDATOR);
|
||||
VALIDATORS.put(Secure.SHOW_MEDIA_WHEN_BYPASSING, BOOLEAN_VALIDATOR);
|
||||
VALIDATORS.put(Secure.FACE_UNLOCK_APP_ENABLED, BOOLEAN_VALIDATOR);
|
||||
VALIDATORS.put(Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, BOOLEAN_VALIDATOR);
|
||||
|
||||
@@ -805,8 +805,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
private Runnable mRetryFingerprintAuthentication = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.w(TAG, "Retrying fingerprint after HW unavailable, attempt " +
|
||||
mHardwareFingerprintUnavailableRetryCount);
|
||||
Log.w(TAG,
|
||||
"Retrying fingerprint attempt: " + mHardwareFingerprintUnavailableRetryCount);
|
||||
if (mFpm.isHardwareDetected()) {
|
||||
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
|
||||
} else if (mHardwareFingerprintUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
|
||||
@@ -833,7 +833,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
|
||||
}
|
||||
|
||||
if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
|
||||
if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE
|
||||
|| msgId == FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED) {
|
||||
Log.d(TAG, "Fingerprint retrying auth due to(" + msgId + ") -> " + errString);
|
||||
mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,17 @@ public class BiometricStateCallback implements ClientMonitorCallback {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricAction(@BiometricStateListener.Action int action) {
|
||||
for (IBiometricStateListener listener : mBiometricStateListeners) {
|
||||
try {
|
||||
listener.onBiometricAction(action);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception in onBiometricAction", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be invoked when:
|
||||
* 1) Enrolled --> None-enrolled
|
||||
|
||||
@@ -30,6 +30,11 @@ public interface ClientMonitorCallback {
|
||||
*/
|
||||
default void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {}
|
||||
|
||||
/**
|
||||
* Invoked when a biometric action has occurred.
|
||||
*/
|
||||
default void onBiometricAction(int action) {}
|
||||
|
||||
/**
|
||||
* Invoked when the ClientMonitor operation is complete. This abstracts away asynchronous
|
||||
* (i.e. Authenticate, Enroll, Enumerate, Remove) and synchronous (i.e. generateChallenge,
|
||||
|
||||
@@ -43,6 +43,13 @@ public class ClientMonitorCompositeCallback implements ClientMonitorCallback {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onBiometricAction(int action) {
|
||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||
mCallbacks.get(i).onBiometricAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
|
||||
boolean success) {
|
||||
|
||||
@@ -1020,9 +1020,18 @@ public class FingerprintService extends SystemService {
|
||||
|
||||
@Override
|
||||
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
|
||||
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
|
||||
FingerprintService.this.registerBiometricStateListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPowerPressed() {
|
||||
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
|
||||
for (ServiceProvider provider : mServiceProviders) {
|
||||
provider.onPowerPressed();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public FingerprintService(Context context) {
|
||||
super(context);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.server.biometrics.sensors.fingerprint;
|
||||
|
||||
/**
|
||||
* Interface for handling power presses.
|
||||
*/
|
||||
public interface PowerPressHandler {
|
||||
/**
|
||||
* Indicates a power press has occurred.
|
||||
*/
|
||||
void onPowerPressed();
|
||||
}
|
||||
@@ -150,6 +150,8 @@ public interface ServiceProvider {
|
||||
|
||||
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
|
||||
|
||||
void onPowerPressed();
|
||||
|
||||
/**
|
||||
* Sets side-fps controller
|
||||
* @param controller side-fps controller
|
||||
|
||||
@@ -21,6 +21,7 @@ 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.common.ICancellationSignal;
|
||||
@@ -29,10 +30,15 @@ import android.hardware.biometrics.fingerprint.PointerContext;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.ISidefpsController;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
|
||||
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;
|
||||
@@ -46,17 +52,18 @@ import com.android.server.biometrics.sensors.LockoutCache;
|
||||
import com.android.server.biometrics.sensors.LockoutConsumer;
|
||||
import com.android.server.biometrics.sensors.LockoutTracker;
|
||||
import com.android.server.biometrics.sensors.SensorOverlays;
|
||||
import com.android.server.biometrics.sensors.fingerprint.PowerPressHandler;
|
||||
import com.android.server.biometrics.sensors.fingerprint.Udfps;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Fingerprint-specific authentication client supporting the
|
||||
* {@link android.hardware.biometrics.fingerprint.IFingerprint} AIDL interface.
|
||||
* Fingerprint-specific authentication client supporting the {@link
|
||||
* android.hardware.biometrics.fingerprint.IFingerprint} AIDL interface.
|
||||
*/
|
||||
class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> implements
|
||||
Udfps, LockoutConsumer {
|
||||
class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
implements Udfps, LockoutConsumer, PowerPressHandler {
|
||||
private static final String TAG = "FingerprintAuthenticationClient";
|
||||
|
||||
@NonNull private final LockoutCache mLockoutCache;
|
||||
@@ -64,33 +71,88 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
@NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
|
||||
@NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
|
||||
|
||||
@Nullable private ICancellationSignal mCancellationSignal;
|
||||
@Nullable
|
||||
private ICancellationSignal mCancellationSignal;
|
||||
private boolean mIsPointerDown;
|
||||
private final Handler mHandler;
|
||||
|
||||
FingerprintAuthenticationClient(@NonNull Context context,
|
||||
private static final int MESSAGE_IGNORE_AUTH = 1;
|
||||
private static final int MESSAGE_AUTH_SUCCESS = 2;
|
||||
private long mWaitForAuthKeyguard;
|
||||
private long mWaitForAuthBp;
|
||||
private long mIgnoreAuthFor;
|
||||
|
||||
FingerprintAuthenticationClient(
|
||||
@NonNull Context context,
|
||||
@NonNull Supplier<AidlSession> lazyDaemon,
|
||||
@NonNull IBinder token, long requestId,
|
||||
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
|
||||
boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
|
||||
@NonNull IBinder token,
|
||||
long requestId,
|
||||
@NonNull ClientMonitorCallbackConverter listener,
|
||||
int targetUserId,
|
||||
long operationId,
|
||||
boolean restricted,
|
||||
@NonNull String owner,
|
||||
int cookie,
|
||||
boolean requireConfirmation,
|
||||
int sensorId,
|
||||
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
|
||||
@NonNull BiometricLogger biometricLogger,
|
||||
@NonNull BiometricContext biometricContext,
|
||||
boolean isStrongBiometric,
|
||||
@Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache,
|
||||
@Nullable TaskStackListener taskStackListener,
|
||||
@NonNull LockoutCache lockoutCache,
|
||||
@Nullable IUdfpsOverlayController udfpsOverlayController,
|
||||
@Nullable ISidefpsController sidefpsController,
|
||||
boolean allowBackgroundAuthentication,
|
||||
@NonNull FingerprintSensorPropertiesInternal sensorProps) {
|
||||
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
|
||||
cookie, requireConfirmation, sensorId,
|
||||
biometricLogger, biometricContext,
|
||||
isStrongBiometric, taskStackListener,
|
||||
lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
|
||||
@NonNull FingerprintSensorPropertiesInternal sensorProps,
|
||||
@NonNull Handler handler) {
|
||||
super(
|
||||
context,
|
||||
lazyDaemon,
|
||||
token,
|
||||
listener,
|
||||
targetUserId,
|
||||
operationId,
|
||||
restricted,
|
||||
owner,
|
||||
cookie,
|
||||
requireConfirmation,
|
||||
sensorId,
|
||||
biometricLogger,
|
||||
biometricContext,
|
||||
isStrongBiometric,
|
||||
taskStackListener,
|
||||
lockoutCache,
|
||||
allowBackgroundAuthentication,
|
||||
true /* shouldVibrate */,
|
||||
false /* isKeyguardBypassEnabled */);
|
||||
setRequestId(requestId);
|
||||
mLockoutCache = lockoutCache;
|
||||
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
||||
mSensorProps = sensorProps;
|
||||
mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
|
||||
mHandler = handler;
|
||||
|
||||
mWaitForAuthKeyguard =
|
||||
context.getResources()
|
||||
.getInteger(R.integer.config_sidefpsKeyguardPowerPressWindow);
|
||||
mWaitForAuthBp =
|
||||
context.getResources().getInteger(R.integer.config_sidefpsBpPowerPressWindow);
|
||||
mIgnoreAuthFor =
|
||||
context.getResources().getInteger(R.integer.config_sidefpsPostAuthDowntime);
|
||||
|
||||
if (mSensorProps.isAnySidefpsType()) {
|
||||
if (Build.isDebuggable()) {
|
||||
mWaitForAuthKeyguard = Settings.Secure.getIntForUser(context.getContentResolver(),
|
||||
Settings.Secure.FINGERPRINT_SIDE_FPS_KG_POWER_WINDOW,
|
||||
(int) mWaitForAuthKeyguard, UserHandle.USER_CURRENT);
|
||||
mWaitForAuthBp = Settings.Secure.getIntForUser(context.getContentResolver(),
|
||||
Settings.Secure.FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW, (int) mWaitForAuthBp,
|
||||
UserHandle.USER_CURRENT);
|
||||
mIgnoreAuthFor = Settings.Secure.getIntForUser(context.getContentResolver(),
|
||||
Settings.Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME, (int) mIgnoreAuthFor,
|
||||
UserHandle.USER_CURRENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,8 +170,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
@NonNull
|
||||
@Override
|
||||
protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
|
||||
return new ClientMonitorCompositeCallback(mALSProbeCallback,
|
||||
getBiometricContextUnsubscriber(), callback);
|
||||
return new ClientMonitorCompositeCallback(
|
||||
mALSProbeCallback, getBiometricContextUnsubscriber(), callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,16 +188,37 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
|
||||
boolean authenticated, ArrayList<Byte> token) {
|
||||
super.onAuthenticated(identifier, authenticated, token);
|
||||
public void onAuthenticated(
|
||||
BiometricAuthenticator.Identifier identifier,
|
||||
boolean authenticated,
|
||||
ArrayList<Byte> token) {
|
||||
|
||||
if (authenticated) {
|
||||
mState = STATE_STOPPED;
|
||||
mSensorOverlays.hide(getSensorId());
|
||||
} else {
|
||||
mState = STATE_STARTED_PAUSED_ATTEMPTED;
|
||||
long delay = 0;
|
||||
if (authenticated && mSensorProps.isAnySidefpsType()) {
|
||||
if (mHandler.hasMessages(MESSAGE_IGNORE_AUTH)) {
|
||||
Slog.i(TAG, "(sideFPS) Ignoring auth due to recent power press");
|
||||
onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true);
|
||||
return;
|
||||
}
|
||||
delay = isKeyguard() ? mWaitForAuthKeyguard : mWaitForAuthBp;
|
||||
Slog.i(TAG, "(sideFPS) Auth succeeded, sideFps waiting for power until: " + delay);
|
||||
}
|
||||
|
||||
mHandler.postDelayed(
|
||||
() -> {
|
||||
if (authenticated && mSensorProps.isAnySidefpsType()) {
|
||||
Slog.i(TAG, "(sideFPS): No power press detected, sending auth");
|
||||
}
|
||||
super.onAuthenticated(identifier, authenticated, token);
|
||||
if (authenticated) {
|
||||
mState = STATE_STOPPED;
|
||||
mSensorOverlays.hide(getSensorId());
|
||||
} else {
|
||||
mState = STATE_STARTED_PAUSED_ATTEMPTED;
|
||||
}
|
||||
},
|
||||
MESSAGE_AUTH_SUCCESS,
|
||||
delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,7 +248,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
mCancellationSignal = doAuthenticate();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
|
||||
onError(
|
||||
BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
mSensorOverlays.hide(getSensorId());
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
@@ -177,15 +261,18 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
|
||||
if (session.hasContextMethods()) {
|
||||
final OperationContext opContext = getOperationContext();
|
||||
final ICancellationSignal cancel = session.getSession().authenticateWithContext(
|
||||
mOperationId, opContext);
|
||||
getBiometricContext().subscribe(opContext, ctx -> {
|
||||
try {
|
||||
session.getSession().onContextChanged(ctx);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to notify context changed", e);
|
||||
}
|
||||
});
|
||||
final ICancellationSignal cancel =
|
||||
session.getSession().authenticateWithContext(mOperationId, opContext);
|
||||
getBiometricContext()
|
||||
.subscribe(
|
||||
opContext,
|
||||
ctx -> {
|
||||
try {
|
||||
session.getSession().onContextChanged(ctx);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to notify context changed", e);
|
||||
}
|
||||
});
|
||||
return cancel;
|
||||
} else {
|
||||
return session.getSession().authenticate(mOperationId);
|
||||
@@ -202,7 +289,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
mCancellationSignal.cancel();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
|
||||
onError(
|
||||
BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
@@ -284,8 +372,13 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
|
||||
// Lockout metrics are logged as an error code.
|
||||
final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
|
||||
getLogger().logOnError(getContext(), getOperationContext(),
|
||||
error, 0 /* vendorCode */, getTargetUserId());
|
||||
getLogger()
|
||||
.logOnError(
|
||||
getContext(),
|
||||
getOperationContext(),
|
||||
error,
|
||||
0 /* vendorCode */,
|
||||
getTargetUserId());
|
||||
|
||||
try {
|
||||
getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
|
||||
@@ -303,8 +396,13 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
|
||||
// Lockout metrics are logged as an error code.
|
||||
final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
|
||||
getLogger().logOnError(getContext(), getOperationContext(),
|
||||
error, 0 /* vendorCode */, getTargetUserId());
|
||||
getLogger()
|
||||
.logOnError(
|
||||
getContext(),
|
||||
getOperationContext(),
|
||||
error,
|
||||
0 /* vendorCode */,
|
||||
getTargetUserId());
|
||||
|
||||
try {
|
||||
getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
|
||||
@@ -315,4 +413,19 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
|
||||
mSensorOverlays.hide(getSensorId());
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPowerPressed() {
|
||||
if (mSensorProps.isAnySidefpsType()) {
|
||||
Slog.i(TAG, "(sideFPS): onPowerPressed");
|
||||
if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) {
|
||||
Slog.i(TAG, "(sideFPS): Ignoring auth in queue");
|
||||
mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
|
||||
// Do not call onError() as that will send an additional callback to coex.
|
||||
onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true);
|
||||
}
|
||||
mHandler.removeMessages(MESSAGE_IGNORE_AUTH);
|
||||
mHandler.postDelayed(() -> {}, MESSAGE_IGNORE_AUTH, mIgnoreAuthFor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.biometrics.BiometricFingerprintConstants;
|
||||
import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired;
|
||||
import android.hardware.biometrics.BiometricStateListener;
|
||||
import android.hardware.biometrics.common.ICancellationSignal;
|
||||
import android.hardware.biometrics.common.OperationContext;
|
||||
import android.hardware.biometrics.fingerprint.PointerContext;
|
||||
@@ -139,7 +140,7 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
|
||||
controller.onEnrollmentHelp(getSensorId());
|
||||
}
|
||||
});
|
||||
|
||||
mCallback.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
||||
super.onAcquired(acquiredInfo, vendorCode);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ import com.android.server.biometrics.sensors.LockoutResetDispatcher;
|
||||
import com.android.server.biometrics.sensors.PerformanceTracker;
|
||||
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
|
||||
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
|
||||
import com.android.server.biometrics.sensors.fingerprint.PowerPressHandler;
|
||||
import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
|
||||
import com.android.server.biometrics.sensors.fingerprint.Udfps;
|
||||
|
||||
@@ -387,6 +388,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mBiometricStateCallback.onClientStarted(clientMonitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricAction(int action) {
|
||||
mBiometricStateCallback.onBiometricAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
|
||||
boolean success) {
|
||||
@@ -441,7 +447,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mBiometricContext, isStrongBiometric,
|
||||
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
|
||||
mUdfpsOverlayController, mSidefpsController, allowBackgroundAuthentication,
|
||||
mSensors.get(sensorId).getSensorProperties());
|
||||
mSensors.get(sensorId).getSensorProperties(), mHandler);
|
||||
scheduleForSensor(sensorId, client, mBiometricStateCallback);
|
||||
});
|
||||
}
|
||||
@@ -613,6 +619,21 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
||||
mUdfpsOverlayController = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPowerPressed() {
|
||||
for (int i = 0; i < mSensors.size(); i++) {
|
||||
final Sensor sensor = mSensors.valueAt(i);
|
||||
BaseClientMonitor client = sensor.getScheduler().getCurrentClient();
|
||||
if (client == null) {
|
||||
return;
|
||||
}
|
||||
if (!(client instanceof PowerPressHandler)) {
|
||||
continue;
|
||||
}
|
||||
((PowerPressHandler) client).onPowerPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSidefpsController(@NonNull ISidefpsController controller) {
|
||||
mSidefpsController = controller;
|
||||
|
||||
@@ -602,6 +602,11 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
mBiometricStateCallback.onClientStarted(clientMonitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricAction(int action) {
|
||||
mBiometricStateCallback.onBiometricAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
|
||||
boolean success) {
|
||||
@@ -820,6 +825,11 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPowerPressed() {
|
||||
Slog.e(TAG, "onPowerPressed not supported for HIDL clients");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
|
||||
mUdfpsOverlayController = controller;
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.biometrics.BiometricFingerprintConstants;
|
||||
import android.hardware.biometrics.BiometricStateListener;
|
||||
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
|
||||
import android.hardware.fingerprint.Fingerprint;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
@@ -151,6 +152,8 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
|
||||
controller.onEnrollmentHelp(getSensorId());
|
||||
}
|
||||
});
|
||||
|
||||
mCallback.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -949,6 +949,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
|
||||
private void powerPress(long eventTime, int count, boolean beganFromNonInteractive) {
|
||||
// SideFPS still needs to know about suppressed power buttons, in case it needs to block
|
||||
// an auth attempt.
|
||||
if (count == 1) {
|
||||
mSideFpsEventHandler.notifyPowerPressed();
|
||||
}
|
||||
if (mDefaultDisplayPolicy.isScreenOnEarly() && !mDefaultDisplayPolicy.isScreenOnFully()) {
|
||||
Slog.i(TAG, "Suppressed redundant power key press while "
|
||||
+ "already in the process of turning the screen on.");
|
||||
@@ -968,7 +973,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
} else if (count > 3 && count <= getMaxMultiPressPowerCount()) {
|
||||
Slog.d(TAG, "No behavior defined for power press count " + count);
|
||||
} else if (count == 1 && interactive && !beganFromNonInteractive) {
|
||||
if (mSideFpsEventHandler.onSinglePressDetected(eventTime)) {
|
||||
if (mSideFpsEventHandler.shouldConsumeSinglePress(eventTime)) {
|
||||
Slog.i(TAG, "Suppressing power key because the user is interacting with the "
|
||||
+ "fingerprint sensor");
|
||||
return;
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.policy;
|
||||
import static android.hardware.biometrics.BiometricStateListener.STATE_BP_AUTH;
|
||||
import static android.hardware.biometrics.BiometricStateListener.STATE_ENROLLING;
|
||||
import static android.hardware.biometrics.BiometricStateListener.STATE_IDLE;
|
||||
import static android.hardware.biometrics.BiometricStateListener.STATE_KEYGUARD_AUTH;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -34,8 +35,12 @@ import android.hardware.biometrics.BiometricStateListener;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -46,14 +51,26 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Defines behavior for handling interactions between power button events and
|
||||
* fingerprint-related operations, for devices where the fingerprint sensor (side fps)
|
||||
* lives on the power button.
|
||||
* Defines behavior for handling interactions between power button events and fingerprint-related
|
||||
* operations, for devices where the fingerprint sensor (side fps) lives on the power button.
|
||||
*/
|
||||
public class SideFpsEventHandler {
|
||||
|
||||
private static final int DEBOUNCE_DELAY_MILLIS = 500;
|
||||
|
||||
private int getTapWaitForPowerDuration(Context context) {
|
||||
int tap = context.getResources().getInteger(
|
||||
R.integer.config_sidefpsEnrollPowerPressWindow);
|
||||
if (Build.isDebuggable()) {
|
||||
tap = Settings.Secure.getIntForUser(context.getContentResolver(),
|
||||
Settings.Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW, tap,
|
||||
UserHandle.USER_CURRENT);
|
||||
}
|
||||
return tap;
|
||||
}
|
||||
|
||||
private static final String TAG = "SideFpsEventHandler";
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final PowerManager mPowerManager;
|
||||
@@ -61,20 +78,26 @@ public class SideFpsEventHandler {
|
||||
@NonNull private final AtomicBoolean mSideFpsEventHandlerReady;
|
||||
|
||||
@Nullable private Dialog mDialog;
|
||||
@NonNull private final DialogInterface.OnDismissListener mDialogDismissListener = (dialog) -> {
|
||||
if (mDialog == dialog) {
|
||||
mDialog = null;
|
||||
}
|
||||
};
|
||||
private final Runnable mTurnOffDialog =
|
||||
() -> {
|
||||
dismissDialog("mTurnOffDialog");
|
||||
};
|
||||
|
||||
@NonNull private final DialogInterface.OnDismissListener mDialogDismissListener;
|
||||
|
||||
private @BiometricStateListener.State int mBiometricState;
|
||||
private final int mTapWaitForPowerDuration;
|
||||
private FingerprintManager mFingerprintManager;
|
||||
|
||||
SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) {
|
||||
this(context, handler, powerManager, () -> new AlertDialog.Builder(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager,
|
||||
SideFpsEventHandler(
|
||||
Context context,
|
||||
Handler handler,
|
||||
PowerManager powerManager,
|
||||
Supplier<AlertDialog.Builder> dialogSupplier) {
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
@@ -82,91 +105,131 @@ public class SideFpsEventHandler {
|
||||
mDialogSupplier = dialogSupplier;
|
||||
mBiometricState = STATE_IDLE;
|
||||
mSideFpsEventHandlerReady = new AtomicBoolean(false);
|
||||
mDialogDismissListener =
|
||||
(dialog) -> {
|
||||
if (mDialog == dialog) {
|
||||
if (mHandler != null) {
|
||||
mHandler.removeCallbacks(mTurnOffDialog);
|
||||
}
|
||||
mDialog = null;
|
||||
}
|
||||
};
|
||||
|
||||
// ensure dialog is dismissed if screen goes off for unrelated reasons
|
||||
context.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
}
|
||||
}
|
||||
}, new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
||||
context.registerReceiver(
|
||||
new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
||||
mTapWaitForPowerDuration = getTapWaitForPowerDuration(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from {@link PhoneWindowManager} after the power button is pressed and displays a
|
||||
* dialog confirming the user's intent to turn screen off if a fingerprint operation is
|
||||
* active. The device goes to sleep if confirmed otherwise the dialog is dismissed.
|
||||
* Called from {@link PhoneWindowManager} to notify FingerprintManager that a single tap power
|
||||
* button has been pressed.
|
||||
*/
|
||||
public void notifyPowerPressed() {
|
||||
Log.i(TAG, "notifyPowerPressed");
|
||||
if (mFingerprintManager == null) {
|
||||
mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
|
||||
}
|
||||
if (mFingerprintManager == null) {
|
||||
return;
|
||||
}
|
||||
mFingerprintManager.onPowerPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from {@link PhoneWindowManager} and will dictate if the SideFpsEventHandler should
|
||||
* handle the power press.
|
||||
*
|
||||
* @param eventTime powerPress event time
|
||||
* @return true if powerPress was consumed, false otherwise
|
||||
*/
|
||||
public boolean onSinglePressDetected(long eventTime) {
|
||||
public boolean shouldConsumeSinglePress(long eventTime) {
|
||||
if (!mSideFpsEventHandlerReady.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (mBiometricState) {
|
||||
case STATE_ENROLLING:
|
||||
case STATE_BP_AUTH:
|
||||
mHandler.post(() -> {
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
}
|
||||
mDialog = showConfirmDialog(mDialogSupplier.get(),
|
||||
mPowerManager, eventTime, mBiometricState, mDialogDismissListener);
|
||||
});
|
||||
mHandler.post(
|
||||
() -> {
|
||||
if (mHandler.hasCallbacks(mTurnOffDialog)) {
|
||||
Log.v(TAG, "Detected a tap to turn off dialog, ignoring");
|
||||
mHandler.removeCallbacks(mTurnOffDialog);
|
||||
}
|
||||
});
|
||||
showDialog(eventTime, "Enroll Power Press");
|
||||
return true;
|
||||
case STATE_BP_AUTH:
|
||||
return true;
|
||||
case STATE_KEYGUARD_AUTH:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Dialog showConfirmDialog(@NonNull AlertDialog.Builder dialogBuilder,
|
||||
@NonNull PowerManager powerManager, long eventTime,
|
||||
private static Dialog showConfirmDialog(
|
||||
@NonNull AlertDialog.Builder dialogBuilder,
|
||||
@NonNull PowerManager powerManager,
|
||||
long eventTime,
|
||||
@BiometricStateListener.State int biometricState,
|
||||
@NonNull DialogInterface.OnDismissListener dismissListener) {
|
||||
final boolean enrolling = biometricState == STATE_ENROLLING;
|
||||
final int title = enrolling ? R.string.fp_power_button_enrollment_title
|
||||
: R.string.fp_power_button_bp_title;
|
||||
final int message = enrolling ? R.string.fp_power_button_enrollment_message
|
||||
: R.string.fp_power_button_bp_message;
|
||||
final int positiveText = enrolling ? R.string.fp_power_button_enrollment_positive_button
|
||||
: R.string.fp_power_button_bp_positive_button;
|
||||
final int negativeText = enrolling ? R.string.fp_power_button_enrollment_negative_button
|
||||
: R.string.fp_power_button_bp_negative_button;
|
||||
final int title =
|
||||
enrolling
|
||||
? R.string.fp_power_button_enrollment_title
|
||||
: R.string.fp_power_button_bp_title;
|
||||
final int message =
|
||||
enrolling
|
||||
? R.string.fp_power_button_enrollment_message
|
||||
: R.string.fp_power_button_bp_message;
|
||||
final int positiveText =
|
||||
enrolling
|
||||
? R.string.fp_power_button_enrollment_positive_button
|
||||
: R.string.fp_power_button_bp_positive_button;
|
||||
final int negativeText =
|
||||
enrolling
|
||||
? R.string.fp_power_button_enrollment_negative_button
|
||||
: R.string.fp_power_button_bp_negative_button;
|
||||
|
||||
final Dialog confirmScreenOffDialog = dialogBuilder
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(positiveText,
|
||||
(dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
powerManager.goToSleep(
|
||||
eventTime,
|
||||
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
|
||||
0 /* flags */
|
||||
);
|
||||
})
|
||||
.setNegativeButton(negativeText, (dialog, which) -> dialog.dismiss())
|
||||
.setOnDismissListener(dismissListener)
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
confirmScreenOffDialog.getWindow().setType(
|
||||
WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
|
||||
final Dialog confirmScreenOffDialog =
|
||||
dialogBuilder
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(
|
||||
positiveText,
|
||||
(dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
powerManager.goToSleep(
|
||||
eventTime,
|
||||
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
|
||||
0 /* flags */);
|
||||
})
|
||||
.setNegativeButton(negativeText, (dialog, which) -> dialog.dismiss())
|
||||
.setOnDismissListener(dismissListener)
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
confirmScreenOffDialog
|
||||
.getWindow()
|
||||
.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
|
||||
confirmScreenOffDialog.show();
|
||||
|
||||
return confirmScreenOffDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Awaits notification from PhoneWindowManager that fingerprint service is ready
|
||||
* to send updates about power button fps sensor state. Then configures a
|
||||
* BiometricStateListener to receive and record updates to fps state, and
|
||||
* registers the BiometricStateListener in FingerprintManager.
|
||||
* Awaits notification from PhoneWindowManager that fingerprint service is ready to send updates
|
||||
* about power button fps sensor state. Then configures a BiometricStateListener to receive and
|
||||
* record updates to fps state, and registers the BiometricStateListener in FingerprintManager.
|
||||
*/
|
||||
public void onFingerprintSensorReady() {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
@@ -184,12 +247,12 @@ public class SideFpsEventHandler {
|
||||
if (fingerprintManager.isPowerbuttonFps()) {
|
||||
fingerprintManager.registerBiometricStateListener(
|
||||
new BiometricStateListener() {
|
||||
@Nullable
|
||||
private Runnable mStateRunnable = null;
|
||||
@Nullable private Runnable mStateRunnable = null;
|
||||
|
||||
@Override
|
||||
public void onStateChanged(
|
||||
@BiometricStateListener.State int newState) {
|
||||
Log.d(TAG, "onStateChanged : " + newState);
|
||||
if (mStateRunnable != null) {
|
||||
mHandler.removeCallbacks(mStateRunnable);
|
||||
mStateRunnable = null;
|
||||
@@ -200,16 +263,58 @@ public class SideFpsEventHandler {
|
||||
// damper when moving to idle in case auth is first
|
||||
if (newState == STATE_IDLE) {
|
||||
mStateRunnable = () -> mBiometricState = newState;
|
||||
mHandler.postDelayed(mStateRunnable,
|
||||
DEBOUNCE_DELAY_MILLIS);
|
||||
// This is also useful in the case of biometric
|
||||
// prompt.
|
||||
// If a user has recently succeeded/failed auth, we
|
||||
// want to disable the power button for a short
|
||||
// period of time (so ethey are able to view the
|
||||
// prompt)
|
||||
mHandler.postDelayed(
|
||||
mStateRunnable, DEBOUNCE_DELAY_MILLIS);
|
||||
dismissDialog("STATE_IDLE");
|
||||
} else {
|
||||
mBiometricState = newState;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBiometricAction(
|
||||
@BiometricStateListener.Action int action) {
|
||||
Log.d(TAG, "onBiometricAction " + action);
|
||||
switch (action) {
|
||||
case BiometricStateListener.ACTION_SENSOR_TOUCH:
|
||||
mHandler.postDelayed(
|
||||
mTurnOffDialog,
|
||||
mTapWaitForPowerDuration);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
mSideFpsEventHandlerReady.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void dismissDialog(String reason) {
|
||||
Log.d(TAG, "Dismissing dialog with reason: " + reason);
|
||||
if (mDialog != null && mDialog.isShowing()) {
|
||||
mDialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private void showDialog(long time, String reason) {
|
||||
Log.d(TAG, "Showing dialog with reason: " + reason);
|
||||
if (mDialog != null && mDialog.isShowing()) {
|
||||
Log.d(TAG, "Ignoring show dialog");
|
||||
return;
|
||||
}
|
||||
mDialog =
|
||||
showConfirmDialog(
|
||||
mDialogSupplier.get(),
|
||||
mPowerManager,
|
||||
time,
|
||||
mBiometricState,
|
||||
mDialogDismissListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,10 @@ import android.hardware.fingerprint.Fingerprint;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.ISidefpsController;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.testing.TestableContext;
|
||||
|
||||
@@ -128,6 +130,8 @@ public class FingerprintAuthenticationClientTest {
|
||||
@Captor
|
||||
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
|
||||
|
||||
private TestLooper mLooper = new TestLooper();
|
||||
|
||||
@Rule
|
||||
public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@@ -233,6 +237,9 @@ public class FingerprintAuthenticationClientTest {
|
||||
client.start(mCallback);
|
||||
client.onAuthenticated(new Fingerprint("name", 2 /* enrollmentId */, SENSOR_ID),
|
||||
true /* authenticated */, new ArrayList<>());
|
||||
|
||||
mLooper.moveTimeForward(10);
|
||||
mLooper.dispatchAll();
|
||||
verify(mLuxProbe).destroy();
|
||||
|
||||
client.onAcquired(2, 0);
|
||||
@@ -309,9 +316,58 @@ public class FingerprintAuthenticationClientTest {
|
||||
client.onAuthenticated(new Fingerprint("friendly", 1 /* fingerId */, 2 /* deviceId */),
|
||||
true /* authenticated */, new ArrayList<>());
|
||||
|
||||
mLooper.moveTimeForward(10);
|
||||
mLooper.dispatchAll();
|
||||
verify(mCancellationSignal).cancel();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fingerprintPowerIgnoresAuthInWindow() throws Exception {
|
||||
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fingerprintAuthIgnoredWaitingForPower() throws Exception {
|
||||
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fingerprintAuthSucceedsAfterPowerWindow() throws Exception {
|
||||
when(mSensorProps.isAnySidefpsType()).thenReturn(true);
|
||||
|
||||
final FingerprintAuthenticationClient client = createClient(1);
|
||||
client.start(mCallback);
|
||||
client.onPowerPressed();
|
||||
mLooper.moveTimeForward(1000);
|
||||
mLooper.dispatchAll();
|
||||
client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
|
||||
true /* authenticated */, new ArrayList<>());
|
||||
mLooper.moveTimeForward(1000);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mCallback).onClientFinished(any(), eq(true));
|
||||
}
|
||||
|
||||
private FingerprintAuthenticationClient createClient() throws RemoteException {
|
||||
return createClient(100 /* version */, true /* allowBackgroundAuthentication */);
|
||||
}
|
||||
@@ -336,7 +392,8 @@ public class FingerprintAuthenticationClientTest {
|
||||
9 /* sensorId */, mBiometricLogger, mBiometricContext,
|
||||
true /* isStrongBiometric */,
|
||||
null /* taskStackListener */, mLockoutCache,
|
||||
mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication, mSensorProps) {
|
||||
mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication, mSensorProps,
|
||||
new Handler(mLooper.getLooper())) {
|
||||
@Override
|
||||
protected ActivityTaskManager getActivityTaskManager() {
|
||||
return mActivityTaskManager;
|
||||
|
||||
@@ -53,33 +53,30 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SideFpsEventHandler}.
|
||||
* <p/>
|
||||
* Run with <code>atest SideFpsEventHandlerTest</code>.
|
||||
*
|
||||
* <p>Run with <code>atest SideFpsEventHandlerTest</code>.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class SideFpsEventHandlerTest {
|
||||
|
||||
private static final List<Integer> sAllStates = List.of(
|
||||
BiometricStateListener.STATE_IDLE,
|
||||
BiometricStateListener.STATE_ENROLLING,
|
||||
BiometricStateListener.STATE_KEYGUARD_AUTH,
|
||||
BiometricStateListener.STATE_BP_AUTH,
|
||||
BiometricStateListener.STATE_AUTH_OTHER);
|
||||
private static final List<Integer> sAllStates =
|
||||
List.of(
|
||||
BiometricStateListener.STATE_IDLE,
|
||||
BiometricStateListener.STATE_ENROLLING,
|
||||
BiometricStateListener.STATE_KEYGUARD_AUTH,
|
||||
BiometricStateListener.STATE_BP_AUTH,
|
||||
BiometricStateListener.STATE_AUTH_OTHER);
|
||||
|
||||
@Rule
|
||||
public TestableContext mContext =
|
||||
new TestableContext(InstrumentationRegistry.getContext(), null);
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private FingerprintManager mFingerprintManager;
|
||||
@Spy
|
||||
private AlertDialog.Builder mDialogBuilder = new AlertDialog.Builder(mContext);
|
||||
@Mock
|
||||
private AlertDialog mAlertDialog;
|
||||
@Mock
|
||||
private Window mWindow;
|
||||
|
||||
@Mock private PackageManager mPackageManager;
|
||||
@Mock private FingerprintManager mFingerprintManager;
|
||||
@Spy private AlertDialog.Builder mDialogBuilder = new AlertDialog.Builder(mContext);
|
||||
@Mock private AlertDialog mAlertDialog;
|
||||
@Mock private Window mWindow;
|
||||
|
||||
private TestLooper mLooper = new TestLooper();
|
||||
private SideFpsEventHandler mEventHandler;
|
||||
@@ -95,9 +92,12 @@ public class SideFpsEventHandlerTest {
|
||||
when(mDialogBuilder.create()).thenReturn(mAlertDialog);
|
||||
when(mAlertDialog.getWindow()).thenReturn(mWindow);
|
||||
|
||||
mEventHandler = new SideFpsEventHandler(
|
||||
mContext, new Handler(mLooper.getLooper()),
|
||||
mContext.getSystemService(PowerManager.class), () -> mDialogBuilder);
|
||||
mEventHandler =
|
||||
new SideFpsEventHandler(
|
||||
mContext,
|
||||
new Handler(mLooper.getLooper()),
|
||||
mContext.getSystemService(PowerManager.class),
|
||||
() -> mDialogBuilder);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,7 +105,7 @@ public class SideFpsEventHandlerTest {
|
||||
when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT)))
|
||||
.thenReturn(false);
|
||||
|
||||
assertThat(mEventHandler.onSinglePressDetected(60L)).isFalse();
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
@@ -117,7 +117,7 @@ public class SideFpsEventHandlerTest {
|
||||
|
||||
for (int state : sAllStates) {
|
||||
setBiometricState(state);
|
||||
assertThat(mEventHandler.onSinglePressDetected(200L)).isFalse();
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(200L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
@@ -130,7 +130,7 @@ public class SideFpsEventHandlerTest {
|
||||
|
||||
for (int state : sAllStates) {
|
||||
setBiometricState(state);
|
||||
assertThat(mEventHandler.onSinglePressDetected(400L)).isFalse();
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(400L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
@@ -139,13 +139,13 @@ public class SideFpsEventHandlerTest {
|
||||
|
||||
@Test
|
||||
public void ignoresWhenIdleOrUnknown() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
setupWithSensor(true /* hasSidefps */, true /* initialized */);
|
||||
|
||||
setBiometricState(BiometricStateListener.STATE_IDLE);
|
||||
assertThat(mEventHandler.onSinglePressDetected(80000L)).isFalse();
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isFalse();
|
||||
|
||||
setBiometricState(BiometricStateListener.STATE_AUTH_OTHER);
|
||||
assertThat(mEventHandler.onSinglePressDetected(90000L)).isFalse();
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(90000L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
@@ -156,7 +156,7 @@ public class SideFpsEventHandlerTest {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setBiometricState(BiometricStateListener.STATE_KEYGUARD_AUTH);
|
||||
assertThat(mEventHandler.onSinglePressDetected(80000L)).isFalse();
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
@@ -164,13 +164,13 @@ public class SideFpsEventHandlerTest {
|
||||
|
||||
@Test
|
||||
public void promptsWhenBPisActive() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
setupWithSensor(true /* hasSideFps */, true /* initialized */);
|
||||
|
||||
setBiometricState(BiometricStateListener.STATE_BP_AUTH);
|
||||
assertThat(mEventHandler.onSinglePressDetected(80000L)).isTrue();
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog).show();
|
||||
verify(mAlertDialog, never()).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -178,7 +178,57 @@ public class SideFpsEventHandlerTest {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
||||
assertThat(mEventHandler.onSinglePressDetected(80000L)).isTrue();
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog).show();
|
||||
verify(mAlertDialog, never()).dismiss();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dismissesDialogOnTouchWhenEnrolling() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
||||
when(mAlertDialog.isShowing()).thenReturn(true);
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog).show();
|
||||
|
||||
mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
||||
mLooper.moveTimeForward(10000);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mAlertDialog).dismiss();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dismissesDialogFailsWhenPowerPressedAndDialogShowing() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
||||
when(mAlertDialog.isShowing()).thenReturn(true);
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog).show();
|
||||
|
||||
mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isTrue();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).dismiss();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showDialogAfterTap() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
||||
when(mAlertDialog.isShowing()).thenReturn(true);
|
||||
mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
||||
assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isTrue();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog).show();
|
||||
@@ -201,11 +251,13 @@ public class SideFpsEventHandlerTest {
|
||||
ArgumentCaptor.forClass(IFingerprintAuthenticatorsRegisteredCallback.class);
|
||||
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(fpCallbackCaptor.capture());
|
||||
if (initialized) {
|
||||
fpCallbackCaptor.getValue().onAllAuthenticatorsRegistered(
|
||||
List.of(mock(FingerprintSensorPropertiesInternal.class)));
|
||||
fpCallbackCaptor
|
||||
.getValue()
|
||||
.onAllAuthenticatorsRegistered(
|
||||
List.of(mock(FingerprintSensorPropertiesInternal.class)));
|
||||
if (hasSfps) {
|
||||
ArgumentCaptor<BiometricStateListener> captor = ArgumentCaptor.forClass(
|
||||
BiometricStateListener.class);
|
||||
ArgumentCaptor<BiometricStateListener> captor =
|
||||
ArgumentCaptor.forClass(BiometricStateListener.class);
|
||||
verify(mFingerprintManager).registerBiometricStateListener(captor.capture());
|
||||
mBiometricStateListener = captor.getValue();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user