Merge "Add get/set feature implementation" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1203a1c628
@@ -133,11 +133,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFeatureGet(boolean success, int feature, boolean value) {
|
||||
public void onFeatureGet(boolean success, int[] features, boolean[] featureState) {
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = success;
|
||||
args.argi1 = feature;
|
||||
args.arg2 = value;
|
||||
args.arg2 = features;
|
||||
args.arg3 = featureState;
|
||||
mHandler.obtainMessage(MSG_GET_FEATURE_COMPLETED, args).sendToTarget();
|
||||
}
|
||||
|
||||
@@ -1088,7 +1088,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
* @hide
|
||||
*/
|
||||
public abstract static class GetFeatureCallback {
|
||||
public abstract void onCompleted(boolean success, int feature, boolean value);
|
||||
public abstract void onCompleted(boolean success, int[] features, boolean[] featureState);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1179,8 +1179,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
case MSG_GET_FEATURE_COMPLETED:
|
||||
SomeArgs args = (SomeArgs) msg.obj;
|
||||
sendGetFeatureCompleted((boolean) args.arg1 /* success */,
|
||||
args.argi1 /* feature */,
|
||||
(boolean) args.arg2 /* value */);
|
||||
(int[]) args.arg2 /* features */,
|
||||
(boolean[]) args.arg3 /* featureState */);
|
||||
args.recycle();
|
||||
break;
|
||||
case MSG_CHALLENGE_GENERATED:
|
||||
@@ -1216,11 +1216,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
mSetFeatureCallback.onCompleted(success, feature);
|
||||
}
|
||||
|
||||
private void sendGetFeatureCompleted(boolean success, int feature, boolean value) {
|
||||
private void sendGetFeatureCompleted(boolean success, int[] features, boolean[] featureState) {
|
||||
if (mGetFeatureCallback == null) {
|
||||
return;
|
||||
}
|
||||
mGetFeatureCallback.onCompleted(success, feature, value);
|
||||
mGetFeatureCallback.onCompleted(success, features, featureState);
|
||||
}
|
||||
|
||||
private void sendChallengeGenerated(int sensorId, long challenge) {
|
||||
|
||||
@@ -66,7 +66,8 @@ public class FaceServiceReceiver extends IFaceServiceReceiver.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFeatureGet(boolean success, int feature, boolean value) throws RemoteException {
|
||||
public void onFeatureGet(boolean success, int[] features, boolean[] featureState)
|
||||
throws RemoteException {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ oneway interface IFaceServiceReceiver {
|
||||
void onError(int error, int vendorCode);
|
||||
void onRemoved(in Face face, int remaining);
|
||||
void onFeatureSet(boolean success, int feature);
|
||||
void onFeatureGet(boolean success, int feature, boolean value);
|
||||
void onFeatureGet(boolean success, in int[] features, in boolean[] featureState);
|
||||
void onChallengeGenerated(int sensorId, long challenge);
|
||||
void onChallengeInterrupted(int sensorId);
|
||||
void onChallengeInterruptFinished(int sensorId);
|
||||
|
||||
@@ -146,9 +146,10 @@ public class ClientMonitorCallbackConverter {
|
||||
}
|
||||
}
|
||||
|
||||
public void onFeatureGet(boolean success, int feature, boolean value) throws RemoteException {
|
||||
public void onFeatureGet(boolean success, int[] features, boolean[] featureState)
|
||||
throws RemoteException {
|
||||
if (mFaceServiceReceiver != null) {
|
||||
mFaceServiceReceiver.onFeatureGet(success, feature, value);
|
||||
mFaceServiceReceiver.onFeatureGet(success, features, featureState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFeatureGet(boolean success, int feature, boolean value) {
|
||||
public void onFeatureGet(boolean success, int[] features, boolean[] featureState) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 com.android.server.biometrics.sensors.face.aidl;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricFaceConstants;
|
||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||
import android.hardware.biometrics.face.Feature;
|
||||
import android.hardware.biometrics.face.IFace;
|
||||
import android.hardware.biometrics.face.ISession;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.BiometricsProto;
|
||||
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
|
||||
import com.android.server.biometrics.sensors.ErrorConsumer;
|
||||
import com.android.server.biometrics.sensors.HalClientMonitor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Face-specific get feature client for the {@link IFace} AIDL HAL interface.
|
||||
*/
|
||||
public class FaceGetFeatureClient extends HalClientMonitor<ISession> implements ErrorConsumer {
|
||||
|
||||
private static final String TAG = "FaceGetFeatureClient";
|
||||
|
||||
private final int mUserId;
|
||||
|
||||
FaceGetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
|
||||
@NonNull IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
|
||||
@NonNull String owner, int sensorId) {
|
||||
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
|
||||
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN);
|
||||
mUserId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unableToStart() {
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(@NonNull Callback callback) {
|
||||
super.start(callback);
|
||||
startHalOperation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
getFreshDaemon().getFeatures();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to getFeature", e);
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_GET_FEATURE;
|
||||
}
|
||||
|
||||
public void onFeatureGet(boolean success, byte[] features) {
|
||||
HashMap<Integer, Boolean> featureMap = getFeatureMap();
|
||||
int[] featuresToSend = new int[featureMap.size()];
|
||||
boolean[] featureState = new boolean[featureMap.size()];
|
||||
|
||||
// The AIDL get feature api states that the presence of a feature means
|
||||
// it is enabled, while the lack thereof means its disabled.
|
||||
for (int i = 0; i < features.length; i++) {
|
||||
Integer feature = convertAidlToFrameworkFeature(features[i]);
|
||||
if (feature != null) {
|
||||
featureMap.put(feature, true);
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Map.Entry<Integer, Boolean> entry : featureMap.entrySet()) {
|
||||
featuresToSend[i] = entry.getKey();
|
||||
featureState[i] = entry.getValue();
|
||||
i++;
|
||||
}
|
||||
|
||||
boolean attentionEnabled = featureMap.get(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION);
|
||||
Slog.d(TAG, "Updating attention value for user: " + mUserId
|
||||
+ " to value: " + attentionEnabled);
|
||||
Settings.Secure.putIntForUser(getContext().getContentResolver(),
|
||||
Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED,
|
||||
attentionEnabled ? 1 : 0, mUserId);
|
||||
try {
|
||||
getListener().onFeatureGet(success, featuresToSend, featureState);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
}
|
||||
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
|
||||
private @NonNull HashMap<Integer, Boolean> getFeatureMap() {
|
||||
HashMap<Integer, Boolean> featureMap = new HashMap<>();
|
||||
featureMap.put(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION, false);
|
||||
return featureMap;
|
||||
}
|
||||
|
||||
private Integer convertAidlToFrameworkFeature(byte feature) {
|
||||
switch (feature) {
|
||||
case Feature.REQUIRE_ATTENTION:
|
||||
return new Integer(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, int vendorCode) {
|
||||
try {
|
||||
getListener().onFeatureGet(false /* success */, new int[0], new boolean[0]);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
}
|
||||
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -435,13 +435,36 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
public void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
|
||||
boolean enabled, @NonNull byte[] hardwareAuthToken,
|
||||
@NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
|
||||
// TODO(b/171335732): implement this.
|
||||
mHandler.post(() -> {
|
||||
final List<Face> faces = FaceUtils.getInstance(sensorId)
|
||||
.getBiometricsForUser(mContext, userId);
|
||||
if (faces.isEmpty()) {
|
||||
Slog.w(getTag(), "Ignoring setFeature, no templates enrolled for user: " + userId);
|
||||
return;
|
||||
}
|
||||
final FaceSetFeatureClient client = new FaceSetFeatureClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token,
|
||||
new ClientMonitorCallbackConverter(receiver), userId,
|
||||
mContext.getOpPackageName(), sensorId, feature, enabled, hardwareAuthToken);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleGetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
|
||||
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName) {
|
||||
// TODO(b/171335732): implement this.
|
||||
mHandler.post(() -> {
|
||||
final List<Face> faces = FaceUtils.getInstance(sensorId)
|
||||
.getBiometricsForUser(mContext, userId);
|
||||
if (faces.isEmpty()) {
|
||||
Slog.w(getTag(), "Ignoring getFeature, no templates enrolled for user: " + userId);
|
||||
return;
|
||||
}
|
||||
final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext,
|
||||
mSensors.get(sensorId).getLazySession(), token, callback, userId,
|
||||
mContext.getOpPackageName(), sensorId);
|
||||
scheduleForSensor(sensorId, client);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.server.biometrics.sensors.face.aidl;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricFaceConstants;
|
||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||
import android.hardware.biometrics.face.Feature;
|
||||
import android.hardware.biometrics.face.IFace;
|
||||
import android.hardware.biometrics.face.ISession;
|
||||
import android.hardware.keymaster.HardwareAuthToken;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.BiometricsProto;
|
||||
import com.android.server.biometrics.HardwareAuthTokenUtils;
|
||||
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
|
||||
import com.android.server.biometrics.sensors.ErrorConsumer;
|
||||
import com.android.server.biometrics.sensors.HalClientMonitor;
|
||||
|
||||
/**
|
||||
* Face-specific get feature client for the {@link IFace} AIDL HAL interface.
|
||||
*/
|
||||
public class FaceSetFeatureClient extends HalClientMonitor<ISession> implements ErrorConsumer {
|
||||
|
||||
private static final String TAG = "FaceSetFeatureClient";
|
||||
|
||||
private final int mFeature;
|
||||
private final boolean mEnabled;
|
||||
private final HardwareAuthToken mHardwareAuthToken;
|
||||
|
||||
FaceSetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
|
||||
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
|
||||
@NonNull String owner, int sensorId, int feature, boolean enabled,
|
||||
byte[] hardwareAuthToken) {
|
||||
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
|
||||
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
|
||||
BiometricsProtoEnums.CLIENT_UNKNOWN);
|
||||
mFeature = feature;
|
||||
mEnabled = enabled;
|
||||
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unableToStart() {
|
||||
try {
|
||||
getListener().onFeatureSet(false /* success */, mFeature);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to send error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(@NonNull Callback callback) {
|
||||
super.start(callback);
|
||||
startHalOperation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
getFreshDaemon()
|
||||
.setFeature(mHardwareAuthToken,
|
||||
convertFrameworkToAidlFeature(mFeature), mEnabled);
|
||||
} catch (RemoteException | IllegalArgumentException e) {
|
||||
Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e);
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return BiometricsProto.CM_SET_FEATURE;
|
||||
}
|
||||
|
||||
public void onFeatureSet(boolean success) {
|
||||
try {
|
||||
getListener().onFeatureSet(success, mFeature);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
}
|
||||
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
}
|
||||
|
||||
private byte convertFrameworkToAidlFeature(int feature) throws IllegalArgumentException {
|
||||
switch (feature) {
|
||||
case BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION:
|
||||
return Feature.REQUIRE_ATTENTION;
|
||||
default:
|
||||
Slog.e(TAG, "Unsupported feature : " + feature);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, int vendorCode) {
|
||||
try {
|
||||
getListener().onFeatureSet(false /* success */, mFeature);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
}
|
||||
|
||||
mCallback.onClientFinished(this, false /* success */);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -377,12 +377,32 @@ public class Sensor {
|
||||
|
||||
@Override
|
||||
public void onFeaturesRetrieved(byte[] features) {
|
||||
mHandler.post(() -> {
|
||||
final BaseClientMonitor client = mScheduler.getCurrentClient();
|
||||
if (!(client instanceof FaceGetFeatureClient)) {
|
||||
Slog.e(mTag, "onFeaturesRetrieved for non-get feature consumer: "
|
||||
+ Utils.getClientName(client));
|
||||
return;
|
||||
}
|
||||
final FaceGetFeatureClient faceGetFeatureClient = (FaceGetFeatureClient) client;
|
||||
faceGetFeatureClient.onFeatureGet(true /* success */, features);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFeatureSet(byte feature) {
|
||||
mHandler.post(() -> {
|
||||
final BaseClientMonitor client = mScheduler.getCurrentClient();
|
||||
if (!(client instanceof FaceSetFeatureClient)) {
|
||||
Slog.e(mTag, "onFeatureSet for non-set consumer: "
|
||||
+ Utils.getClientName(client));
|
||||
return;
|
||||
}
|
||||
|
||||
final FaceSetFeatureClient faceSetFeatureClient = (FaceSetFeatureClient) client;
|
||||
faceSetFeatureClient.onFeatureSet(true /* success */);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -94,7 +94,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFeatureGet(boolean success, int feature, boolean value) {
|
||||
public void onFeatureGet(boolean success, int[] features, boolean[] featureState) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public class FaceGetFeatureClient extends HalClientMonitor<IBiometricsFace> {
|
||||
public void unableToStart() {
|
||||
try {
|
||||
if (getListener() != null) {
|
||||
getListener().onFeatureGet(false /* success */, mFeature, false /* value */);
|
||||
getListener().onFeatureGet(false /* success */, new int[0], new boolean[0]);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to send error", e);
|
||||
@@ -75,9 +75,14 @@ public class FaceGetFeatureClient extends HalClientMonitor<IBiometricsFace> {
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
final OptionalBool result = getFreshDaemon().getFeature(mFeature, mFaceId);
|
||||
int[] features = new int[1];
|
||||
boolean[] featureState = new boolean[1];
|
||||
features[0] = mFeature;
|
||||
featureState[0] = result.value;
|
||||
mValue = result.value;
|
||||
|
||||
if (getListener() != null) {
|
||||
getListener().onFeatureGet(result.status == Status.OK, mFeature, mValue);
|
||||
getListener().onFeatureGet(result.status == Status.OK, features, featureState);
|
||||
}
|
||||
mCallback.onClientFinished(this, true /* success */);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
Reference in New Issue
Block a user