3/n: For passive modalities, add plumbing for "try again"

When "try again" is showing, authentication is canceled internally.
BiometricService caches the client's info so that authentication can
be restarted when "try again" is pressed. Because authentication
is not running when "try again" is showing, BiometricService also needs
to have a TaskStackListener so that BP can be dismissed and an error can
be sent to the client when the app loses focus.

IBiometricServiceReceiver has been split into two. One for BiometricPrompt
to receive messages from BiometricService, and another for BiometricService
to receive messages from SystemUI/<Biometric>Services.

When we get locked out, don't send the last onAuthenticationFailed
to the client, since "Authentication failed" will be shown briefly
and be replaced by "Device locked out" which is janky

Bug: 111461540

Test: Tested with requireConfirmation enabled/disabled
Test: Tested onConfigurationChange corner cases, e.g. when "try again"
      or "confirm" buttons are showing, rotate the device. Buttons
      persist correctly and don't appear when unexpected
Test: Tested task stack corner cases, e.g. when "try again" is showing,
      press home button. BP dismisses and client receives ERROR_CANCELED
Test: BiometricPromptDemo receives all callbacks

Change-Id: I62126708ce8db8b358c666a07aa7c39607642c9d
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 3c7ba14..b238d77 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -263,12 +263,6 @@
         }
 
         @Override
-        public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] bytes)
-                throws RemoteException {
-            throw new UnsupportedOperationException("Operation not supported!");
-        }
-
-        @Override
         public void onAuthenticationFailed() throws RemoteException {
             mExecutor.execute(() -> {
                 mAuthenticationCallback.onAuthenticationFailed();
@@ -283,11 +277,6 @@
         }
 
         @Override
-        public void onErrorInternal(int error, String message, int cookie) throws RemoteException {
-            throw new UnsupportedOperationException("Operation not supported!");
-        }
-
-        @Override
         public void onAcquired(int acquireInfo, String message) throws RemoteException {
             mExecutor.execute(() -> {
                 mAuthenticationCallback.onAuthenticationHelp(acquireInfo, message);
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
index 62222a3..22ef33e 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
@@ -16,28 +16,16 @@
 package android.hardware.biometrics;
 
 /**
- * Communication channel from
- *   1) BiometricDialogImpl (SysUI) back to BiometricService
- *   2) <Biometric>Service back to BiometricService
- *   3) BiometricService back to BiometricPrompt
- * BiometricPrompt sends a receiver to BiometricService, BiometricService contains another
- * "trampoline" receiver which intercepts messages from <Biometric>Service and does some
- * logic before forwarding results as necessary to BiometricPrompt.
+ * Communication channel from BiometricService back to BiometricPrompt
  * @hide
  */
 oneway interface IBiometricServiceReceiver {
     // Notify BiometricPrompt that authentication was successful
     void onAuthenticationSucceeded();
-    // Notify BiometricService that authentication was successful. If user confirmation is required,
-    // the auth token must be submitted into KeyStore.
-    void onAuthenticationSucceededInternal(boolean requireConfirmation, in byte[] token);
     // Noties that authentication failed.
     void onAuthenticationFailed();
     // Notify BiometricPrompt that an error has occurred.
     void onError(int error, String message);
-    // Notify BiometricService than an error has occured. Forward to the correct receiver depending
-    // on the cookie.
-    void onErrorInternal(int error, String message, int cookie);
     // Notifies that a biometric has been acquired.
     void onAcquired(int acquiredInfo, String message);
     // Notifies that the SystemUI dialog has been dismissed.
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
new file mode 100644
index 0000000..180daaf
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+/**
+ * Communication channel from
+ *   1) BiometricDialogImpl (SysUI) back to BiometricService
+ *   2) <Biometric>Service back to BiometricService
+ * Receives messages from the above and does some handling before forwarding to BiometricPrompt
+ * via IBiometricServiceReceiver.
+ * @hide
+ */
+oneway interface IBiometricServiceReceiverInternal {
+    // Notify BiometricService that authentication was successful. If user confirmation is required,
+    // the auth token must be submitted into KeyStore.
+    void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token);
+    // Notify BiometricService that an error has occurred.
+    void onAuthenticationFailed(int cookie, boolean requireConfirmation);
+    // Notify BiometricService than an error has occured. Forward to the correct receiver depending
+    // on the cookie.
+    void onError(int cookie, int error, String message);
+    // Notifies that a biometric has been acquired.
+    void onAcquired(int acquiredInfo, String message);
+    // Notifies that the SystemUI dialog has been dismissed.
+    void onDialogDismissed(int reason);
+    // Notifies that the user has pressed the "try again" button on SystemUI
+    void onTryAgainPressed();
+}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index f17bfc4..a15dcec 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -15,7 +15,7 @@
  */
 package android.hardware.face;
 
-import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.face.IFaceServiceReceiver;
 import android.hardware.face.Face;
@@ -36,7 +36,7 @@
     // by BiometricService. To start authentication after the clients are ready, use
     // startPreparedClient().
     void prepareForAuthentication(boolean requireConfirmation, IBinder token, long sessionId,
-            int userId, IBiometricServiceReceiver wrapperReceiver, String opPackageName,
+            int userId, IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName,
             int cookie, int callingUid, int callingPid, int callingUserId);
 
     // Starts authentication with the previously prepared client.
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index b859720..dd6b29d 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -15,7 +15,7 @@
  */
 package android.hardware.fingerprint;
 
-import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.fingerprint.IFingerprintClientActiveCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -39,7 +39,7 @@
     // by BiometricService. To start authentication after the clients are ready, use
     // startPreparedClient().
     void prepareForAuthentication(IBinder token, long sessionId, int userId,
-            IBiometricServiceReceiver wrapperReceiver, String opPackageName, int cookie,
+            IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName, int cookie,
             int callingUid, int callingPid, int callingUserId);
 
     // Starts authentication with the previously prepared client.
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index bb00900..600b1b3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -18,7 +18,7 @@
 
 import android.content.ComponentName;
 import android.graphics.Rect;
-import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
 
@@ -141,7 +141,7 @@
     void showShutdownUi(boolean isReboot, String reason);
 
     // Used to show the dialog when BiometricService starts authentication
-    void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiver receiver, int type,
+    void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
             boolean requireConfirmation, int userId);
     // Used to hide the dialog when a biometric is authenticated
     void onBiometricAuthenticated();
@@ -151,4 +151,6 @@
     void onBiometricError(String error);
     // Used to hide the biometric dialog when the AuthenticationClient is stopped
     void hideBiometricDialog();
+    // Used to request the "try again" button for authentications which requireConfirmation=true
+    void showBiometricTryAgain();
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 40a7812..22cec17 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -20,7 +20,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
-import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
@@ -91,7 +91,7 @@
     void showPinningEscapeToast();
 
     // Used to show the dialog when BiometricService starts authentication
-    void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiver receiver, int type,
+    void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
             boolean requireConfirmation, int userId);
     // Used to hide the dialog when a biometric is authenticated
     void onBiometricAuthenticated();
@@ -101,4 +101,6 @@
     void onBiometricError(String error);
     // Used to hide the biometric dialog when the AuthenticationClient is stopped
     void hideBiometricDialog();
+    // Used to request the "try again" button for authentications which requireConfirmation=true
+    void showBiometricTryAgain();
 }