Add SensorPrivacy error message to FaceService.

If the camera privacy sensor is enabled, show an error message
on Keyguard.

Test: Verified that the sensor privacy error is shown when privacy sensor is enabled.
Bug: 201045056
Change-Id: Ib7709596d378caa690a782294197a5b26e55857f
This commit is contained in:
Joshua Mccloskey
2021-11-22 16:21:04 -08:00
parent c7f6a0750e
commit 9d3f1be63c
6 changed files with 59 additions and 3 deletions

View File

@@ -69,7 +69,7 @@ public interface BiometricFaceConstants {
BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
BIOMETRIC_ERROR_RE_ENROLL,
FACE_ERROR_UNKNOWN
FACE_ERROR_UNKNOWN,
})
@Retention(RetentionPolicy.SOURCE)
@interface FaceError {}

View File

@@ -219,6 +219,9 @@
<!-- Face hint message when finger was not recognized. [CHAR LIMIT=20] -->
<string name="kg_face_not_recognized">Not recognized</string>
<!-- Error message indicating that the camera privacy sensor has been turned on [CHAR LIMIT=NONE] -->
<string name="kg_face_sensor_privacy_enabled">To use Face Unlock, turn on <b>Camera access</b> in Settings > Privacy</string>
<!-- Instructions telling the user remaining times when enter SIM PIN view. -->
<plurals name="kg_password_default_pin_message">
<item quantity="one">Enter SIM PIN. You have <xliff:g id="number">%d</xliff:g> remaining

View File

@@ -51,6 +51,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -322,6 +323,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mLockIconPressed;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private final Executor mBackgroundExecutor;
private SensorPrivacyManager mSensorPrivacyManager;
private int mFaceAuthUserId;
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
@@ -993,6 +996,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// Error is always the end of authentication lifecycle
mFaceCancelSignal = null;
boolean cameraPrivacyEnabled = false;
if (mSensorPrivacyManager != null) {
cameraPrivacyEnabled = mSensorPrivacyManager
.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
mFaceAuthUserId);
}
if (msgId == FaceManager.FACE_ERROR_CANCELED
&& mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
@@ -1002,7 +1011,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
}
if (msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE
final boolean isHwUnavailable = msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE;
if (isHwUnavailable
|| msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
if (mHardwareFaceUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
mHardwareFaceUnavailableRetryCount++;
@@ -1018,6 +1029,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
requireStrongAuthIfAllLockedOut();
}
if (isHwUnavailable && cameraPrivacyEnabled) {
errString = mContext.getString(R.string.kg_face_sensor_privacy_enabled);
}
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -1791,6 +1806,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLockPatternUtils = lockPatternUtils;
mAuthController = authController;
dumpManager.registerDumpable(getClass().getName(), this);
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
mHandler = new Handler(mainLooper) {
@Override
@@ -2476,6 +2492,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// This would need to be updated for multi-sensor devices
final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty()
&& mFaceSensorProperties.get(0).supportsFaceDetection;
mFaceAuthUserId = userId;
if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
} else {

View File

@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.app.NotificationManager;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
@@ -56,6 +57,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
@NonNull private final LockoutCache mLockoutCache;
@Nullable private final NotificationManager mNotificationManager;
@Nullable private ICancellationSignal mCancellationSignal;
@Nullable private SensorPrivacyManager mSensorPrivacyManager;
private final int[] mBiometricPromptIgnoreList;
private final int[] mBiometricPromptIgnoreListVendor;
@@ -81,6 +83,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
mUsageStats = usageStats;
mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class);
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
final Resources resources = getContext().getResources();
mBiometricPromptIgnoreList = resources.getIntArray(
@@ -108,7 +111,16 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
@Override
protected void startHalOperation() {
try {
mCancellationSignal = getFreshDaemon().authenticate(mOperationId);
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
getTargetUserId())) {
onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
} else {
mCancellationSignal = getFreshDaemon().authenticate(mOperationId);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting auth", e);
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);

View File

@@ -19,6 +19,8 @@ package com.android.server.biometrics.sensors.face.aidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.face.ISession;
@@ -41,6 +43,7 @@ public class FaceDetectClient extends AcquisitionClient<ISession> implements Det
private final boolean mIsStrongBiometric;
@Nullable private ICancellationSignal mCancellationSignal;
@Nullable private SensorPrivacyManager mSensorPrivacyManager;
public FaceDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
@NonNull IBinder token, long requestId,
@@ -51,6 +54,7 @@ public class FaceDetectClient extends AcquisitionClient<ISession> implements Det
BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
}
@Override
@@ -73,6 +77,14 @@ public class FaceDetectClient extends AcquisitionClient<ISession> implements Det
@Override
protected void startHalOperation() {
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, getTargetUserId())) {
onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
return;
}
try {
mCancellationSignal = getFreshDaemon().detectInteraction();
} catch (RemoteException e) {

View File

@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
@@ -55,6 +56,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
private final int[] mKeyguardIgnoreListVendor;
private int mLastAcquire;
private SensorPrivacyManager mSensorPrivacyManager;
FaceAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
@@ -71,6 +73,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
isKeyguardBypassEnabled);
setRequestId(requestId);
mUsageStats = usageStats;
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
final Resources resources = getContext().getResources();
mBiometricPromptIgnoreList = resources.getIntArray(
@@ -97,6 +100,15 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
@Override
protected void startHalOperation() {
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, getTargetUserId())) {
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
return;
}
try {
getFreshDaemon().authenticate(mOperationId);
} catch (RemoteException e) {