Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f3e3d55 authored by Diya Bera's avatar Diya Bera
Browse files

Correct mIsPromptShowing value when auth fails

Test: Diagnostics tool, atest BiometricPromptTest
Bug: 264816072
Change-Id: If08ef05842129eec61a77b2504b9db7052d3f2b3
parent 4c6f5787
Loading
Loading
Loading
Loading
+19 −5
Original line number Diff line number Diff line
@@ -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.
@@ -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.
@@ -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);
        }
    }

@@ -521,7 +536,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        public void onAuthenticationFailed() {
            mExecutor.execute(() -> {
                mAuthenticationCallback.onAuthenticationFailed();
                mIsPromptShowing = false;
            });
        }

@@ -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;
    }

+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());
    }
}
+1 −0
Original line number Diff line number Diff line
include /services/core/java/com/android/server/biometrics/OWNERS