Loading core/java/android/hardware/biometrics/BiometricPrompt.java +19 −5 Original line number Diff line number Diff line Loading @@ -142,6 +142,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private PromptInfo mPromptInfo; private ButtonInfo mNegativeButtonInfo; private Context mContext; private IAuthService mService; /** * Creates a builder for a {@link BiometricPrompt} dialog. Loading Loading @@ -211,6 +212,18 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan return this; } /** * @param service * @return This builder. * @hide */ @RequiresPermission(TEST_BIOMETRIC) @NonNull public Builder setService(@NonNull IAuthService service) { mService = service; return this; } /** * Sets an optional title, subtitle, and/or description that will override other text when * the user is authenticating with PIN/pattern/password. Currently for internal use only. Loading Loading @@ -472,7 +485,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan throw new IllegalArgumentException("Can't have both negative button behavior" + " and device credential enabled"); } return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo); mService = (mService == null) ? IAuthService.Stub.asInterface( ServiceManager.getService(Context.AUTH_SERVICE)) : mService; return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo, mService); } } Loading Loading @@ -521,7 +536,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan public void onAuthenticationFailed() { mExecutor.execute(() -> { mAuthenticationCallback.onAuthenticationFailed(); mIsPromptShowing = false; }); } Loading Loading @@ -604,12 +618,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private boolean mIsPromptShowing; private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo) { private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo, IAuthService service) { mContext = context; mPromptInfo = promptInfo; mNegativeButtonInfo = negativeButtonInfo; mService = IAuthService.Stub.asInterface( ServiceManager.getService(Context.AUTH_SERVICE)); mService = service; mIsPromptShowing = false; } Loading core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * 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 android.hardware.biometrics; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.os.CancellationSignal; import android.os.Handler; import android.os.RemoteException; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoRule; import java.util.concurrent.Executor; @Presubmit @RunWith(MockitoJUnitRunner.class) public class BiometricPromptTest { @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @Mock private Context mContext; @Mock private IAuthService mService; private BiometricPrompt mBiometricPrompt; private CancellationSignal mCancellationSignal; private final TestLooper mLooper = new TestLooper(); private final Handler mHandler = new Handler(mLooper.getLooper()); private final Executor mExecutor = mHandler::post; @Before public void setUp() throws RemoteException { mBiometricPrompt = new BiometricPrompt.Builder(mContext) .setUseDefaultSubtitle() .setUseDefaultTitle() .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL) .setService(mService) .build(); mCancellationSignal = new CancellationSignal(); when(mService.authenticate(any(), anyLong(), anyInt(), any(), anyString(), any())) .thenReturn(0L); when(mContext.getPackageName()).thenReturn("BiometricPromptTest"); } @Test public void testCancellationAfterAuthenticationFailed() throws RemoteException { ArgumentCaptor<IBiometricServiceReceiver> biometricServiceReceiverCaptor = ArgumentCaptor.forClass(IBiometricServiceReceiver.class); BiometricPrompt.AuthenticationCallback callback = new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, CharSequence errString) { super.onAuthenticationError(errorCode, errString); }}; mBiometricPrompt.authenticate(mCancellationSignal, mExecutor, callback); mLooper.dispatchAll(); verify(mService).authenticate(any(), anyLong(), anyInt(), biometricServiceReceiverCaptor.capture(), anyString(), any()); biometricServiceReceiverCaptor.getValue().onAuthenticationFailed(); mLooper.dispatchAll(); mCancellationSignal.cancel(); verify(mService).cancelAuthentication(any(), anyString(), anyLong()); } } core/tests/coretests/src/android/hardware/biometrics/OWNERS 0 → 100644 +1 −0 Original line number Diff line number Diff line include /services/core/java/com/android/server/biometrics/OWNERS Loading
core/java/android/hardware/biometrics/BiometricPrompt.java +19 −5 Original line number Diff line number Diff line Loading @@ -142,6 +142,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private PromptInfo mPromptInfo; private ButtonInfo mNegativeButtonInfo; private Context mContext; private IAuthService mService; /** * Creates a builder for a {@link BiometricPrompt} dialog. Loading Loading @@ -211,6 +212,18 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan return this; } /** * @param service * @return This builder. * @hide */ @RequiresPermission(TEST_BIOMETRIC) @NonNull public Builder setService(@NonNull IAuthService service) { mService = service; return this; } /** * Sets an optional title, subtitle, and/or description that will override other text when * the user is authenticating with PIN/pattern/password. Currently for internal use only. Loading Loading @@ -472,7 +485,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan throw new IllegalArgumentException("Can't have both negative button behavior" + " and device credential enabled"); } return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo); mService = (mService == null) ? IAuthService.Stub.asInterface( ServiceManager.getService(Context.AUTH_SERVICE)) : mService; return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo, mService); } } Loading Loading @@ -521,7 +536,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan public void onAuthenticationFailed() { mExecutor.execute(() -> { mAuthenticationCallback.onAuthenticationFailed(); mIsPromptShowing = false; }); } Loading Loading @@ -604,12 +618,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private boolean mIsPromptShowing; private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo) { private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo, IAuthService service) { mContext = context; mPromptInfo = promptInfo; mNegativeButtonInfo = negativeButtonInfo; mService = IAuthService.Stub.asInterface( ServiceManager.getService(Context.AUTH_SERVICE)); mService = service; mIsPromptShowing = false; } Loading
core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * 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 android.hardware.biometrics; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.os.CancellationSignal; import android.os.Handler; import android.os.RemoteException; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoRule; import java.util.concurrent.Executor; @Presubmit @RunWith(MockitoJUnitRunner.class) public class BiometricPromptTest { @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @Mock private Context mContext; @Mock private IAuthService mService; private BiometricPrompt mBiometricPrompt; private CancellationSignal mCancellationSignal; private final TestLooper mLooper = new TestLooper(); private final Handler mHandler = new Handler(mLooper.getLooper()); private final Executor mExecutor = mHandler::post; @Before public void setUp() throws RemoteException { mBiometricPrompt = new BiometricPrompt.Builder(mContext) .setUseDefaultSubtitle() .setUseDefaultTitle() .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL) .setService(mService) .build(); mCancellationSignal = new CancellationSignal(); when(mService.authenticate(any(), anyLong(), anyInt(), any(), anyString(), any())) .thenReturn(0L); when(mContext.getPackageName()).thenReturn("BiometricPromptTest"); } @Test public void testCancellationAfterAuthenticationFailed() throws RemoteException { ArgumentCaptor<IBiometricServiceReceiver> biometricServiceReceiverCaptor = ArgumentCaptor.forClass(IBiometricServiceReceiver.class); BiometricPrompt.AuthenticationCallback callback = new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, CharSequence errString) { super.onAuthenticationError(errorCode, errString); }}; mBiometricPrompt.authenticate(mCancellationSignal, mExecutor, callback); mLooper.dispatchAll(); verify(mService).authenticate(any(), anyLong(), anyInt(), biometricServiceReceiverCaptor.capture(), anyString(), any()); biometricServiceReceiverCaptor.getValue().onAuthenticationFailed(); mLooper.dispatchAll(); mCancellationSignal.cancel(); verify(mService).cancelAuthentication(any(), anyString(), anyLong()); } }
core/tests/coretests/src/android/hardware/biometrics/OWNERS 0 → 100644 +1 −0 Original line number Diff line number Diff line include /services/core/java/com/android/server/biometrics/OWNERS