Merge changes from topic "biometric-prompt-service"

* changes:
  Add BiometricPromptService
  Remove common biometric directory
diff --git a/Android.bp b/Android.bp
index 759014f..39da11f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -151,6 +151,8 @@
         ":libcamera_client_framework_aidl",
         "core/java/android/hardware/IConsumerIrService.aidl",
         "core/java/android/hardware/ISerialManager.aidl",
+        "core/java/android/hardware/biometrics/IBiometricPromptService.aidl",
+        "core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl",
         "core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
         "core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
         "core/java/android/hardware/display/IDisplayManager.aidl",
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a352e84..4fb21f3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3672,6 +3672,15 @@
     public static final String AUDIO_SERVICE = "audio";
 
     /**
+     * Use with {@link #getSystemService(String)}
+     *
+     * @hide
+     * @see #getSystemService(String)
+     * @see com.android.server.biometrics.BiometricPromptService
+     */
+    public static final String BIOMETRIC_PROMPT_SERVICE = "biometric_prompt";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.fingerprint.FingerprintManager} for handling management
      * of fingerprints.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ac2f1ce..7d8ff4c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2281,6 +2281,14 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device has biometric hardware to perform iris authentication.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_IRIS = "android.hardware.iris";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports portrait orientation
      * screens.  For backwards compatibility, you can assume that if neither
      * this nor {@link #FEATURE_SCREEN_LANDSCAPE} is set then the device supports
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index e7c5116..59195dc 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -161,12 +161,6 @@
         public void onAuthenticationHelp(int helpCode, CharSequence helpString) {}
 
         /**
-         * Called when a biometric is recognized.
-         * @param result An object containing authentication-related data
-         */
-        public void onAuthenticationSucceeded(AuthenticationResult result) {}
-
-        /**
          * Called when a biometric is valid but not recognized.
          */
         public void onAuthenticationFailed() {}
@@ -179,6 +173,29 @@
     };
 
     /**
+     * @return true if the biometric hardware is detected.
+     */
+    default boolean isHardwareDetected() {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    /**
+     * @return true if the user has enrolled templates for this biometric.
+     */
+    default boolean hasEnrolledTemplates() {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    /**
+     * @param error
+     * @param vendorCode
+     * @return the error string associated with this error
+     */
+    default String getErrorString(int error, int vendorCode) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    /**
      * This call warms up the hardware and starts scanning for valid biometrics. It terminates
      * when {@link AuthenticationCallback#onAuthenticationError(int,
      * CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
@@ -198,10 +215,12 @@
      * @param executor An executor to handle callback events
      * @param callback An object to receive authentication events
      */
-    void authenticate(@NonNull CryptoObject crypto,
+    default void authenticate(@NonNull CryptoObject crypto,
             @NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull AuthenticationCallback callback);
+            @NonNull AuthenticationCallback callback) {
+        throw new UnsupportedOperationException("Stub!");
+    }
 
     /**
      * This call warms up the hardware and starts scanning for valid biometrics. It terminates
@@ -221,7 +240,9 @@
      * @param executor An executor to handle callback events
      * @param callback An object to receive authentication events
      */
-    void authenticate(@NonNull CancellationSignal cancel,
+    default void authenticate(@NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull AuthenticationCallback callback);
+            @NonNull AuthenticationCallback callback) {
+        throw new UnsupportedOperationException("Stub!");
+    }
 }
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index f83e847..6150be3 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -175,5 +175,5 @@
     /**
      * @hide
      */
-    int BIOMETRICT_ACQUIRED_VENDOR_BASE = 1000;
+    int BIOMETRIC_ACQUIRED_VENDOR_BASE = 1000;
 }
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 4aa1e76..c788bc5 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -229,7 +229,8 @@
      *
      * @hide
      */
-    public static final int FACE_ACQUIRED_VENDOR = 13;
+    public static final int FACE_ACQUIRED_VENDOR = 14;
+
     /**
      * @hide
      */
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 02bcff5..1cca27d 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -20,14 +20,20 @@
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.pm.PackageManager;
-import android.hardware.fingerprint.FingerprintManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
 
 import java.security.Signature;
 import java.util.concurrent.Executor;
@@ -40,6 +46,8 @@
  */
 public class BiometricPrompt implements BiometricAuthenticator, BiometricConstants {
 
+    private static final String TAG = "BiometricPrompt";
+
     /**
      * @hide
      */
@@ -208,11 +216,23 @@
         }
     }
 
-    private PackageManager mPackageManager;
-    private FingerprintManager mFingerprintManager;
-    private Bundle mBundle;
-    private ButtonInfo mPositiveButtonInfo;
-    private ButtonInfo mNegativeButtonInfo;
+    private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener {
+        @Override
+        public void onCancel() {
+            cancelAuthentication();
+        }
+    }
+
+    private final IBinder mToken = new Binder();
+    private final Context mContext;
+    private final IBiometricPromptService mService;
+    private final Bundle mBundle;
+    private final ButtonInfo mPositiveButtonInfo;
+    private final ButtonInfo mNegativeButtonInfo;
+
+    private CryptoObject mCryptoObject;
+    private Executor mExecutor;
+    private AuthenticationCallback mAuthenticationCallback;
 
     IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
         @Override
@@ -230,13 +250,48 @@
         }
     };
 
+    IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver =
+            new IBiometricPromptServiceReceiver.Stub() {
+
+        @Override
+        public void onAuthenticationSucceeded(long deviceId) throws RemoteException {
+            mExecutor.execute(() -> {
+                final AuthenticationResult result = new AuthenticationResult(mCryptoObject);
+                mAuthenticationCallback.onAuthenticationSucceeded(result);
+            });
+        }
+
+        @Override
+        public void onAuthenticationFailed(long deviceId) throws RemoteException {
+            mExecutor.execute(() -> {
+                mAuthenticationCallback.onAuthenticationFailed();
+            });
+        }
+
+        @Override
+        public void onError(long deviceId, int error, String message)
+                throws RemoteException {
+            mExecutor.execute(() -> {
+                mAuthenticationCallback.onAuthenticationError(error, message);
+            });
+        }
+
+        @Override
+        public void onAcquired(long deviceId, int acquireInfo, String message) {
+            mExecutor.execute(() -> {
+                mAuthenticationCallback.onAuthenticationHelp(acquireInfo, message);
+            });
+        }
+    };
+
     private BiometricPrompt(Context context, Bundle bundle,
             ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) {
+        mContext = context;
         mBundle = bundle;
         mPositiveButtonInfo = positiveButtonInfo;
         mNegativeButtonInfo = negativeButtonInfo;
-        mFingerprintManager = context.getSystemService(FingerprintManager.class);
-        mPackageManager = context.getPackageManager();
+        mService = IBiometricPromptService.Stub.asInterface(
+                ServiceManager.getService(Context.BIOMETRIC_PROMPT_SERVICE));
     }
 
     /**
@@ -290,13 +345,12 @@
         /**
          * Authentication result
          * @param crypto
-         * @param identifier
-         * @param userId
          * @hide
          */
-        public AuthenticationResult(CryptoObject crypto, Identifier identifier,
-                int userId) {
-            super(crypto, identifier, userId);
+        public AuthenticationResult(CryptoObject crypto) {
+            // For compatibility, this extends from common base class as FingerprintManager does.
+            // Identifier and userId is not used for BiometricPrompt.
+            super(crypto, null /* identifier */, 0 /* userId */);
         }
         /**
          * Obtain the crypto object associated with this transaction
@@ -353,53 +407,6 @@
          */
         @Override
         public void onAuthenticationAcquired(int acquireInfo) {}
-
-        /**
-         * @param result An object containing authentication-related data
-         * @hide
-         */
-        @Override
-        public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
-            onAuthenticationSucceeded(new AuthenticationResult(
-                    (CryptoObject) result.getCryptoObject(),
-                    result.getId(),
-                    result.getUserId()));
-        }
-    }
-
-    /**
-     * @param crypto Object associated with the call
-     * @param cancel An object that can be used to cancel authentication
-     * @param executor An executor to handle callback events
-     * @param callback An object to receive authentication events
-     * @hide
-     */
-    @Override
-    public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
-            @NonNull CancellationSignal cancel,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        if (!(callback instanceof BiometricPrompt.AuthenticationCallback)) {
-            throw new IllegalArgumentException("Callback cannot be casted");
-        }
-        authenticate(crypto, cancel, executor, (AuthenticationCallback) callback);
-    }
-
-    /**
-     *
-     * @param cancel An object that can be used to cancel authentication
-     * @param executor An executor to handle callback events
-     * @param callback An object to receive authentication events
-     * @hide
-     */
-    @Override
-    public void authenticate(@NonNull CancellationSignal cancel,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        if (!(callback instanceof BiometricPrompt.AuthenticationCallback)) {
-            throw new IllegalArgumentException("Callback cannot be casted");
-        }
-        authenticate(cancel, executor, (AuthenticationCallback) callback);
     }
 
     /**
@@ -430,11 +437,19 @@
             @NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AuthenticationCallback callback) {
-        if (handlePreAuthenticationErrors(callback, executor)) {
-            return;
+        if (crypto == null) {
+            throw new IllegalArgumentException("Must supply a crypto object");
         }
-        mFingerprintManager.authenticate(crypto, cancel, mBundle, executor, mDialogReceiver,
-                callback);
+        if (cancel == null) {
+            throw new IllegalArgumentException("Must supply a cancellation signal");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must supply an executor");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("Must supply a callback");
+        }
+        authenticateInternal(crypto, cancel, executor, callback);
     }
 
     /**
@@ -462,34 +477,53 @@
     public void authenticate(@NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AuthenticationCallback callback) {
-        if (handlePreAuthenticationErrors(callback, executor)) {
-            return;
+        if (cancel == null) {
+            throw new IllegalArgumentException("Must supply a cancellation signal");
         }
-        mFingerprintManager.authenticate(cancel, mBundle, executor, mDialogReceiver, callback);
+        if (executor == null) {
+            throw new IllegalArgumentException("Must supply an executor");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("Must supply a callback");
+        }
+        authenticateInternal(null /* crypto */, cancel, executor, callback);
     }
 
-    private boolean handlePreAuthenticationErrors(AuthenticationCallback callback,
-            Executor executor) {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
-            sendError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT, callback,
-                      executor);
-            return true;
-        } else if (!mFingerprintManager.isHardwareDetected()) {
-            sendError(BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, callback,
-                      executor);
-            return true;
-        } else if (!mFingerprintManager.hasEnrolledFingerprints()) {
-            sendError(BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS, callback,
-                      executor);
-            return true;
+    private void cancelAuthentication() {
+        if (mService != null) {
+            try {
+                mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to cancel authentication", e);
+            }
         }
-        return false;
     }
 
-    private void sendError(int error, AuthenticationCallback callback, Executor executor) {
-        executor.execute(() -> {
-            callback.onAuthenticationError(error, mFingerprintManager.getErrorString(
-                    error, 0 /* vendorCode */));
-        });
+    private void authenticateInternal(@Nullable CryptoObject crypto,
+            @NonNull CancellationSignal cancel,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull AuthenticationCallback callback) {
+        try {
+            if (cancel.isCanceled()) {
+                Log.w(TAG, "Authentication already canceled");
+                return;
+            } else {
+                cancel.setOnCancelListener(new OnAuthenticationCancelListener());
+            }
+
+            mCryptoObject = crypto;
+            mExecutor = executor;
+            mAuthenticationCallback = callback;
+            final long sessionId = crypto != null ? crypto.getOpId() : 0;
+            mService.authenticate(mToken, sessionId, mContext.getUserId(),
+                    mBiometricPromptServiceReceiver, 0 /* flags */, mContext.getOpPackageName(),
+                    mBundle, mDialogReceiver);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote exception while authenticating", e);
+            mExecutor.execute(() -> {
+                callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+                        mContext.getString(R.string.biometric_error_hw_unavailable));
+            });
+        }
     }
 }
diff --git a/core/java/android/hardware/biometrics/IBiometricPromptService.aidl b/core/java/android/hardware/biometrics/IBiometricPromptService.aidl
new file mode 100644
index 0000000..2c93579
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IBiometricPromptService.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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 android.hardware.biometrics;
+
+import android.os.Bundle;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+
+/**
+ * Communication channel from BiometricPrompt to BiometricPromptService. The interface does not
+ * expose specific biometric modalities. The system will use the default biometric for apps. On
+ * devices with more than one, the choice is dictated by user preference in Settings.
+ * @hide
+ */
+interface IBiometricPromptService {
+    // Requests authentication. The service choose the appropriate biometric to use, and show
+    // the corresponding BiometricDialog.
+    void authenticate(IBinder token, long sessionId, int userId,
+            IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+            in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
+
+    // Cancel authentication for the given sessionId
+    void cancelAuthentication(IBinder token, String opPackageName);
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl
new file mode 100644
index 0000000..1ef6c52
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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 android.hardware.biometrics;
+
+import android.hardware.biometrics.BiometricSourceType;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Communication channel from the BiometricPromptService back to BiometricPrompt.
+ * @hide
+ */
+oneway interface IBiometricPromptServiceReceiver {
+    void onAuthenticationSucceeded(long deviceId);
+    void onAuthenticationFailed(long deviceId);
+    void onError(long deviceId, int error, String message);
+    void onAcquired(long deviceId, int acquiredInfo, String message);
+}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 6a3dd7d..b3b962f 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -17,10 +17,9 @@
 package android.hardware.face;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.MANAGE_FACE;
-import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 
-import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -28,13 +27,11 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricFaceConstants;
-import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.CryptoObject;
-import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.CancellationSignal.OnCancelListener;
 import android.os.Handler;
@@ -50,15 +47,13 @@
 import com.android.internal.R;
 
 import java.util.List;
-import java.util.concurrent.Executor;
 
 /**
  * A class that coordinates access to the face authentication hardware.
  * @hide
  */
 @SystemService(Context.FACE_SERVICE)
-public class FaceManager implements BiometricFaceConstants {
-
+public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
 
     private static final String TAG = "FaceManager";
     private static final boolean DEBUG = true;
@@ -72,13 +67,12 @@
     private IFaceService mService;
     private final Context mContext;
     private IBinder mToken = new Binder();
-    private BiometricAuthenticator.AuthenticationCallback mAuthenticationCallback;
+    private AuthenticationCallback mAuthenticationCallback;
     private EnrollmentCallback mEnrollmentCallback;
     private RemovalCallback mRemovalCallback;
     private CryptoObject mCryptoObject;
     private Face mRemovalFace;
     private Handler mHandler;
-    private Executor mExecutor;
 
     private IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() {
 
@@ -147,7 +141,7 @@
      * @throws IllegalStateException    if the crypto primitive is not initialized.
      * @hide
      */
-    @RequiresPermission(USE_BIOMETRIC)
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
             int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
         if (callback == null) {
@@ -170,7 +164,7 @@
                 mCryptoObject = crypto;
                 long sessionId = crypto != null ? crypto.getOpId() : 0;
                 mService.authenticate(mToken, sessionId, mServiceReceiver, flags,
-                        mContext.getOpPackageName(), null /* bundle */, null /* receiver */);
+                        mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.w(TAG, "Remote exception while authenticating: ", e);
                 if (callback != null) {
@@ -195,108 +189,6 @@
     }
 
     /**
-     * This method invokes the BiometricPrompt.
-     */
-    private void authenticateWithPrompt(@Nullable android.hardware.biometrics.CryptoObject crypto,
-            @NonNull CancellationSignal cancel,
-            @NonNull Bundle bundle,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricPromptReceiver receiver,
-            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        mCryptoObject = crypto;
-        if (cancel.isCanceled()) {
-            Slog.w(TAG, "authentication already canceled");
-            return;
-        } else {
-            cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
-        }
-
-        if (mService != null) {
-            try {
-                mExecutor = executor;
-                mAuthenticationCallback = callback;
-                final long sessionId = crypto != null ? crypto.getOpId() : 0;
-                mService.authenticate(mToken, sessionId, mServiceReceiver,
-                        0 /* flags */, mContext.getOpPackageName(), bundle, receiver);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Remote exception while authenticating", e);
-                mExecutor.execute(() -> {
-                    callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
-                            getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
-                });
-            }
-        }
-    }
-
-    /**
-     * Private method, see {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
-     * BiometricPrompt.AuthenticationCallback)}
-     * @param cancel
-     * @param executor
-     * @param callback
-     * @hide
-     */
-    public void authenticate(
-            @NonNull CancellationSignal cancel,
-            @NonNull Bundle bundle,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricPromptReceiver receiver,
-            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        if (cancel == null) {
-            throw new IllegalArgumentException("Must supply a cancellation signal");
-        }
-        if (bundle == null) {
-            throw new IllegalArgumentException("Must supply a bundle");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException("Must supply an executor");
-        }
-        if (receiver == null) {
-            throw new IllegalArgumentException("Must supply a receiver");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("Must supply a calback");
-        }
-        authenticateWithPrompt(null, cancel, bundle, executor, receiver, callback);
-    }
-
-    /**
-     * Private method, see {@link BiometricPrompt#authenticate(BiometricPrompt.CryptoObject,
-     * CancellationSignal, Executor, BiometricPrompt.AuthenticationCallback)}
-     * @param crypto
-     * @param cancel
-     * @param executor
-     * @param callback
-     * @hide
-     */
-    public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
-            @NonNull CancellationSignal cancel,
-            @NonNull Bundle bundle,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricPromptReceiver receiver,
-            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        if (crypto == null) {
-            throw new IllegalArgumentException("Must supply a crypto object");
-        }
-        if (cancel == null) {
-            throw new IllegalArgumentException("Must supply a cancellation signal");
-        }
-        if (bundle == null) {
-            throw new IllegalArgumentException("Must supply a bundle");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException("Must supply an executor");
-        }
-        if (receiver == null) {
-            throw new IllegalArgumentException("Must supply a receiver");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("Must supply a callback");
-        }
-        authenticateWithPrompt(crypto, cancel, bundle, executor, receiver, callback);
-    }
-
-    /**
      * Request face authentication enrollment. This call operates the face authentication hardware
      * and starts capturing images. Progress will be indicated by callbacks to the
      * {@link EnrollmentCallback} object. It terminates when
@@ -313,7 +205,7 @@
      * @param callback an object to receive enrollment events
      * @hide
      */
-    @RequiresPermission(MANAGE_FACE)
+    @RequiresPermission(MANAGE_BIOMETRIC)
     public void enroll(byte[] token, CancellationSignal cancel, int flags,
             int userId, EnrollmentCallback callback) {
         if (userId == UserHandle.USER_CURRENT) {
@@ -355,7 +247,7 @@
      *
      * @hide
      */
-    @RequiresPermission(MANAGE_FACE)
+    @RequiresPermission(MANAGE_BIOMETRIC)
     public long preEnroll() {
         long result = 0;
         if (mService != null) {
@@ -373,7 +265,7 @@
      *
      * @hide
      */
-    @RequiresPermission(MANAGE_FACE)
+    @RequiresPermission(MANAGE_BIOMETRIC)
     public int postEnroll() {
         int result = 0;
         if (mService != null) {
@@ -392,7 +284,7 @@
      *
      * @hide
      */
-    @RequiresPermission(MANAGE_FACE)
+    @RequiresPermission(MANAGE_BIOMETRIC)
     public void setActiveUser(int userId) {
         if (mService != null) {
             try {
@@ -412,7 +304,7 @@
      *                 successfully removed. May be null if no callback is required.
      * @hide
      */
-    @RequiresPermission(MANAGE_FACE)
+    @RequiresPermission(MANAGE_BIOMETRIC)
     public void remove(Face face, int userId, RemovalCallback callback) {
         if (mService != null) {
             try {
@@ -435,7 +327,7 @@
      * @return the current face item
      * @hide
      */
-    @RequiresPermission(USE_BIOMETRIC)
+    @RequiresPermission(MANAGE_BIOMETRIC)
     public List<Face> getEnrolledFaces(int userId) {
         if (mService != null) {
             try {
@@ -453,7 +345,7 @@
      * @return the current face item
      * @hide
      */
-    @RequiresPermission(USE_BIOMETRIC)
+    @RequiresPermission(MANAGE_BIOMETRIC)
     public List<Face> getEnrolledFaces() {
         return getEnrolledFaces(UserHandle.myUserId());
     }
@@ -463,8 +355,9 @@
      *
      * @return true if a face is enrolled, false otherwise
      */
-    @RequiresPermission(USE_BIOMETRIC)
-    public boolean hasEnrolledFaces() {
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    @Override
+    public boolean hasEnrolledTemplates() {
         if (mService != null) {
             try {
                 return mService.hasEnrolledFaces(
@@ -480,9 +373,9 @@
      * @hide
      */
     @RequiresPermission(allOf = {
-            USE_BIOMETRIC,
+            USE_BIOMETRIC_INTERNAL,
             INTERACT_ACROSS_USERS})
-    public boolean hasEnrolledFaces(int userId) {
+    public boolean hasEnrolledTemplates(int userId) {
         if (mService != null) {
             try {
                 return mService.hasEnrolledFaces(userId, mContext.getOpPackageName());
@@ -498,7 +391,8 @@
      *
      * @return true if hardware is present and functional, false otherwise.
      */
-    @RequiresPermission(USE_BIOMETRIC)
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    @Override
     public boolean isHardwareDetected() {
         if (mService != null) {
             try {
@@ -538,6 +432,7 @@
      * @param token an opaque token returned by password confirmation.
      * @hide
      */
+    @RequiresPermission(MANAGE_BIOMETRIC)
     public void resetTimeout(byte[] token) {
         if (mService != null) {
             try {
@@ -553,6 +448,7 @@
     /**
      * @hide
      */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
     public void addLockoutResetCallback(final LockoutResetCallback callback) {
         if (mService != null) {
             try {
@@ -617,7 +513,8 @@
         }
     }
 
-    private String getErrorString(int errMsg, int vendorCode) {
+    @Override
+    public String getErrorString(int errMsg, int vendorCode) {
         switch (errMsg) {
             case FACE_ERROR_HW_UNAVAILABLE:
                 return mContext.getString(
@@ -652,7 +549,10 @@
         return null;
     }
 
-    private String getAcquiredString(int acquireInfo, int vendorCode) {
+    /**
+     * @hide
+     */
+    public String getAcquiredString(int acquireInfo, int vendorCode) {
         switch (acquireInfo) {
             case FACE_ACQUIRED_GOOD:
                 return null;
@@ -691,6 +591,37 @@
     }
 
     /**
+     * Used so BiometricPrompt can map the face ones onto existing public constants.
+     * @hide
+     */
+    public int getMappedAcquiredInfo(int acquireInfo, int vendorCode) {
+        switch (acquireInfo) {
+            case FACE_ACQUIRED_GOOD:
+                return BiometricConstants.BIOMETRIC_ACQUIRED_GOOD;
+            case FACE_ACQUIRED_INSUFFICIENT:
+            case FACE_ACQUIRED_TOO_BRIGHT:
+            case FACE_ACQUIRED_TOO_DARK:
+                return BiometricConstants.BIOMETRIC_ACQUIRED_INSUFFICIENT;
+            case FACE_ACQUIRED_TOO_CLOSE:
+            case FACE_ACQUIRED_TOO_FAR:
+            case FACE_ACQUIRED_TOO_HIGH:
+            case FACE_ACQUIRED_TOO_LOW:
+            case FACE_ACQUIRED_TOO_RIGHT:
+            case FACE_ACQUIRED_TOO_LEFT:
+                return BiometricConstants.BIOMETRIC_ACQUIRED_PARTIAL;
+            case FACE_ACQUIRED_POOR_GAZE:
+            case FACE_ACQUIRED_NOT_DETECTED:
+            case FACE_ACQUIRED_TOO_MUCH_MOTION:
+            case FACE_ACQUIRED_RECALIBRATE:
+                return BiometricConstants.BIOMETRIC_ACQUIRED_INSUFFICIENT;
+            case FACE_ACQUIRED_VENDOR:
+                return BiometricConstants.BIOMETRIC_ACQUIRED_VENDOR_BASE + vendorCode;
+            default:
+                return BiometricConstants.BIOMETRIC_ACQUIRED_GOOD;
+        }
+    }
+
+    /**
      * Container for callback data from {@link FaceManager#authenticate(CryptoObject,
      * CancellationSignal, int, AuthenticationCallback, Handler)}.
      */
@@ -796,18 +727,6 @@
          */
         public void onAuthenticationAcquired(int acquireInfo) {
         }
-
-        /**
-         * @hide
-         * @param result
-         */
-        @Override
-        public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
-            onAuthenticationSucceeded(new AuthenticationResult(
-                    result.getCryptoObject(),
-                    (Face) result.getId(), result.getUserId()));
-        }
-
     }
 
     /**
@@ -988,8 +907,8 @@
 
     private void sendAuthenticatedSucceeded(Face face, int userId) {
         if (mAuthenticationCallback != null) {
-            final BiometricAuthenticator.AuthenticationResult result =
-                    new BiometricAuthenticator.AuthenticationResult(mCryptoObject, face, userId);
+            final AuthenticationResult result =
+                    new AuthenticationResult(mCryptoObject, face, userId);
             mAuthenticationCallback.onAuthenticationSucceeded(result);
         }
     }
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 03bb7ae..dd995c9 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -17,23 +17,35 @@
 
 import android.os.Bundle;
 import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricPromptServiceReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.face.IFaceServiceReceiver;
 import android.hardware.face.Face;
 
 /**
- * Communication channel from client to the face service.
+ * Communication channel from client to the face service. These methods are all require the
+ * MANAGE_BIOMETRIC signature permission.
  * @hide
  */
 interface IFaceService {
     // Authenticate the given sessionId with a face
     void authenticate(IBinder token, long sessionId,
-            IFaceServiceReceiver receiver, int flags, String opPackageName,
-            in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
+            IFaceServiceReceiver receiver, int flags, String opPackageName);
+
+    // This method invokes the BiometricDialog. The arguments are almost the same as above,
+    // but should only be called from (BiometricPromptService).
+    void authenticateFromService(IBinder token, long sessionId, int userId,
+            IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+            in Bundle bundle, IBiometricPromptReceiver dialogReceiver,
+            int callingUid, int callingPid, int callingUserId);
 
     // Cancel authentication for the given sessionId
     void cancelAuthentication(IBinder token, String opPackageName);
 
+    // Same as above, with extra arguments.
+    void cancelAuthenticationFromService(IBinder token, String opPackageName,
+            int callingUid, int callingPid, int callingUserId);
+
     // Start face enrollment
     void enroll(IBinder token, in byte [] cryptoToken, int userId, IFaceServiceReceiver receiver,
                 int flags, String opPackageName);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 15868f1..44b8faf 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -18,10 +18,10 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
+import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
 import static android.Manifest.permission.USE_BIOMETRIC;
 import static android.Manifest.permission.USE_FINGERPRINT;
 
-import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
@@ -34,10 +34,8 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricFingerprintConstants;
 import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.CancellationSignal.OnCancelListener;
 import android.os.Handler;
@@ -66,7 +64,8 @@
 @Deprecated
 @SystemService(Context.FINGERPRINT_SERVICE)
 @RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
-public class FingerprintManager implements BiometricFingerprintConstants {
+public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {
+
     private static final String TAG = "FingerprintManager";
     private static final boolean DEBUG = true;
     private static final int MSG_ENROLL_RESULT = 100;
@@ -80,14 +79,13 @@
     private IFingerprintService mService;
     private Context mContext;
     private IBinder mToken = new Binder();
-    private BiometricAuthenticator.AuthenticationCallback mAuthenticationCallback;
+    private AuthenticationCallback mAuthenticationCallback;
     private EnrollmentCallback mEnrollmentCallback;
     private RemovalCallback mRemovalCallback;
     private EnumerateCallback mEnumerateCallback;
-    private android.hardware.biometrics.CryptoObject mCryptoObject;
+    private CryptoObject mCryptoObject;
     private Fingerprint mRemovalFingerprint;
     private Handler mHandler;
-    private Executor mExecutor;
 
     private class OnEnrollCancelListener implements OnCancelListener {
         @Override
@@ -250,24 +248,12 @@
          */
         @Override
         public void onAuthenticationAcquired(int acquireInfo) {}
-
-        /**
-         * @hide
-         * @param result
-         */
-        @Override
-        public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
-            onAuthenticationSucceeded(new AuthenticationResult(
-                    (CryptoObject) result.getCryptoObject(),
-                    (Fingerprint) result.getId(), result.getUserId()));
-        }
     };
 
     /**
-     * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
-     * CancellationSignal, int). Users of {@link #FingerprintManager()}
-     * must provide an implementation of this to {@link FingerprintManager#enroll(long,
-     * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
+     * Callback structure provided to {@link FingerprintManager#enroll(byte[], CancellationSignal,
+     * int, int, EnrollmentCallback)} must provide an implementation of this for listening to
+     * fingerprint events.
      *
      * @hide
      */
@@ -328,9 +314,9 @@
     };
 
     /**
-     * Callback structure provided to {@link FingerprintManager#enumerate(int). Users of
-     * {@link #FingerprintManager()} may optionally provide an implementation of this to
-     * {@link FingerprintManager#enumerate(int, int, EnumerateCallback)} for listening to
+     * Callback structure provided to {@link FingerprintManager#enumerate(int, EnumerateCallback)}.
+     * Users of{@link #FingerprintManager} may optionally provide an implementation of this to
+     * {@link FingerprintManager#enumerate(int, EnumerateCallback)} for listening to
      * fingerprint template removal events.
      *
      * @hide
@@ -433,7 +419,7 @@
             mCryptoObject = crypto;
             long sessionId = crypto != null ? crypto.getOpId() : 0;
             mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
-                    mContext.getOpPackageName(), null /* bundle */, null /* receiver */);
+                    mContext.getOpPackageName());
         } catch (RemoteException e) {
             Slog.w(TAG, "Remote exception while authenticating: ", e);
             if (callback != null) {
@@ -446,110 +432,6 @@
     }
 
     /**
-     * Per-user version. This method invokes the BiometricPrompt.
-     */
-    private void authenticate(int userId,
-            @Nullable android.hardware.biometrics.CryptoObject crypto,
-            @NonNull CancellationSignal cancel,
-            @NonNull Bundle bundle,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricPromptReceiver receiver,
-            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        mCryptoObject = crypto;
-        if (cancel.isCanceled()) {
-            Slog.w(TAG, "authentication already canceled");
-            return;
-        } else {
-            cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
-        }
-
-        if (mService != null) {
-            try {
-                mExecutor = executor;
-                mAuthenticationCallback = callback;
-                final long sessionId = crypto != null ? crypto.getOpId() : 0;
-                mService.authenticate(mToken, sessionId, userId, mServiceReceiver,
-                        0 /* flags */, mContext.getOpPackageName(), bundle, receiver);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Remote exception while authenticating", e);
-                mExecutor.execute(() -> {
-                    callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                            getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
-                });
-            }
-        }
-    }
-
-    /**
-     * Private method, see {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
-     * BiometricPrompt.AuthenticationCallback)}
-     * @param cancel
-     * @param executor
-     * @param callback
-     * @hide
-     */
-    public void authenticate(
-            @NonNull CancellationSignal cancel,
-            @NonNull Bundle bundle,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricPromptReceiver receiver,
-            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        if (cancel == null) {
-            throw new IllegalArgumentException("Must supply a cancellation signal");
-        }
-        if (bundle == null) {
-            throw new IllegalArgumentException("Must supply a bundle");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException("Must supply an executor");
-        }
-        if (receiver == null) {
-            throw new IllegalArgumentException("Must supply a receiver");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("Must supply a calback");
-        }
-        authenticate(mContext.getUserId(), null, cancel, bundle, executor, receiver, callback);
-    }
-
-    /**
-     * Private method, see {@link BiometricPrompt#authenticate(BiometricPrompt.CryptoObject,
-     * CancellationSignal, Executor, BiometricPrompt.AuthenticationCallback)}
-     * @param crypto
-     * @param cancel
-     * @param executor
-     * @param callback
-     * @hide
-     */
-    public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
-            @NonNull CancellationSignal cancel,
-            @NonNull Bundle bundle,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricPromptReceiver receiver,
-            @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        if (crypto == null) {
-            throw new IllegalArgumentException("Must supply a crypto object");
-        }
-        if (cancel == null) {
-            throw new IllegalArgumentException("Must supply a cancellation signal");
-        }
-        if (bundle == null) {
-            throw new IllegalArgumentException("Must supply a bundle");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException("Must supply an executor");
-        }
-        if (receiver == null) {
-            throw new IllegalArgumentException("Must supply a receiver");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("Must supply a callback");
-        }
-        authenticate(mContext.getUserId(), crypto, cancel,
-                bundle, executor, receiver, callback);
-    }
-
-    /**
      * Request fingerprint enrollment. This call warms up the fingerprint hardware
      * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
      * {@link EnrollmentCallback} object. It terminates when
@@ -743,6 +625,14 @@
     }
 
     /**
+     * @hide
+     */
+    @Override
+    public boolean hasEnrolledTemplates() {
+        return hasEnrolledFingerprints();
+    }
+
+    /**
      * Determine if there is at least one fingerprint enrolled.
      *
      * @return true if at least one fingerprint is enrolled, false otherwise
@@ -785,6 +675,7 @@
      */
     @Deprecated
     @RequiresPermission(USE_FINGERPRINT)
+    @Override
     public boolean isHardwareDetected() {
         if (mService != null) {
             try {
@@ -826,6 +717,7 @@
      *
      * @hide
      */
+    @RequiresPermission(RESET_FINGERPRINT_LOCKOUT)
     public void resetTimeout(byte[] token) {
         if (mService != null) {
             try {
@@ -954,8 +846,8 @@
 
     private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
         if (mAuthenticationCallback != null) {
-            final BiometricAuthenticator.AuthenticationResult result =
-                    new BiometricAuthenticator.AuthenticationResult(mCryptoObject, fp, userId);
+            final AuthenticationResult result =
+                    new AuthenticationResult(mCryptoObject, fp, userId);
             mAuthenticationCallback.onAuthenticationSucceeded(result);
         }
     }
@@ -1042,6 +934,7 @@
     /**
      * @hide
      */
+    @Override
     public String getErrorString(int errMsg, int vendorCode) {
         switch (errMsg) {
             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
@@ -1127,47 +1020,23 @@
 
         @Override // binder call
         public void onAcquired(long deviceId, int acquireInfo, int vendorCode) {
-            if (mExecutor != null) {
-                mExecutor.execute(() -> {
-                    sendAcquiredResult(deviceId, acquireInfo, vendorCode);
-                });
-            } else {
-                mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode,
-                        deviceId).sendToTarget();
-            }
+            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode,
+                    deviceId).sendToTarget();
         }
 
         @Override // binder call
         public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
-            if (mExecutor != null) {
-                mExecutor.execute(() -> {
-                    sendAuthenticatedSucceeded(fp, userId);
-                });
-            } else {
-                mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
-            }
+            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
         }
 
         @Override // binder call
         public void onAuthenticationFailed(long deviceId) {
-            if (mExecutor != null) {
-                mExecutor.execute(() -> {
-                    sendAuthenticatedFailed();
-                });
-            } else {
-                mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
-            }
+            mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
         }
 
         @Override // binder call
         public void onError(long deviceId, int error, int vendorCode) {
-            if (mExecutor != null) {
-                mExecutor.execute(() -> {
-                    sendErrorResult(deviceId, error, vendorCode);
-                });
-            } else {
-                mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
-            }
+            mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
         }
 
         @Override // binder call
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 71a6420..2b2c0b7 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,6 +17,7 @@
 
 import android.os.Bundle;
 import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricPromptServiceReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.fingerprint.IFingerprintClientActiveCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -28,14 +29,29 @@
  * @hide
  */
 interface IFingerprintService {
-    // Authenticate the given sessionId with a fingerprint
+    // Authenticate the given sessionId with a fingerprint. This is protected by
+    // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes
+    // through FingerprintManager now.
     void authenticate(IBinder token, long sessionId, int userId,
-            IFingerprintServiceReceiver receiver, int flags, String opPackageName,
-            in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
+            IFingerprintServiceReceiver receiver, int flags, String opPackageName);
+
+    // This method invokes the BiometricDialog. The arguments are almost the same as above, except
+    // this is protected by the MANAGE_BIOMETRIC signature permission. This method should only be
+    // called from BiometricPromptService. The additional uid, pid, userId arguments should be
+    // determined by BiometricPromptService.
+    void authenticateFromService(IBinder token, long sessionId, int userId,
+            IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+            in Bundle bundle, IBiometricPromptReceiver dialogReceiver,
+            int callingUid, int callingPid, int callingUserId);
 
     // Cancel authentication for the given sessionId
     void cancelAuthentication(IBinder token, String opPackageName);
 
+    // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
+    // an additional uid, pid, userid.
+    void cancelAuthenticationFromService(IBinder token, String opPackageName,
+            int callingUid, int callingPid, int callingUserId);
+
     // Start fingerprint enrollment
     void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver,
             int flags, String opPackageName);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 67bdbf6..5258518 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3748,9 +3748,13 @@
     <permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
         android:protectionLevel="signature" />
 
-    <!-- Allows managing (adding, removing) facial templates. Reserved for the system. @hide -->
-    <permission android:name="android.permission.MANAGE_FACE"
-        android:protectionLevel="signature|privileged" />
+    <!-- Allows direct access to the <Biometric>Service interfaces. Reserved for the system. @hide -->
+    <permission android:name="android.permission.MANAGE_BIOMETRIC"
+        android:protectionLevel="signature" />
+
+    <!-- Allows direct access to the <Biometric>Service authentication methods. Reserved for the system. @hide -->
+    <permission android:name="android.permission.USE_BIOMETRIC_INTERNAL"
+        android:protectionLevel="signature" />
 
     <!-- Allows an app to reset face authentication attempt counter. Reserved for the system. @hide -->
     <permission android:name="android.permission.RESET_FACE_LOCKOUT"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dfd5e81..e3b90526 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1397,6 +1397,9 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_mediaLocation">Allows the app to read locations from your media collection.</string>
 
+    <!-- Message shown when biometric hardware is not available [CHAR LIMIT=50] -->
+    <string name="biometric_error_hw_unavailable">Biometric hardware unavailable</string>
+
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
     <string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ede142f6..b82f9e5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2392,6 +2392,9 @@
   <!-- From KeyguardServiceDelegate -->
   <java-symbol type="string" name="config_keyguardComponent" />
 
+  <!-- Biometric messages -->
+  <java-symbol type="string" name="biometric_error_hw_unavailable" />
+
   <!-- Fingerprint messages -->
   <java-symbol type="string" name="fingerprint_error_unable_to_process" />
   <java-symbol type="string" name="fingerprint_error_hw_not_available" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a5616d5..e31dd1e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -120,7 +120,7 @@
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
     <uses-permission android:name="android.permission.TRUST_LISTENER" />
-    <uses-permission android:name="android.permission.USE_BIOMETRIC" />
+    <uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
     <uses-permission android:name="android.permission.USE_FINGERPRINT" />
     <uses-permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" />
     <uses-permission android:name="android.permission.MANAGE_SLICE_PERMISSIONS" />
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3e534d1..ff6a1c9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1597,7 +1597,7 @@
     public boolean isUnlockWithFacePossible(int userId) {
         return mFaceAuthenticationManager != null && mFaceAuthenticationManager.isHardwareDetected()
                 && !isFaceDisabled(userId)
-                && mFaceAuthenticationManager.hasEnrolledFaces(userId);
+                && mFaceAuthenticationManager.hasEnrolledTemplates(userId);
     }
 
     private void stopListeningForFingerprint() {
diff --git a/services/core/java/com/android/server/biometrics/common/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
similarity index 99%
rename from services/core/java/com/android/server/biometrics/common/AuthenticationClient.java
rename to services/core/java/com/android/server/biometrics/AuthenticationClient.java
index a9cf963..06462a2 100644
--- a/services/core/java/com/android/server/biometrics/common/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
diff --git a/services/core/java/com/android/server/biometrics/BiometricPromptService.java b/services/core/java/com/android/server/biometrics/BiometricPromptService.java
new file mode 100644
index 0000000..29eda8b
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/BiometricPromptService.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_FINGERPRINT;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricPromptService;
+import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.face.FaceManager;
+import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.os.SomeArgs;
+import com.android.server.SystemService;
+
+import java.util.ArrayList;
+
+/**
+ * System service that arbitrates the modality for BiometricPrompt to use.
+ */
+public class BiometricPromptService extends SystemService {
+
+    private static final String TAG = "BiometricPromptService";
+
+    /**
+     * No biometric methods or nothing has been enrolled.
+     * Move/expose these in BiometricPrompt if we ever want to allow applications to "blacklist"
+     * modalities when calling authenticate().
+     */
+    private static final int BIOMETRIC_NONE = 0;
+
+    /**
+     * Constant representing fingerprint.
+     */
+    private static final int BIOMETRIC_FINGERPRINT = 1 << 0;
+
+    /**
+     * Constant representing iris.
+     */
+    private static final int BIOMETRIC_IRIS = 1 << 1;
+
+    /**
+     * Constant representing face.
+     */
+    private static final int BIOMETRIC_FACE = 1 << 2;
+
+    private static final int[] FEATURE_ID = {
+            BIOMETRIC_FINGERPRINT,
+            BIOMETRIC_IRIS,
+            BIOMETRIC_FACE
+    };
+
+    private final Handler mHandler;
+    private final boolean mHasFeatureFingerprint;
+    private final boolean mHasFeatureIris;
+    private final boolean mHasFeatureFace;
+
+    private IFingerprintService mFingerprintService;
+    private IFaceService mFaceService;
+
+    // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
+    // polymorphism :/
+    final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();
+
+    // Cache the current service that's being used. This is the service which
+    // cancelAuthentication() must be forwarded to. This is just a cache, and the actual
+    // check (is caller the current client) is done in the <Biometric>Service.
+    // Since Settings/System (not application) is responsible for changing preference, this
+    // should be safe.
+    private int mCurrentModality;
+
+    private final class Authenticator {
+        int mType;
+        BiometricAuthenticator mAuthenticator;
+
+        Authenticator(int type, BiometricAuthenticator authenticator) {
+            mType = type;
+            mAuthenticator = authenticator;
+        }
+
+        int getType() {
+            return mType;
+        }
+
+        BiometricAuthenticator getAuthenticator() {
+            return mAuthenticator;
+        }
+    }
+
+    /**
+     * This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service
+     * should not carry any state. The reality is we need to keep a tiny amount of state so that
+     * cancelAuthentication() can go to the right place.
+     */
+    private final class BiometricPromptServiceWrapper extends IBiometricPromptService.Stub {
+
+        @Override // Binder call
+        public void authenticate(IBinder token, long sessionId, int userId,
+                IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+                Bundle bundle, IBiometricPromptReceiver dialogReceiver) throws RemoteException {
+            // Check the USE_BIOMETRIC permission here. In the BiometricService, check do the
+            // AppOps and foreground check.
+            checkPermission();
+
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int callingUserId = UserHandle.getCallingUserId();
+
+            mHandler.post(() -> {
+                mCurrentModality = checkAndGetBiometricModality(receiver);
+
+                try {
+                    // No polymorphism :(
+                    if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
+                        mFingerprintService.authenticateFromService(token, sessionId, userId,
+                                receiver, flags, opPackageName, bundle, dialogReceiver,
+                                callingUid, callingPid, callingUserId);
+                    } else if (mCurrentModality == BIOMETRIC_IRIS) {
+                        Slog.w(TAG, "Unsupported modality");
+                    } else if (mCurrentModality == BIOMETRIC_FACE) {
+                        mFaceService.authenticateFromService(token, sessionId, userId,
+                                receiver, flags, opPackageName, bundle, dialogReceiver,
+                                callingUid, callingPid, callingUserId);
+                    } else {
+                        Slog.w(TAG, "Unsupported modality");
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to start authentication", e);
+                }
+            });
+        }
+
+        @Override // Binder call
+        public void cancelAuthentication(IBinder token, String opPackageName)
+                throws RemoteException {
+            checkPermission();
+
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int callingUserId = UserHandle.getCallingUserId();
+
+            mHandler.post(() -> {
+                try {
+                    if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
+                        mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
+                                callingUid, callingPid, callingUserId);
+                    } else if (mCurrentModality == BIOMETRIC_IRIS) {
+                        Slog.w(TAG, "Unsupported modality");
+                    } else if (mCurrentModality == BIOMETRIC_FACE) {
+                        mFaceService.cancelAuthenticationFromService(token, opPackageName,
+                                callingUid, callingPid, callingUserId);
+                    } else {
+                        Slog.w(TAG, "Unsupported modality");
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to cancel authentication");
+                }
+            });
+        }
+    }
+
+    private void checkPermission() {
+        if (getContext().checkCallingPermission(USE_FINGERPRINT)
+                != PackageManager.PERMISSION_GRANTED) {
+            getContext().enforceCallingPermission(USE_BIOMETRIC,
+                    "Must have USE_BIOMETRIC permission");
+        }
+    }
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     */
+    public BiometricPromptService(Context context) {
+        super(context);
+
+        mHandler = new Handler(Looper.getMainLooper());
+
+        final PackageManager pm = context.getPackageManager();
+        mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+        mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
+        mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
+    }
+
+    @Override
+    public void onStart() {
+        // TODO: maybe get these on-demand
+        if (mHasFeatureFingerprint) {
+            mFingerprintService = IFingerprintService.Stub.asInterface(
+                    ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+        }
+        if (mHasFeatureFace) {
+            mFaceService = IFaceService.Stub.asInterface(
+                    ServiceManager.getService(Context.FACE_SERVICE));
+        }
+
+        // Cache the authenticators
+        for (int i = 0; i < FEATURE_ID.length; i++) {
+            if (hasFeature(FEATURE_ID[i])) {
+                Authenticator authenticator =
+                        new Authenticator(FEATURE_ID[i], getAuthenticator(FEATURE_ID[i]));
+                mAuthenticators.add(authenticator);
+            }
+        }
+
+        publishBinderService(Context.BIOMETRIC_PROMPT_SERVICE, new BiometricPromptServiceWrapper());
+    }
+
+    /**
+     * Checks if there are any available biometrics, and returns the modality. This method also
+     * returns errors through the callback (no biometric feature, hardware not detected, no
+     * templates enrolled, etc). This service must not start authentication if errors are sent.
+     */
+    private int checkAndGetBiometricModality(IBiometricPromptServiceReceiver receiver) {
+        int modality = BIOMETRIC_NONE;
+        final String hardwareUnavailable =
+                getContext().getString(R.string.biometric_error_hw_unavailable);
+
+        // No biometric features, send error
+        if (mAuthenticators.isEmpty()) {
+            try {
+                receiver.onError(0 /* deviceId */,
+                        BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT,
+                        hardwareUnavailable);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to send error", e);
+            }
+            return BIOMETRIC_NONE;
+        }
+
+        // Find first authenticator that's both detected and enrolled
+        boolean isHardwareDetected = false;
+        boolean hasTemplatesEnrolled = false;
+        for (int i = 0; i < mAuthenticators.size(); i++) {
+            int featureId = mAuthenticators.get(i).getType();
+            BiometricAuthenticator authenticator = mAuthenticators.get(i).getAuthenticator();
+            if (authenticator.isHardwareDetected()) {
+                isHardwareDetected = true;
+                if (authenticator.hasEnrolledTemplates()) {
+                    hasTemplatesEnrolled = true;
+                    modality = featureId;
+                    break;
+                }
+            }
+        }
+
+        // Check error conditions
+        if (!isHardwareDetected) {
+            try {
+                receiver.onError(0 /* deviceId */,
+                        BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+                        hardwareUnavailable);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to send error", e);
+            }
+            return BIOMETRIC_NONE;
+        }
+        if (!hasTemplatesEnrolled) {
+            try {
+                receiver.onError(0 /* deviceId */,
+                        BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
+                        hardwareUnavailable);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to send error", e);
+            }
+            return BIOMETRIC_NONE;
+        }
+
+        return modality;
+    }
+
+    private BiometricAuthenticator getAuthenticator(int type) {
+        switch (type) {
+            case BIOMETRIC_FINGERPRINT:
+                return (FingerprintManager)
+                        getContext().getSystemService(Context.FINGERPRINT_SERVICE);
+            case BIOMETRIC_IRIS:
+                return null;
+            case BIOMETRIC_FACE:
+                return (FaceManager)
+                        getContext().getSystemService(Context.FACE_SERVICE);
+            default:
+                return null;
+        }
+    }
+
+    private boolean hasFeature(int type) {
+        switch (type) {
+            case BIOMETRIC_FINGERPRINT:
+                return mHasFeatureFingerprint;
+            case BIOMETRIC_IRIS:
+                return mHasFeatureIris;
+            case BIOMETRIC_FACE:
+                return mHasFeatureFace;
+            default:
+                return false;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/common/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
similarity index 97%
rename from services/core/java/com/android/server/biometrics/common/BiometricService.java
rename to services/core/java/com/android/server/biometrics/BiometricService.java
index 5603f2f..cc2e81f 100644
--- a/services/core/java/com/android/server/biometrics/common/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -11,10 +11,10 @@
  * 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.
+ * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
 
@@ -333,8 +333,8 @@
      * Wraps the callback interface from Service -> Manager
      */
     protected interface ServiceListener {
-        void onEnrollResult(BiometricAuthenticator.Identifier identifier,
-                int remaining) throws RemoteException;
+        default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
+                int remaining) throws RemoteException {};
 
         void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
                 throws RemoteException;
@@ -349,11 +349,11 @@
         void onError(long deviceId, int error, int vendorCode)
                 throws RemoteException;
 
-        void onRemoved(BiometricAuthenticator.Identifier identifier,
-                int remaining) throws RemoteException;
+        default void onRemoved(BiometricAuthenticator.Identifier identifier,
+                int remaining) throws RemoteException {};
 
-        void onEnumerated(BiometricAuthenticator.Identifier identifier,
-                int remaining) throws RemoteException;
+        default void onEnumerated(BiometricAuthenticator.Identifier identifier,
+                int remaining) throws RemoteException {};
     }
 
     /**
@@ -688,7 +688,11 @@
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         final int callingUserId = UserHandle.getCallingUserId();
+        authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);
+    }
 
+    protected void authenticateInternal(AuthenticationClientImpl client, long opId,
+            String opPackageName, int callingUid, int callingPid, int callingUserId) {
         if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
                 callingUserId)) {
             if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
@@ -716,7 +720,11 @@
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         final int callingUserId = UserHandle.getCallingUserId();
+        cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, callingUserId);
+    }
 
+    protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
+            int callingUid, int callingPid, int callingUserId) {
         if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
                 callingUserId)) {
             if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
diff --git a/services/core/java/com/android/server/biometrics/common/BiometricUserState.java b/services/core/java/com/android/server/biometrics/BiometricUserState.java
similarity index 98%
rename from services/core/java/com/android/server/biometrics/common/BiometricUserState.java
rename to services/core/java/com/android/server/biometrics/BiometricUserState.java
index 53eaac0..979ce3a2 100644
--- a/services/core/java/com/android/server/biometrics/common/BiometricUserState.java
+++ b/services/core/java/com/android/server/biometrics/BiometricUserState.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
diff --git a/services/core/java/com/android/server/biometrics/common/BiometricUtils.java b/services/core/java/com/android/server/biometrics/BiometricUtils.java
similarity index 96%
rename from services/core/java/com/android/server/biometrics/common/BiometricUtils.java
rename to services/core/java/com/android/server/biometrics/BiometricUtils.java
index 8f076f1..4ff743a 100644
--- a/services/core/java/com/android/server/biometrics/common/BiometricUtils.java
+++ b/services/core/java/com/android/server/biometrics/BiometricUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
diff --git a/services/core/java/com/android/server/biometrics/common/ClientMonitor.java b/services/core/java/com/android/server/biometrics/ClientMonitor.java
similarity index 99%
rename from services/core/java/com/android/server/biometrics/common/ClientMonitor.java
rename to services/core/java/com/android/server/biometrics/ClientMonitor.java
index 1486754..d30bed2 100644
--- a/services/core/java/com/android/server/biometrics/common/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/ClientMonitor.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
diff --git a/services/core/java/com/android/server/biometrics/common/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
similarity index 98%
rename from services/core/java/com/android/server/biometrics/common/EnrollClient.java
rename to services/core/java/com/android/server/biometrics/EnrollClient.java
index aee772b..c305eca6 100644
--- a/services/core/java/com/android/server/biometrics/common/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
diff --git a/services/core/java/com/android/server/biometrics/common/EnumerateClient.java b/services/core/java/com/android/server/biometrics/EnumerateClient.java
similarity index 98%
rename from services/core/java/com/android/server/biometrics/common/EnumerateClient.java
rename to services/core/java/com/android/server/biometrics/EnumerateClient.java
index ee40ee9..b763769 100644
--- a/services/core/java/com/android/server/biometrics/common/EnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/EnumerateClient.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
diff --git a/services/core/java/com/android/server/biometrics/common/Metrics.java b/services/core/java/com/android/server/biometrics/Metrics.java
similarity index 95%
rename from services/core/java/com/android/server/biometrics/common/Metrics.java
rename to services/core/java/com/android/server/biometrics/Metrics.java
index eb1a1f8..02e44e9 100644
--- a/services/core/java/com/android/server/biometrics/common/Metrics.java
+++ b/services/core/java/com/android/server/biometrics/Metrics.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 public interface Metrics {
     /** The log tag */
diff --git a/services/core/java/com/android/server/biometrics/common/RemovalClient.java b/services/core/java/com/android/server/biometrics/RemovalClient.java
similarity index 98%
rename from services/core/java/com/android/server/biometrics/common/RemovalClient.java
rename to services/core/java/com/android/server/biometrics/RemovalClient.java
index 27c42ab..3bf7f04 100644
--- a/services/core/java/com/android/server/biometrics/common/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/RemovalClient.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.biometrics.common;
+package com.android.server.biometrics;
 
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
diff --git a/services/core/java/com/android/server/biometrics/face/FaceMetrics.java b/services/core/java/com/android/server/biometrics/face/FaceMetrics.java
index 4c907b1..1c5cd5a 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceMetrics.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceMetrics.java
@@ -17,7 +17,7 @@
 package com.android.server.biometrics.face;
 
 import com.android.internal.logging.nano.MetricsProto;
-import com.android.server.biometrics.common.Metrics;
+import com.android.server.biometrics.Metrics;
 
 public class FaceMetrics implements Metrics {
     @Override
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 f8ccef5..2e76406 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -17,9 +17,9 @@
 package com.android.server.biometrics.face;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.MANAGE_FACE;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
 import static android.Manifest.permission.RESET_FACE_LOCKOUT;
-import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
@@ -28,10 +28,12 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricPromptServiceReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.biometrics.face.V1_0.IBiometricsFace;
 import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
 import android.hardware.face.Face;
+import android.hardware.face.FaceManager;
 import android.hardware.face.IFaceService;
 import android.hardware.face.IFaceServiceReceiver;
 import android.os.Binder;
@@ -51,9 +53,9 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemServerInitThreadPool;
-import com.android.server.biometrics.common.BiometricService;
-import com.android.server.biometrics.common.BiometricUtils;
-import com.android.server.biometrics.common.Metrics;
+import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.BiometricUtils;
+import com.android.server.biometrics.Metrics;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -92,13 +94,13 @@
          */
         @Override // Binder call
         public long preEnroll(IBinder token) {
-            checkPermission(MANAGE_FACE);
+            checkPermission(MANAGE_BIOMETRIC);
             return startPreEnroll(token);
         }
 
         @Override // Binder call
         public int postEnroll(IBinder token) {
-            checkPermission(MANAGE_FACE);
+            checkPermission(MANAGE_BIOMETRIC);
             return startPostEnroll(token);
         }
 
@@ -106,7 +108,7 @@
         public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
                 final IFaceServiceReceiver receiver, final int flags,
                 final String opPackageName) {
-            checkPermission(MANAGE_FACE);
+            checkPermission(MANAGE_BIOMETRIC);
 
             final boolean restricted = isRestricted();
             final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
@@ -118,39 +120,64 @@
 
         @Override // Binder call
         public void cancelEnrollment(final IBinder token) {
-            checkPermission(MANAGE_FACE);
+            checkPermission(MANAGE_BIOMETRIC);
             cancelEnrollmentInternal(token);
         }
 
         @Override // Binder call
         public void authenticate(final IBinder token, final long opId,
                 final IFaceServiceReceiver receiver, final int flags,
-                final String opPackageName, final Bundle bundle,
-                final IBiometricPromptReceiver dialogReceiver) {
+                final String opPackageName) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
             final boolean restricted = isRestricted();
             final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
                     mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
-                    mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, bundle,
-                    dialogReceiver, mStatusBarService);
+                    mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
+                    null /* bundle */, null /* dialogReceiver */, mStatusBarService);
 
             authenticateInternal(client, opId, opPackageName);
         }
 
         @Override // Binder call
+        public void authenticateFromService(IBinder token, long opId, int groupId,
+                IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+                Bundle bundle, IBiometricPromptReceiver dialogReceiver,
+                int callingUid, int callingPid, int callingUserId) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
+            final boolean restricted = true; // BiometricPrompt is always restricted
+            final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+                    mDaemonWrapper, mHalDeviceId, token,
+                    new BiometricPromptServiceListenerImpl(receiver),
+                    mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
+                    bundle, dialogReceiver, mStatusBarService);
+            authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
+                    callingUserId);
+        }
+
+        @Override // Binder call
         public void cancelAuthentication(final IBinder token, final String opPackageName) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
             cancelAuthenticationInternal(token, opPackageName);
         }
 
         @Override // Binder call
+        public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
+                int callingUid, int callingPid, int callingUserId) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
+            cancelAuthenticationInternal(token, opPackageName,
+                    callingUid, callingPid, callingUserId);
+        }
+
+        @Override // Binder call
         public void setActiveUser(final int userId) {
-            checkPermission(MANAGE_FACE);
+            checkPermission(MANAGE_BIOMETRIC);
             setActiveUserInternal(userId);
         }
 
         @Override // Binder call
         public void remove(final IBinder token, final int faceId, final int userId,
                 final IFaceServiceReceiver receiver) {
-            checkPermission(MANAGE_FACE);
+            checkPermission(MANAGE_BIOMETRIC);
 
             if (token == null) {
                 Slog.w(TAG, "remove(): token is null");
@@ -168,7 +195,7 @@
         @Override
         public void enumerate(final IBinder token, final int userId,
                 final IFaceServiceReceiver receiver) {
-            checkPermission(MANAGE_FACE);
+            checkPermission(MANAGE_BIOMETRIC);
 
             final boolean restricted = isRestricted();
             final EnumerateClientImpl client = new EnumerateClientImpl(getContext(), mDaemonWrapper,
@@ -180,6 +207,7 @@
         @Override
         public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
                 throws RemoteException {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
             FaceService.super.addLockoutResetCallback(callback);
         }
 
@@ -208,6 +236,7 @@
         // TODO: refactor out common code here
         @Override // Binder call
         public boolean isHardwareDetected(long deviceId, String opPackageName) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
             if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
                     Binder.getCallingUid(), Binder.getCallingPid(),
                     UserHandle.getCallingUserId())) {
@@ -225,7 +254,7 @@
 
         @Override // Binder call
         public void rename(final int faceId, final String name) {
-            checkPermission(MANAGE_FACE);
+            checkPermission(MANAGE_BIOMETRIC);
             if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
                 return;
             }
@@ -240,6 +269,7 @@
 
         @Override // Binder call
         public List<Face> getEnrolledFaces(int userId, String opPackageName) {
+            checkPermission(MANAGE_BIOMETRIC);
             if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
                     Binder.getCallingUid(), Binder.getCallingPid(),
                     UserHandle.getCallingUserId())) {
@@ -251,6 +281,7 @@
 
         @Override // Binder call
         public boolean hasEnrolledFaces(int userId, String opPackageName) {
+            checkPermission(USE_BIOMETRIC_INTERNAL);
             if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
                     Binder.getCallingUid(), Binder.getCallingPid(),
                     UserHandle.getCallingUserId())) {
@@ -283,7 +314,7 @@
 
         @Override // Binder call
         public void resetTimeout(byte[] token) {
-            checkPermission(RESET_FACE_LOCKOUT);
+            checkPermission(MANAGE_BIOMETRIC);
             // TODO: confirm security token when we move timeout management into the HAL layer.
             mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
         }
@@ -291,6 +322,58 @@
 
     /**
      * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
+     * BiometricPrompt.
+     */
+    private class BiometricPromptServiceListenerImpl implements ServiceListener {
+
+        // Use FaceManager to get strings, so BiometricPrompt interface is cleaner
+        private FaceManager mFaceManager;
+        private IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver;
+
+        public BiometricPromptServiceListenerImpl(IBiometricPromptServiceReceiver receiver) {
+            mBiometricPromptServiceReceiver = receiver;
+            mFaceManager = (FaceManager) getContext().getSystemService(Context.FACE_SERVICE);
+        }
+
+        @Override
+        public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
+                throws RemoteException {
+            /**
+             * Map the acquired codes onto existing {@link BiometricConstants} acquired codes.
+             */
+            if (mBiometricPromptServiceReceiver != null) {
+                mBiometricPromptServiceReceiver.onAcquired(deviceId,
+                        mFaceManager.getMappedAcquiredInfo(acquiredInfo, vendorCode),
+                        mFaceManager.getAcquiredString(acquiredInfo, vendorCode));
+            }
+        }
+
+        @Override
+        public void onAuthenticationSucceeded(long deviceId,
+                BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
+            if (mBiometricPromptServiceReceiver != null) {
+                mBiometricPromptServiceReceiver.onAuthenticationSucceeded(deviceId);
+            }
+        }
+
+        @Override
+        public void onAuthenticationFailed(long deviceId) throws RemoteException {
+            if (mBiometricPromptServiceReceiver != null) {
+                mBiometricPromptServiceReceiver.onAuthenticationFailed(deviceId);
+            }
+        }
+
+        @Override
+        public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
+            if (mBiometricPromptServiceReceiver != null) {
+                mBiometricPromptServiceReceiver.onError(deviceId, error,
+                        mFaceManager.getErrorString(error, vendorCode));
+            }
+        }
+    }
+
+    /**
+     * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
      * the FaceManager.
      */
     private class ServiceListenerImpl implements ServiceListener {
@@ -616,12 +699,13 @@
 
     @Override
     protected String getManageBiometricPermission() {
-        return MANAGE_FACE;
+        return MANAGE_BIOMETRIC;
     }
 
     @Override
     protected void checkUseBiometricPermission() {
-        checkPermission(USE_BIOMETRIC);
+        // noop for Face. The permission checks are all done on the incoming binder call.
+        // TODO: Perhaps do the same in FingerprintService
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/face/FaceUserState.java
index c438bfb..65c942d 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceUserState.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceUserState.java
@@ -24,7 +24,7 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.biometrics.common.BiometricUserState;
+import com.android.server.biometrics.BiometricUserState;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/biometrics/face/FaceUtils.java b/services/core/java/com/android/server/biometrics/face/FaceUtils.java
index a7e85e0..63ff548 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceUtils.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceUtils.java
@@ -23,7 +23,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.biometrics.common.BiometricUtils;
+import com.android.server.biometrics.BiometricUtils;
 
 import java.util.List;
 
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintMetrics.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintMetrics.java
index ba8b3b3..a1115c8 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintMetrics.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintMetrics.java
@@ -17,7 +17,7 @@
 package com.android.server.biometrics.fingerprint;
 
 import com.android.internal.logging.nano.MetricsProto;
-import com.android.server.biometrics.common.Metrics;
+import com.android.server.biometrics.Metrics;
 
 public class FingerprintMetrics implements Metrics {
 
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 64b248e..a25b4b4 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -17,6 +17,7 @@
 package com.android.server.biometrics.fingerprint;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
 import static android.Manifest.permission.USE_BIOMETRIC;
@@ -30,10 +31,12 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricPromptServiceReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
 import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintClientActiveCallback;
 import android.hardware.fingerprint.IFingerprintService;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -42,7 +45,6 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.IBinder;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SELinux;
 import android.os.ServiceManager;
@@ -56,11 +58,11 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemServerInitThreadPool;
-import com.android.server.biometrics.common.BiometricService;
-import com.android.server.biometrics.common.BiometricUtils;
-import com.android.server.biometrics.common.ClientMonitor;
-import com.android.server.biometrics.common.EnumerateClient;
-import com.android.server.biometrics.common.Metrics;
+import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.BiometricUtils;
+import com.android.server.biometrics.ClientMonitor;
+import com.android.server.biometrics.EnumerateClient;
+import com.android.server.biometrics.Metrics;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -147,23 +149,46 @@
         @Override // Binder call
         public void authenticate(final IBinder token, final long opId, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags,
-                final String opPackageName, final Bundle bundle,
-                final IBiometricPromptReceiver dialogReceiver) {
+                final String opPackageName) {
             final boolean restricted = isRestricted();
             final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
                     mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
-                    mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
-                    dialogReceiver, mStatusBarService);
+                    mCurrentUserId, groupId, opId, restricted, opPackageName, null /* bundle */,
+                    null /* dialogReceiver */, mStatusBarService);
 
             authenticateInternal(client, opId, opPackageName);
         }
 
         @Override // Binder call
+        public void authenticateFromService(IBinder token, long opId, int groupId,
+                IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+                Bundle bundle, IBiometricPromptReceiver dialogReceiver,
+                int callingUid, int callingPid, int callingUserId) {
+            checkPermission(MANAGE_BIOMETRIC);
+            final boolean restricted = true; // BiometricPrompt is always restricted
+            final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+                    mDaemonWrapper, mHalDeviceId, token,
+                    new BiometricPromptServiceListenerImpl(receiver),
+                    mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
+                    dialogReceiver, mStatusBarService);
+            authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
+                    callingUserId);
+        }
+
+        @Override // Binder call
         public void cancelAuthentication(final IBinder token, final String opPackageName) {
             cancelAuthenticationInternal(token, opPackageName);
         }
 
         @Override // Binder call
+        public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
+                int callingUid, int callingPid, int callingUserId) {
+            checkPermission(MANAGE_BIOMETRIC);
+            cancelAuthenticationInternal(token, opPackageName,
+                    callingUid, callingPid, callingUserId);
+        }
+
+        @Override // Binder call
         public void setActiveUser(final int userId) {
             checkPermission(MANAGE_FINGERPRINT);
             setActiveUserInternal(userId);
@@ -333,6 +358,55 @@
 
     /**
      * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
+     * BiometricPrompt.
+     */
+    private class BiometricPromptServiceListenerImpl implements ServiceListener {
+
+        // Use FingerprintManager to get strings, so BiometricPrompt interface is cleaner
+        private FingerprintManager mFingerprintManager;
+        private IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver;
+
+        public BiometricPromptServiceListenerImpl(IBiometricPromptServiceReceiver receiver) {
+            mBiometricPromptServiceReceiver = receiver;
+            mFingerprintManager = (FingerprintManager)
+                    getContext().getSystemService(Context.FINGERPRINT_SERVICE);
+        }
+
+        @Override
+        public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
+                throws RemoteException {
+            if (mBiometricPromptServiceReceiver != null) {
+                mBiometricPromptServiceReceiver.onAcquired(deviceId, acquiredInfo,
+                        mFingerprintManager.getAcquiredString(acquiredInfo, vendorCode));
+            }
+        }
+
+        @Override
+        public void onAuthenticationSucceeded(long deviceId,
+                BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
+            if (mBiometricPromptServiceReceiver != null) {
+                mBiometricPromptServiceReceiver.onAuthenticationSucceeded(deviceId);
+            }
+        }
+
+        @Override
+        public void onAuthenticationFailed(long deviceId) throws RemoteException {
+            if (mBiometricPromptServiceReceiver != null) {
+                mBiometricPromptServiceReceiver.onAuthenticationFailed(deviceId);
+            }
+        }
+
+        @Override
+        public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
+            if (mBiometricPromptServiceReceiver != null) {
+                mBiometricPromptServiceReceiver.onError(deviceId, error,
+                        mFingerprintManager.getErrorString(error, vendorCode));
+            }
+        }
+    }
+
+    /**
+     * Receives callbacks from the ClientMonitor implementations. The results are forwarded to
      * the FingerprintManager.
      */
     private class ServiceListenerImpl implements ServiceListener {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUserState.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUserState.java
index 9e34ee8..25da978 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUserState.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUserState.java
@@ -24,7 +24,7 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.biometrics.common.BiometricUserState;
+import com.android.server.biometrics.BiometricUserState;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUtils.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUtils.java
index 41216e9..a05606b 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUtils.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintUtils.java
@@ -23,7 +23,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.biometrics.common.BiometricUtils;
+import com.android.server.biometrics.BiometricUtils;
 
 import java.util.List;
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a61f94c..ecc13b2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -67,6 +67,7 @@
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.ActivityTaskManagerService;
 import com.android.server.audio.AudioService;
+import com.android.server.biometrics.BiometricPromptService;
 import com.android.server.broadcastradio.BroadcastRadioService;
 import com.android.server.camera.CameraServiceProxy;
 import com.android.server.clipboard.ClipboardService;
@@ -1551,18 +1552,30 @@
             }
             traceEnd();
 
-            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+            final boolean hasFeatureFace
+                    = mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE);
+            final boolean hasFeatureFingerprint
+                    = mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+
+            if (hasFeatureFace) {
                 traceBeginAndSlog("StartFaceSensor");
                 mSystemServiceManager.startService(FaceService.class);
                 traceEnd();
             }
 
-            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+            if (hasFeatureFingerprint) {
                 traceBeginAndSlog("StartFingerprintSensor");
                 mSystemServiceManager.startService(FingerprintService.class);
                 traceEnd();
             }
 
+            if (hasFeatureFace || hasFeatureFingerprint) {
+                // Start this service after all biometric services.
+                traceBeginAndSlog("StartBiometricPromptService");
+                mSystemServiceManager.startService(BiometricPromptService.class);
+                traceEnd();
+            }
+
             traceBeginAndSlog("StartBackgroundDexOptService");
             try {
                 BackgroundDexOptService.schedule(context);