Make get/set feature async between settings and service

Fixes: 127382095

Test: None
Change-Id: Ib5495bf5a39bc3a2939aad5c721e32375dd9dde3
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 3e8c334..6035f40 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -45,6 +45,7 @@
 import android.util.Slog;
 
 import com.android.internal.R;
+import com.android.internal.os.SomeArgs;
 
 import java.util.List;
 
@@ -63,6 +64,8 @@
     private static final int MSG_AUTHENTICATION_FAILED = 103;
     private static final int MSG_ERROR = 104;
     private static final int MSG_REMOVED = 105;
+    private static final int MSG_GET_FEATURE_COMPLETED = 106;
+    private static final int MSG_SET_FEATURE_COMPLETED = 107;
 
     private IFaceService mService;
     private final Context mContext;
@@ -70,6 +73,8 @@
     private AuthenticationCallback mAuthenticationCallback;
     private EnrollmentCallback mEnrollmentCallback;
     private RemovalCallback mRemovalCallback;
+    private SetFeatureCallback mSetFeatureCallback;
+    private GetFeatureCallback mGetFeatureCallback;
     private CryptoObject mCryptoObject;
     private Face mRemovalFace;
     private Handler mHandler;
@@ -112,6 +117,20 @@
         public void onEnumerated(long deviceId, int faceId, int remaining) {
             // TODO: Finish. Low priority since it's not used.
         }
+
+        @Override
+        public void onFeatureSet(boolean success, int feature) {
+            mHandler.obtainMessage(MSG_SET_FEATURE_COMPLETED, feature, 0, success).sendToTarget();
+        }
+
+        @Override
+        public void onFeatureGet(boolean success, int feature, boolean value) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = success;
+            args.argi1 = feature;
+            args.arg2 = value;
+            mHandler.obtainMessage(MSG_GET_FEATURE_COMPLETED, args).sendToTarget();
+        }
     };
 
     /**
@@ -286,31 +305,31 @@
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public boolean setFeature(int feature, boolean enabled, byte[] token) {
+    public void setFeature(int feature, boolean enabled, byte[] token,
+            SetFeatureCallback callback) {
         if (mService != null) {
             try {
-                return mService.setFeature(feature, enabled, token);
+                mSetFeatureCallback = callback;
+                mService.setFeature(feature, enabled, token, mServiceReceiver);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
         }
-        return false;
     }
 
     /**
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public boolean getFeature(int feature) {
-        boolean result = true;
+    public void getFeature(int feature, GetFeatureCallback callback) {
         if (mService != null) {
             try {
-                result = mService.getFeature(feature);
+                mGetFeatureCallback = callback;
+                mService.getFeature(feature, mServiceReceiver);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
         }
-        return result;
     }
 
     /**
@@ -874,6 +893,20 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    public abstract static class SetFeatureCallback {
+        public abstract void onCompleted(boolean success, int feature);
+    }
+
+    /**
+     * @hide
+     */
+    public abstract static class GetFeatureCallback {
+        public abstract void onCompleted(boolean success, int feature, boolean value);
+    }
+
     private class OnEnrollCancelListener implements OnCancelListener {
         @Override
         public void onCancel() {
@@ -926,9 +959,36 @@
                 case MSG_REMOVED:
                     sendRemovedResult((Face) msg.obj, msg.arg1 /* remaining */);
                     break;
+                case MSG_SET_FEATURE_COMPLETED:
+                    sendSetFeatureCompleted((boolean) msg.obj /* success */,
+                            msg.arg1 /* feature */);
+                    break;
+                case MSG_GET_FEATURE_COMPLETED:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    sendGetFeatureCompleted((boolean) args.arg1 /* success */,
+                            args.argi1 /* feature */,
+                            (boolean) args.arg2 /* value */);
+                    args.recycle();
+                    break;
+                default:
+                    Log.w(TAG, "Unknown message: " + msg.what);
             }
         }
-    };
+    }
+
+    private void sendSetFeatureCompleted(boolean success, int feature) {
+        if (mSetFeatureCallback == null) {
+            return;
+        }
+        mSetFeatureCallback.onCompleted(success, feature);
+    }
+
+    private void sendGetFeatureCompleted(boolean success, int feature, boolean value) {
+        if (mGetFeatureCallback == null) {
+            return;
+        }
+        mGetFeatureCallback.onCompleted(success, feature, value);
+    }
 
     private void sendRemovedResult(Face face, int remaining) {
         if (mRemovalCallback == null) {
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 5043d4c..601be75 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -51,7 +51,7 @@
 
     // Start face enrollment
     void enroll(IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
-                String opPackageName, in int [] disabledFeatures);
+            String opPackageName, in int [] disabledFeatures);
 
     // Cancel enrollment in progress
     void cancelEnrollment(IBinder token);
@@ -98,9 +98,10 @@
     // Enumerate all faces
     void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver);
 
-    boolean setFeature(int feature, boolean enabled, in byte [] token);
+    void setFeature(int feature, boolean enabled, in byte [] token,
+            IFaceServiceReceiver receiver);
 
-    boolean getFeature(int feature);
+    void getFeature(int feature, IFaceServiceReceiver receiver);
 
     void userActivity();
 }
diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
index cec9fd8..2176902 100644
--- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl
+++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
@@ -29,4 +29,6 @@
     void onError(long deviceId, int error, int vendorCode);
     void onRemoved(long deviceId, int faceId, int remaining);
     void onEnumerated(long deviceId, int faceId, int remaining);
+    void onFeatureSet(boolean success, int feature);
+    void onFeatureGet(boolean success, int feature, boolean value);
 }
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 5e4bf33..c573bbb 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -397,61 +397,62 @@
         }
 
         @Override
-        public boolean setFeature(int feature, boolean enabled, final byte[] token) {
+        public void setFeature(int feature, boolean enabled, final byte[] token,
+                IFaceServiceReceiver receiver) {
             checkPermission(MANAGE_BIOMETRIC);
 
-            if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
-                Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature);
-                return false;
-            }
-
-            final ArrayList<Byte> byteToken = new ArrayList<>();
-            for (int i = 0; i < token.length; i++) {
-                byteToken.add(token[i]);
-            }
-
-            // TODO: Support multiple faces
-            final int faceId = getFirstTemplateForUser(mCurrentUserId);
-
-            if (mDaemon != null) {
-                try {
-                    return mDaemon.setFeature(feature, enabled, byteToken, faceId) == Status.OK;
-                } catch (RemoteException e) {
-                    Slog.e(getTag(), "Unable to set feature: " + feature + " to enabled:" + enabled,
-                            e);
+            mHandler.post(() -> {
+                if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
+                    Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature);
+                    return;
                 }
-            }
-            return false;
+
+                final ArrayList<Byte> byteToken = new ArrayList<>();
+                for (int i = 0; i < token.length; i++) {
+                    byteToken.add(token[i]);
+                }
+
+                // TODO: Support multiple faces
+                final int faceId = getFirstTemplateForUser(mCurrentUserId);
+
+                if (mDaemon != null) {
+                    try {
+                        final int result = mDaemon.setFeature(feature, enabled, byteToken, faceId);
+                        receiver.onFeatureSet(result == Status.OK, feature);
+                    } catch (RemoteException e) {
+                        Slog.e(getTag(), "Unable to set feature: " + feature
+                                        + " to enabled:" + enabled, e);
+                    }
+                }
+            });
+
         }
 
         @Override
-        public boolean getFeature(int feature) {
+        public void getFeature(int feature, IFaceServiceReceiver receiver) {
             checkPermission(MANAGE_BIOMETRIC);
 
-            // This should ideally return tri-state, but the user isn't shown settings unless
-            // they are enrolled so it's fine for now.
-            if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
-                Slog.e(TAG, "No enrolled biometrics while getting feature: " + feature);
-                return false;
-            }
-
-            // TODO: Support multiple faces
-            final int faceId = getFirstTemplateForUser(mCurrentUserId);
-
-            if (mDaemon != null) {
-                try {
-                    OptionalBool result = mDaemon.getFeature(feature, faceId);
-                    if (result.status == Status.OK) {
-                        return result.value;
-                    } else {
-                        // Same tri-state comment applies here.
-                        return false;
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(getTag(), "Unable to getRequireAttention", e);
+            mHandler.post(() -> {
+                // This should ideally return tri-state, but the user isn't shown settings unless
+                // they are enrolled so it's fine for now.
+                if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
+                    Slog.e(TAG, "No enrolled biometrics while getting feature: " + feature);
+                    return;
                 }
-            }
-            return false;
+
+                // TODO: Support multiple faces
+                final int faceId = getFirstTemplateForUser(mCurrentUserId);
+
+                if (mDaemon != null) {
+                    try {
+                        OptionalBool result = mDaemon.getFeature(feature, faceId);
+                        receiver.onFeatureGet(result.status == Status.OK, feature, result.value);
+                    } catch (RemoteException e) {
+                        Slog.e(getTag(), "Unable to getRequireAttention", e);
+                    }
+                }
+            });
+
         }
 
         @Override