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

Commit ea16a724 authored by Diya Bera's avatar Diya Bera
Browse files

No biometric prompt for external display

Return error if biometric prompt is requested and if the display is
external. This is to support Desktop Experience Feature.

Flag: com.android.server.biometrics.biometric_prompt_external_display
Fixes: 421237594
Test: atest PreAuthInfoTest
Change-Id: I8a703ed7190358ea38ef33c9395eb784c1fa9695
parent 613d31be
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.biometrics;

import static android.hardware.biometrics.BiometricAuthenticator.TYPE_ANY_BIOMETRIC;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
@@ -35,6 +36,7 @@ import android.os.RemoteException;
import android.os.UserManager;
import android.util.Pair;
import android.util.Slog;
import android.view.Display;

import com.android.internal.R;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -397,7 +399,11 @@ class PreAuthInfo {
            cameraPrivacyEnabled = mBiometricCameraManager.isCameraPrivacyEnabled();
        }

        if (mBiometricRequested && credentialRequested) {
        if (com.android.server.biometrics.Flags.biometricPromptExternalDisplay()
                && isExternalDisplay()) {
            status = BIOMETRIC_HARDWARE_NOT_DETECTED;
            modality = TYPE_ANY_BIOMETRIC | TYPE_CREDENTIAL;
        } else if (mBiometricRequested && credentialRequested) {
            if (credentialAvailable || !eligibleSensors.isEmpty()) {
                for (BiometricSensor sensor : eligibleSensors) {
                    modality |= sensor.modality;
@@ -480,6 +486,15 @@ class PreAuthInfo {
                        getInternalStatus().second));
    }

    private boolean isExternalDisplay() {
        try {
            return context.getDisplay().getType() == Display.TYPE_EXTERNAL;
        } catch (UnsupportedOperationException e) {
            Slog.d(TAG, "Exception thrown when checking display type " + e);
            return false;
        }
    }

    /** Returns if mandatory biometrics authentication is in effect */
    boolean getIsMandatoryBiometricsAuthentication() {
        return mIsMandatoryBiometricsAuthentication;
+10 −0
Original line number Diff line number Diff line
@@ -51,3 +51,13 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
  name: "biometric_prompt_external_display"
  namespace: "biometrics_framework"
  description: "This flag returns error code when biometric prompt is requested on external display."
  bug: "421237594"
  metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+47 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.biometrics;

import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_ANY_BIOMETRIC;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
@@ -40,6 +42,8 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.Flags;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.PromptInfo;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.IDisplayManager;
import android.os.RemoteException;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@@ -47,6 +51,9 @@ import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Pair;
import android.view.Display;
import android.view.DisplayInfo;

import androidx.test.filters.SmallTest;

@@ -92,6 +99,8 @@ public class PreAuthInfoTest {
    BiometricCameraManager mBiometricCameraManager;
    @Mock
    UserManager mUserManager;
    @Mock
    IDisplayManager mDisplayManager;

    @Before
    public void setup() throws RemoteException {
@@ -114,6 +123,35 @@ public class PreAuthInfoTest {
        when(mBiometricCameraManager.isAnyCameraUnavailable()).thenReturn(false);
        when(mContext.getResources()).thenReturn(mResources);
        when(mResources.getString(anyInt())).thenReturn(TEST_PACKAGE_NAME);
        setContextDisplayWithType(Display.TYPE_INTERNAL);
    }

    @Test
    @RequiresFlagsEnabled(
            com.android.server.biometrics.Flags.FLAG_BIOMETRIC_PROMPT_EXTERNAL_DISPLAY)
    public void testAuthentication_whenExternalDisplay() throws RemoteException {
        setContextDisplayWithType(Display.TYPE_EXTERNAL);

        final BiometricSensor faceSensor = getFaceSensor();
        final BiometricSensor fingerprintSensor = getFingerprintSensor();
        final PromptInfo promptInfo = new PromptInfo();

        promptInfo.setConfirmationRequested(false /* requireConfirmation */);
        promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
        promptInfo.setDisallowBiometricsIfPolicyExists(false /* checkDevicePolicy */);
        final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
                mSettingObserver, List.of(faceSensor, fingerprintSensor), USER_ID, promptInfo,
                TEST_PACKAGE_NAME, false /* checkDevicePolicyManager */, mContext,
                mBiometricCameraManager, mUserManager);
        final Pair<Integer, Integer> preAuthenticateStatus = preAuthInfo.getPreAuthenticateStatus();

        //Should return hardware unavailable even if there are eligible sensors
        assertThat(preAuthInfo.eligibleSensors).hasSize(2);
        assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo(
                BIOMETRIC_ERROR_HW_UNAVAILABLE);
        assertThat(preAuthenticateStatus.first).isEqualTo(
                TYPE_ANY_BIOMETRIC | TYPE_CREDENTIAL);
        assertThat(preAuthenticateStatus.second).isEqualTo(BIOMETRIC_ERROR_HW_UNAVAILABLE);
    }

    @Test
@@ -505,6 +543,15 @@ public class PreAuthInfoTest {
                .isEqualTo(BIOMETRIC_NOT_ENABLED_FOR_APPS);
    }

    private void setContextDisplayWithType(int type) {
        final DisplayInfo displayInfo = new DisplayInfo();
        displayInfo.type = type;
        final Display display = new Display(new DisplayManagerGlobal(mDisplayManager),
                0 /* displayId */, displayInfo, mResources);

        when(mContext.getDisplay()).thenReturn(display);
    }

    private BiometricSensor getFingerprintSensor() {
        BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FINGERPRINT,
                TYPE_FINGERPRINT, BiometricManager.Authenticators.BIOMETRIC_STRONG,