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

Commit 27db3c0a authored by Joshua Mccloskey's avatar Joshua Mccloskey
Browse files

Added sensor privacy message to biometric prompt

Bug: 201045056
Test: Verified that BiometricPrompt shows an error message if the user
is using face authentication and camera privacy is enabled.

Change-Id: Idc2140062c4aa87e0bcffb14e07336dc6cd7d955
parent 9d3f1be6
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -150,6 +150,12 @@ public interface BiometricConstants {
     */
    int BIOMETRIC_ERROR_RE_ENROLL = 16;

    /**
     * The privacy setting has been enabled and will block use of the sensor.
     * @hide
     */
    int BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED = 18;

    /**
     * This constant is only used by SystemUI. It notifies SystemUI that authentication was paused
     * because the authentication attempt was unsuccessful.
+2 −0
Original line number Diff line number Diff line
@@ -1666,6 +1666,8 @@
    <string name="face_setup_notification_title">Set up Face Unlock</string>
    <!-- Contents of a notification that directs the user to set up face unlock by enrolling their face. [CHAR LIMIT=NONE] -->
    <string name="face_setup_notification_content">Unlock your phone by looking at it</string>
    <!-- Error message indicating that the camera privacy sensor has been turned on [CHAR LIMIT=NONE] -->
    <string name="face_sensor_privacy_enabled">To use Face Unlock, turn on <b>Camera access</b> in Settings > Privacy</string>
    <!-- Title of a notification that directs the user to enroll a fingerprint. [CHAR LIMIT=NONE] -->
    <string name="fingerprint_setup_notification_title">Set up more ways to unlock</string>
    <!-- Contents of a notification that directs the user to enroll a fingerprint. [CHAR LIMIT=NONE] -->
+1 −0
Original line number Diff line number Diff line
@@ -2570,6 +2570,7 @@
  <java-symbol type="string" name="face_recalibrate_notification_name" />
  <java-symbol type="string" name="face_recalibrate_notification_title" />
  <java-symbol type="string" name="face_recalibrate_notification_content" />
  <java-symbol type="string" name="face_sensor_privacy_enabled" />
  <java-symbol type="string" name="face_error_unable_to_process" />
  <java-symbol type="string" name="face_error_hw_not_available" />
  <java-symbol type="string" name="face_error_no_space" />
+24 −3
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PointF;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
@@ -89,6 +90,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,

    private static final String TAG = "AuthController";
    private static final boolean DEBUG = true;
    private static final int SENSOR_PRIVACY_DELAY = 500;

    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final CommandQueue mCommandQueue;
@@ -122,6 +124,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
    @Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps;

    @NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
    private SensorPrivacyManager mSensorPrivacyManager;

    private class BiometricTaskStackListener extends TaskStackListener {
        @Override
@@ -492,6 +495,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);

        context.registerReceiver(mBroadcastReceiver, filter);
        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
    }

    private void updateFingerprintLocation() {
@@ -642,10 +646,16 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
        final boolean isLockout = (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT)
                || (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);

        boolean isCameraPrivacyEnabled = false;
        if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE
                && mSensorPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
                mCurrentDialogArgs.argi1 /* userId */)) {
            isCameraPrivacyEnabled = true;
        }
        // TODO(b/141025588): Create separate methods for handling hard and soft errors.
        final boolean isSoftError = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED
                || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT);

                || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT
                || isCameraPrivacyEnabled);
        if (mCurrentDialog != null) {
            if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
                if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
@@ -655,12 +665,23 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
                        ? mContext.getString(R.string.biometric_not_recognized)
                        : getErrorString(modality, error, vendorCode);
                if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
                // The camera privacy error can return before the prompt initializes its state,
                // causing the prompt to appear to endlessly authenticate. Add a small delay
                // to stop this.
                if (isCameraPrivacyEnabled) {
                    mHandler.postDelayed(() -> {
                        mCurrentDialog.onAuthenticationFailed(modality,
                                mContext.getString(R.string.face_sensor_privacy_enabled));
                    }, SENSOR_PRIVACY_DELAY);
                } else {
                    mCurrentDialog.onAuthenticationFailed(modality, errorMessage);
                }
            } else {
                final String errorMessage = getErrorString(modality, error, vendorCode);
                if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
                mCurrentDialog.onError(modality, errorMessage);
            }

        } else {
            Log.w(TAG, "onBiometricError callback but dialog is gone");
        }
+9 −4
Original line number Diff line number Diff line
@@ -1036,7 +1036,8 @@ public class BiometricService extends SystemService {
        promptInfo.setAuthenticators(authenticators);

        return PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors,
                userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */);
                userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */,
                getContext());
    }

    /**
@@ -1375,7 +1376,8 @@ public class BiometricService extends SystemService {
            try {
                final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager,
                        mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo,
                        opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists());
                        opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists(),
                        getContext());

                final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus();

@@ -1383,8 +1385,11 @@ public class BiometricService extends SystemService {
                        + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo
                        + " requestId: " + requestId + " promptInfo.isIgnoreEnrollmentState: "
                        + promptInfo.isIgnoreEnrollmentState());

                if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) {
                // BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED is added so that BiometricPrompt can
                // be shown for this case.
                if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS
                        || preAuthStatus.second
                        == BiometricConstants.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED) {
                    // If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but
                    // CREDENTIAL is requested and available, set the bundle to only request
                    // CREDENTIAL.
Loading