Loading core/java/android/hardware/fingerprint/Fingerprint.java +4 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,10 @@ public final class Fingerprint extends BiometricAuthenticator.Identifier { mGroupId = groupId; } public Fingerprint(CharSequence name, int fingerId, long deviceId) { super(name, fingerId, deviceId); } private Fingerprint(Parcel in) { super(in.readString(), in.readInt(), in.readLong()); mGroupId = in.readInt(); Loading services/core/java/com/android/server/biometrics/HardwareAuthTokenUtils.java 0 → 100644 +138 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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; import static java.nio.ByteOrder.LITTLE_ENDIAN; import android.hardware.keymaster.HardwareAuthToken; import android.hardware.keymaster.Timestamp; import java.nio.ByteOrder; /** * Utilities for converting between old and new HardwareAuthToken types. See * {@link HardwareAuthToken}. */ public class HardwareAuthTokenUtils { public static byte[] toByteArray(HardwareAuthToken hat) { final byte[] array = new byte[69]; // Version, first byte. Used in hw_auth_token.h but not HardwareAuthToken array[0] = 0; // Challenge, 1:8. writeLong(hat.challenge, array, 1 /* offset */); // UserId, 9:16. writeLong(hat.userId, array, 9 /* offset */); // AuthenticatorId, 17:24. writeLong(hat.authenticatorId, array, 17 /* offset */); // AuthenticatorType, 25:28. writeInt(flipIfNativelyLittle(hat.authenticatorType), array, 25 /* offset */); // Timestamp, 29:36. writeLong(flipIfNativelyLittle(hat.timestamp.milliSeconds), array, 29 /* offset */); // MAC, 37:69. Byte array. System.arraycopy(hat.mac, 0 /* srcPos */, array, 37 /* destPos */, hat.mac.length); return array; } public static HardwareAuthToken toHardwareAuthToken(byte[] array) { final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken(); // First byte is version, which doesn't not exist in HardwareAuthToken anymore // Next 8 bytes is the challenge. hardwareAuthToken.challenge = getLong(array, 1 /* offset */); // Next 8 bytes is the userId hardwareAuthToken.userId = getLong(array, 9 /* offset */); // Next 8 bytes is the authenticatorId. hardwareAuthToken.authenticatorId = getLong(array, 17 /* offset */); // Next 4 bytes is the authenticatorType. hardwareAuthToken.authenticatorType = flipIfNativelyLittle(getInt(array, 25 /* offset */)); // Next 8 bytes is the timestamp. final Timestamp timestamp = new Timestamp(); timestamp.milliSeconds = flipIfNativelyLittle(getLong(array, 29 /* offset */)); hardwareAuthToken.timestamp = timestamp; // Last 32 bytes is the mac, 37:69 hardwareAuthToken.mac = new byte[32]; System.arraycopy(array, 37 /* srcPos */, hardwareAuthToken.mac, 0 /* destPos */, 32 /* length */); return hardwareAuthToken; } private static long flipIfNativelyLittle(long l) { if (LITTLE_ENDIAN == ByteOrder.nativeOrder()) { return Long.reverseBytes(l); } return l; } private static int flipIfNativelyLittle(int i) { if (LITTLE_ENDIAN == ByteOrder.nativeOrder()) { return Integer.reverseBytes(i); } return i; } private static void writeLong(long l, byte[] dest, int offset) { dest[offset + 0] = (byte) l; dest[offset + 1] = (byte) (l >> 8); dest[offset + 2] = (byte) (l >> 16); dest[offset + 3] = (byte) (l >> 24); dest[offset + 4] = (byte) (l >> 32); dest[offset + 5] = (byte) (l >> 40); dest[offset + 6] = (byte) (l >> 48); dest[offset + 7] = (byte) (l >> 56); } private static void writeInt(int i, byte[] dest, int offset) { dest[offset + 0] = (byte) i; dest[offset + 1] = (byte) (i >> 8); dest[offset + 2] = (byte) (i >> 16); dest[offset + 3] = (byte) (i >> 24); } private static long getLong(byte[] array, int offset) { long result = 0; // Lowest bit is LSB for (int i = 0; i < 8; i++) { result += (long) ((array[i + offset] & 0xffL) << (8 * i)); } return result; } private static int getInt(byte[] array, int offset) { int result = 0; // Lowest bit is LSB for (int i = 0; i < 4; i++) { result += (int) (((int) array[i + offset] & 0xff) << (8 * i)); } return result; } } services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +3 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.sensors.BiometricUtils; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.EnrollClient; Loading Loading @@ -82,8 +83,8 @@ public class FingerprintEnrollClient extends EnrollClient<ISession> implements U protected void startHalOperation() { UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController); try { // TODO(b/170163175): Need a way to convert byte arrays to HardwareAuthToken getFreshDaemon().enroll(mSequentialId, null /* hat */); getFreshDaemon().enroll(mSequentialId, HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken)); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting enroll", e); onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */); Loading services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +2 −2 Original line number Diff line number Diff line Loading @@ -79,8 +79,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi prop.commonProps.maxEnrollmentsPerUser, prop.sensorType, true /* resetLockoutRequiresHardwareAuthToken */); final Sensor sensor = new Sensor(getTag() + "/" + sensorId, internalProp, gestureAvailabilityDispatcher); final Sensor sensor = new Sensor(getTag() + "/" + sensorId, mContext, mHandler, internalProp, gestureAvailabilityDispatcher); mSensors.put(sensorId, sensor); Slog.d(getTag(), "Added: " + internalProp); Loading services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java +99 −6 Original line number Diff line number Diff line Loading @@ -18,24 +18,40 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.fingerprint.Error; import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.ISession; import android.hardware.biometrics.fingerprint.ISessionCallback; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.keymaster.HardwareAuthToken; import android.os.Handler; import android.os.RemoteException; import android.util.Slog; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.AcquisitionClient; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.ClientMonitor; import com.android.server.biometrics.sensors.Interruptable; import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Maintains the state of a single sensor within an instance of the * {@link android.hardware.biometrics.fingerprint.IFingerprint} HAL. */ class Sensor { @NonNull private final String mTag; @NonNull private final Context mContext; @NonNull private final Handler mHandler; @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; @NonNull private final BiometricScheduler mScheduler; Loading @@ -58,10 +74,12 @@ class Sensor { } } Sensor(@NonNull String tag, Sensor(@NonNull String tag, @NonNull Context context, @NonNull Handler handler, @NonNull FingerprintSensorPropertiesInternal sensorProperties, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { mTag = tag; mContext = context; mHandler = handler; mSensorProperties = sensorProperties; mScheduler = new BiometricScheduler(tag, gestureAvailabilityDispatcher); mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null; Loading Loading @@ -89,27 +107,102 @@ class Sensor { @Override public void onAcquired(byte info, int vendorCode) { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof AcquisitionClient)) { Slog.e(mTag, "onAcquired for non-acquisition client: " + Utils.getClientName(client)); return; } final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client; acquisitionClient.onAcquired(info, vendorCode); }); } @Override public void onError(byte error, int vendorCode) { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); Slog.d(mTag, "onError" + ", client: " + Utils.getClientName(client) + ", error: " + error + ", vendorCode: " + vendorCode); if (!(client instanceof Interruptable)) { Slog.e(mTag, "onError for non-error consumer: " + Utils.getClientName(client)); return; } final Interruptable interruptable = (Interruptable) client; interruptable.onError(error, vendorCode); if (error == Error.HW_UNAVAILABLE) { Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE"); mCurrentSession = null; } }); } @Override public void onEnrollmentProgress(int enrollmentId, int remaining) { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof FingerprintEnrollClient)) { Slog.e(mTag, "onEnrollmentProgress for non-enroll client: " + Utils.getClientName(client)); return; } final int currentUserId = client.getTargetUserId(); final CharSequence name = FingerprintUtils.getInstance() .getUniqueName(mContext, currentUserId); final Fingerprint fingerprint = new Fingerprint(name, enrollmentId, sensorId); final FingerprintEnrollClient enrollClient = (FingerprintEnrollClient) client; enrollClient.onEnrollResult(fingerprint, remaining); }); } @Override public void onAuthenticationSucceeded(int enrollmentId, HardwareAuthToken hat) { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof AuthenticationConsumer)) { Slog.e(mTag, "onAuthenticationSucceeded for non-authentication consumer: " + Utils.getClientName(client)); return; } final AuthenticationConsumer authenticationConsumer = (AuthenticationConsumer) client; final Fingerprint fp = new Fingerprint("", enrollmentId, sensorId); final byte[] byteArray = HardwareAuthTokenUtils.toByteArray(hat); final ArrayList<Byte> byteList = new ArrayList<>(); for (byte b : byteArray) { byteList.add(b); } authenticationConsumer.onAuthenticated(fp, true /* authenticated */, byteList); }); } @Override public void onAuthenticationFailed() { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof AuthenticationConsumer)) { Slog.e(mTag, "onAuthenticationFailed for non-authentication consumer: " + Utils.getClientName(client)); return; } final AuthenticationConsumer authenticationConsumer = (AuthenticationConsumer) client; final Fingerprint fp = new Fingerprint("", 0 /* enrollmentId */, sensorId); authenticationConsumer .onAuthenticated(fp, false /* authenticated */, null /* hat */); }); } @Override Loading Loading
core/java/android/hardware/fingerprint/Fingerprint.java +4 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,10 @@ public final class Fingerprint extends BiometricAuthenticator.Identifier { mGroupId = groupId; } public Fingerprint(CharSequence name, int fingerId, long deviceId) { super(name, fingerId, deviceId); } private Fingerprint(Parcel in) { super(in.readString(), in.readInt(), in.readLong()); mGroupId = in.readInt(); Loading
services/core/java/com/android/server/biometrics/HardwareAuthTokenUtils.java 0 → 100644 +138 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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; import static java.nio.ByteOrder.LITTLE_ENDIAN; import android.hardware.keymaster.HardwareAuthToken; import android.hardware.keymaster.Timestamp; import java.nio.ByteOrder; /** * Utilities for converting between old and new HardwareAuthToken types. See * {@link HardwareAuthToken}. */ public class HardwareAuthTokenUtils { public static byte[] toByteArray(HardwareAuthToken hat) { final byte[] array = new byte[69]; // Version, first byte. Used in hw_auth_token.h but not HardwareAuthToken array[0] = 0; // Challenge, 1:8. writeLong(hat.challenge, array, 1 /* offset */); // UserId, 9:16. writeLong(hat.userId, array, 9 /* offset */); // AuthenticatorId, 17:24. writeLong(hat.authenticatorId, array, 17 /* offset */); // AuthenticatorType, 25:28. writeInt(flipIfNativelyLittle(hat.authenticatorType), array, 25 /* offset */); // Timestamp, 29:36. writeLong(flipIfNativelyLittle(hat.timestamp.milliSeconds), array, 29 /* offset */); // MAC, 37:69. Byte array. System.arraycopy(hat.mac, 0 /* srcPos */, array, 37 /* destPos */, hat.mac.length); return array; } public static HardwareAuthToken toHardwareAuthToken(byte[] array) { final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken(); // First byte is version, which doesn't not exist in HardwareAuthToken anymore // Next 8 bytes is the challenge. hardwareAuthToken.challenge = getLong(array, 1 /* offset */); // Next 8 bytes is the userId hardwareAuthToken.userId = getLong(array, 9 /* offset */); // Next 8 bytes is the authenticatorId. hardwareAuthToken.authenticatorId = getLong(array, 17 /* offset */); // Next 4 bytes is the authenticatorType. hardwareAuthToken.authenticatorType = flipIfNativelyLittle(getInt(array, 25 /* offset */)); // Next 8 bytes is the timestamp. final Timestamp timestamp = new Timestamp(); timestamp.milliSeconds = flipIfNativelyLittle(getLong(array, 29 /* offset */)); hardwareAuthToken.timestamp = timestamp; // Last 32 bytes is the mac, 37:69 hardwareAuthToken.mac = new byte[32]; System.arraycopy(array, 37 /* srcPos */, hardwareAuthToken.mac, 0 /* destPos */, 32 /* length */); return hardwareAuthToken; } private static long flipIfNativelyLittle(long l) { if (LITTLE_ENDIAN == ByteOrder.nativeOrder()) { return Long.reverseBytes(l); } return l; } private static int flipIfNativelyLittle(int i) { if (LITTLE_ENDIAN == ByteOrder.nativeOrder()) { return Integer.reverseBytes(i); } return i; } private static void writeLong(long l, byte[] dest, int offset) { dest[offset + 0] = (byte) l; dest[offset + 1] = (byte) (l >> 8); dest[offset + 2] = (byte) (l >> 16); dest[offset + 3] = (byte) (l >> 24); dest[offset + 4] = (byte) (l >> 32); dest[offset + 5] = (byte) (l >> 40); dest[offset + 6] = (byte) (l >> 48); dest[offset + 7] = (byte) (l >> 56); } private static void writeInt(int i, byte[] dest, int offset) { dest[offset + 0] = (byte) i; dest[offset + 1] = (byte) (i >> 8); dest[offset + 2] = (byte) (i >> 16); dest[offset + 3] = (byte) (i >> 24); } private static long getLong(byte[] array, int offset) { long result = 0; // Lowest bit is LSB for (int i = 0; i < 8; i++) { result += (long) ((array[i + offset] & 0xffL) << (8 * i)); } return result; } private static int getInt(byte[] array, int offset) { int result = 0; // Lowest bit is LSB for (int i = 0; i < 4; i++) { result += (int) (((int) array[i + offset] & 0xff) << (8 * i)); } return result; } }
services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +3 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.sensors.BiometricUtils; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.EnrollClient; Loading Loading @@ -82,8 +83,8 @@ public class FingerprintEnrollClient extends EnrollClient<ISession> implements U protected void startHalOperation() { UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController); try { // TODO(b/170163175): Need a way to convert byte arrays to HardwareAuthToken getFreshDaemon().enroll(mSequentialId, null /* hat */); getFreshDaemon().enroll(mSequentialId, HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken)); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting enroll", e); onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */); Loading
services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +2 −2 Original line number Diff line number Diff line Loading @@ -79,8 +79,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi prop.commonProps.maxEnrollmentsPerUser, prop.sensorType, true /* resetLockoutRequiresHardwareAuthToken */); final Sensor sensor = new Sensor(getTag() + "/" + sensorId, internalProp, gestureAvailabilityDispatcher); final Sensor sensor = new Sensor(getTag() + "/" + sensorId, mContext, mHandler, internalProp, gestureAvailabilityDispatcher); mSensors.put(sensorId, sensor); Slog.d(getTag(), "Added: " + internalProp); Loading
services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java +99 −6 Original line number Diff line number Diff line Loading @@ -18,24 +18,40 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.fingerprint.Error; import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.ISession; import android.hardware.biometrics.fingerprint.ISessionCallback; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.keymaster.HardwareAuthToken; import android.os.Handler; import android.os.RemoteException; import android.util.Slog; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.AcquisitionClient; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.ClientMonitor; import com.android.server.biometrics.sensors.Interruptable; import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Maintains the state of a single sensor within an instance of the * {@link android.hardware.biometrics.fingerprint.IFingerprint} HAL. */ class Sensor { @NonNull private final String mTag; @NonNull private final Context mContext; @NonNull private final Handler mHandler; @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; @NonNull private final BiometricScheduler mScheduler; Loading @@ -58,10 +74,12 @@ class Sensor { } } Sensor(@NonNull String tag, Sensor(@NonNull String tag, @NonNull Context context, @NonNull Handler handler, @NonNull FingerprintSensorPropertiesInternal sensorProperties, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { mTag = tag; mContext = context; mHandler = handler; mSensorProperties = sensorProperties; mScheduler = new BiometricScheduler(tag, gestureAvailabilityDispatcher); mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null; Loading Loading @@ -89,27 +107,102 @@ class Sensor { @Override public void onAcquired(byte info, int vendorCode) { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof AcquisitionClient)) { Slog.e(mTag, "onAcquired for non-acquisition client: " + Utils.getClientName(client)); return; } final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client; acquisitionClient.onAcquired(info, vendorCode); }); } @Override public void onError(byte error, int vendorCode) { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); Slog.d(mTag, "onError" + ", client: " + Utils.getClientName(client) + ", error: " + error + ", vendorCode: " + vendorCode); if (!(client instanceof Interruptable)) { Slog.e(mTag, "onError for non-error consumer: " + Utils.getClientName(client)); return; } final Interruptable interruptable = (Interruptable) client; interruptable.onError(error, vendorCode); if (error == Error.HW_UNAVAILABLE) { Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE"); mCurrentSession = null; } }); } @Override public void onEnrollmentProgress(int enrollmentId, int remaining) { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof FingerprintEnrollClient)) { Slog.e(mTag, "onEnrollmentProgress for non-enroll client: " + Utils.getClientName(client)); return; } final int currentUserId = client.getTargetUserId(); final CharSequence name = FingerprintUtils.getInstance() .getUniqueName(mContext, currentUserId); final Fingerprint fingerprint = new Fingerprint(name, enrollmentId, sensorId); final FingerprintEnrollClient enrollClient = (FingerprintEnrollClient) client; enrollClient.onEnrollResult(fingerprint, remaining); }); } @Override public void onAuthenticationSucceeded(int enrollmentId, HardwareAuthToken hat) { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof AuthenticationConsumer)) { Slog.e(mTag, "onAuthenticationSucceeded for non-authentication consumer: " + Utils.getClientName(client)); return; } final AuthenticationConsumer authenticationConsumer = (AuthenticationConsumer) client; final Fingerprint fp = new Fingerprint("", enrollmentId, sensorId); final byte[] byteArray = HardwareAuthTokenUtils.toByteArray(hat); final ArrayList<Byte> byteList = new ArrayList<>(); for (byte b : byteArray) { byteList.add(b); } authenticationConsumer.onAuthenticated(fp, true /* authenticated */, byteList); }); } @Override public void onAuthenticationFailed() { mHandler.post(() -> { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof AuthenticationConsumer)) { Slog.e(mTag, "onAuthenticationFailed for non-authentication consumer: " + Utils.getClientName(client)); return; } final AuthenticationConsumer authenticationConsumer = (AuthenticationConsumer) client; final Fingerprint fp = new Fingerprint("", 0 /* enrollmentId */, sensorId); authenticationConsumer .onAuthenticated(fp, false /* authenticated */, null /* hat */); }); } @Override Loading