From a1cf4df73eeb05935655edae390c5015c6b6476a Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Wed, 18 Nov 2020 12:34:35 -0800 Subject: [PATCH] Run error callback when BiometricPrompt dismissed early Currently, if BiometricPrompt is dismissed quickly (e.g. by tapping on the top half of the screen to dismiss it while it's being shown) the ongoing authentication session may not be canceled and the onAuthenticationError callback may not be run. This commit fixes the issue by ensuring that a dismissal reason is sent to callback if the prompt is shown while in the "pending dismissal" state. Test: atest com.android.systemui.biometrics Test: Manual: 1. Using a custom test app, trigger BiometricPrompt to be shown 2. While the prompt is being shown, repeatedly tap top half of screen 3. Ensure the prompt is dismissed and onAuthenticationError is called Bug: 173417042 Change-Id: I99284cb7fc413c0790f50056d553dc311117ce0c --- .../android/systemui/biometrics/AuthContainerView.java | 7 ++++--- .../systemui/biometrics/AuthContainerViewTest.java | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index dbe5a77965be9..c1233fe6b9daf 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -96,7 +96,7 @@ public class AuthContainerView extends LinearLayout @VisibleForTesting final WakefulnessLifecycle mWakefulnessLifecycle; - private @ContainerState int mContainerState = STATE_UNKNOWN; + @VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN; // Non-null only if the dialog is in the act of dismissing and has not sent the reason yet. @Nullable @AuthDialogCallback.DismissedReason Integer mPendingCallbackReason; @@ -607,10 +607,11 @@ public class AuthContainerView extends LinearLayout mWindowManager.removeView(this); } - private void onDialogAnimatedIn() { + @VisibleForTesting + void onDialogAnimatedIn() { if (mContainerState == STATE_PENDING_DISMISS) { Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now"); - animateAway(false /* sendReason */, 0); + animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); return; } mContainerState = STATE_SHOWING; diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java index 29d7a524dd8b6..5f3f3a79e31d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java @@ -203,6 +203,16 @@ public class AuthContainerViewTest extends SysuiTestCase { eq(View.IMPORTANT_FOR_ACCESSIBILITY_NO)); } + @Test + public void testOnDialogAnimatedIn_sendsCancelReason_whenPendingDismiss() { + initializeContainer(Authenticators.BIOMETRIC_WEAK); + mAuthContainer.mContainerState = AuthContainerView.STATE_PENDING_DISMISS; + mAuthContainer.onDialogAnimatedIn(); + verify(mCallback).onDismissed( + eq(AuthDialogCallback.DISMISSED_USER_CANCELED), + eq(null) /* credentialAttestation */); + } + @Test public void testLayoutParams_hasSecureWindowFlag() { final IBinder windowToken = mock(IBinder.class);