Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1bafe67c authored by Kevin Chyn's avatar Kevin Chyn Committed by Android (Google) Code Review
Browse files

Merge changes from topic "face-small"

* changes:
  2/n: Add BiometricPrompt implicit UI
  1/n: Add BiometricPrompt#setRequireConfirmation(bool) API
parents 48273286 e1912712
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -73,6 +73,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
     * @hide
     */
    public static final String KEY_NEGATIVE_TEXT = "negative_text";
    /**
     * @hide
     */
    public static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation";

    /**
     * Error/help message will show for this amount of time.
@@ -214,6 +218,30 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            return this;
        }

        /**
         * Optional: A hint to the system to require user confirmation after a biometric has been
         * authenticated. For example, implicit modalities like Face and Iris authentication are
         * passive, meaning they don't require an explicit user action to complete. When set to
         * 'false', the user action (e.g. pressing a button) will not be required. BiometricPrompt
         * will require confirmation by default.
         *
         * A typical use case for not requiring confirmation would be for low-risk transactions,
         * such as re-authenticating a recently authenticated application. A typical use case for
         * requiring confirmation would be for authorizing a purchase.
         *
         * Note that this is a hint to the system. The system may choose to ignore the flag. For
         * example, if the user disables implicit authentication in Settings, or if it does not
         * apply to a modality (e.g. Fingerprint). When ignored, the system will default to
         * requiring confirmation.
         *
         * @param requireConfirmation
         * @hide
         */
        public Builder setRequireConfirmation(boolean requireConfirmation) {
            mBundle.putBoolean(KEY_REQUIRE_CONFIRMATION, requireConfirmation);
            return this;
        }

        /**
         * Creates a {@link BiometricPrompt}.
         * @return a {@link BiometricPrompt}
+1 −3
Original line number Diff line number Diff line
@@ -153,13 +153,11 @@ oneway interface IStatusBar
    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();
    void onBiometricAuthenticated(boolean authenticated);
    // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
    void onBiometricHelp(String message);
    // Used to set a message - the dialog will dismiss after a certain amount of time
    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();
}
+1 −3
Original line number Diff line number Diff line
@@ -97,13 +97,11 @@ interface IStatusBarService
    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();
    void onBiometricAuthenticated(boolean authenticated);
    // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
    void onBiometricHelp(String message);
    // Used to set a message - the dialog will dismiss after a certain amount of time
    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();
}
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="?android:attr/colorBackgroundFloating" />
    <corners android:radius="1dp"
    <corners
        android:topLeftRadius="@dimen/biometric_dialog_corner_size"
        android:topRightRadius="@dimen/biometric_dialog_corner_size"
        android:bottomLeftRadius="@dimen/biometric_dialog_corner_size"
+66 −75
Original line number Diff line number Diff line
@@ -33,9 +33,6 @@ import com.android.internal.os.SomeArgs;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.CommandQueue;

import java.util.HashMap;
import java.util.Map;

/**
 * Receives messages sent from AuthenticationClient and shows the appropriate biometric UI (e.g.
 * BiometricDialogView).
@@ -52,10 +49,8 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
    private static final int MSG_BUTTON_NEGATIVE = 6;
    private static final int MSG_USER_CANCELED = 7;
    private static final int MSG_BUTTON_POSITIVE = 8;
    private static final int MSG_BIOMETRIC_SHOW_TRY_AGAIN = 9;
    private static final int MSG_TRY_AGAIN_PRESSED = 10;
    private static final int MSG_TRY_AGAIN_PRESSED = 9;

    private Map<Integer, BiometricDialogView> mDialogs; // BiometricAuthenticator type, view
    private SomeArgs mCurrentDialogArgs;
    private BiometricDialogView mCurrentDialog;
    private WindowManager mWindowManager;
@@ -63,21 +58,22 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
    private boolean mDialogShowing;
    private Callback mCallback = new Callback();

    private boolean mTryAgainShowing; // No good place to save state before config change :/
    private boolean mConfirmShowing; // No good place to save state before config change :/

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case MSG_SHOW_DIALOG:
                    handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */);
                    handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */,
                            null /* savedState */);
                    break;
                case MSG_BIOMETRIC_AUTHENTICATED:
                    handleBiometricAuthenticated();
                    handleBiometricAuthenticated((boolean) msg.obj);
                    break;
                case MSG_BIOMETRIC_HELP:
                    handleBiometricHelp((String) msg.obj);
                    SomeArgs args = (SomeArgs) msg.obj;
                    handleBiometricHelp((String) args.arg1 /* message */,
                            (boolean) args.arg2 /* requireTryAgain */);
                    args.recycle();
                    break;
                case MSG_BIOMETRIC_ERROR:
                    handleBiometricError((String) msg.obj);
@@ -94,9 +90,6 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
                case MSG_BUTTON_POSITIVE:
                    handleButtonPositive();
                    break;
                case MSG_BIOMETRIC_SHOW_TRY_AGAIN:
                    handleShowTryAgain();
                    break;
                case MSG_TRY_AGAIN_PRESSED:
                    handleTryAgainPressed();
                    break;
@@ -137,30 +130,22 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba

    @Override
    public void start() {
        createDialogs();

        if (!mDialogs.isEmpty()) {
        final PackageManager pm = mContext.getPackageManager();
        if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
                || pm.hasSystemFeature(PackageManager.FEATURE_FACE)
                || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
            getComponent(CommandQueue.class).addCallback(this);
            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        }
    }

    private void createDialogs() {
        final PackageManager pm = mContext.getPackageManager();
        mDialogs = new HashMap<>();
        if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
            mDialogs.put(BiometricAuthenticator.TYPE_FACE, new FaceDialogView(mContext, mCallback));
        }
        if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
            mDialogs.put(BiometricAuthenticator.TYPE_FINGERPRINT,
                    new FingerprintDialogView(mContext, mCallback));
        }
    }

    @Override
    public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
            int type, boolean requireConfirmation, int userId) {
        if (DEBUG) Log.d(TAG, "showBiometricDialog, type: " + type);
        if (DEBUG) {
            Log.d(TAG, "showBiometricDialog, type: " + type
                    + ", requireConfirmation: " + requireConfirmation);
        }
        // Remove these messages as they are part of the previous client
        mHandler.removeMessages(MSG_BIOMETRIC_ERROR);
        mHandler.removeMessages(MSG_BIOMETRIC_HELP);
@@ -176,15 +161,18 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
    }

    @Override
    public void onBiometricAuthenticated() {
        if (DEBUG) Log.d(TAG, "onBiometricAuthenticated");
        mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget();
    public void onBiometricAuthenticated(boolean authenticated) {
        if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated);
        mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, authenticated).sendToTarget();
    }

    @Override
    public void onBiometricHelp(String message) {
        if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
        mHandler.obtainMessage(MSG_BIOMETRIC_HELP, message).sendToTarget();
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = message;
        args.arg2 = false; // requireTryAgain
        mHandler.obtainMessage(MSG_BIOMETRIC_HELP, args).sendToTarget();
    }

    @Override
@@ -199,16 +187,21 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
        mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget();
    }

    @Override
    public void showBiometricTryAgain() {
        if (DEBUG) Log.d(TAG, "showBiometricTryAgain");
        mHandler.obtainMessage(MSG_BIOMETRIC_SHOW_TRY_AGAIN).sendToTarget();
    }

    private void handleShowDialog(SomeArgs args, boolean skipAnimation) {
    private void handleShowDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
        mCurrentDialogArgs = args;
        final int type = args.argi1;
        mCurrentDialog = mDialogs.get(type);

        if (type == BiometricAuthenticator.TYPE_FINGERPRINT) {
            mCurrentDialog = new FingerprintDialogView(mContext, mCallback);
        } else if (type == BiometricAuthenticator.TYPE_FACE) {
            mCurrentDialog = new FaceDialogView(mContext, mCallback);
        } else {
            Log.e(TAG, "Unsupported type: " + type);
        }

        if (savedState != null) {
            mCurrentDialog.restoreState(savedState);
        }

        if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: "
                + mCurrentDialog.isAnimatingAway() + " type: " + type);
@@ -224,20 +217,18 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
        mCurrentDialog.setRequireConfirmation((boolean) args.arg3);
        mCurrentDialog.setUserId(args.argi2);
        mCurrentDialog.setSkipIntro(skipAnimation);
        mCurrentDialog.setPendingTryAgain(mTryAgainShowing);
        mCurrentDialog.setPendingConfirm(mConfirmShowing);
        mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
        mDialogShowing = true;
    }

    private void handleBiometricAuthenticated() {
        if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated");
    private void handleBiometricAuthenticated(boolean authenticated) {
        if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated: " + authenticated);

        if (authenticated) {
            mCurrentDialog.announceForAccessibility(
                    mContext.getResources()
                            .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
            if (mCurrentDialog.requiresConfirmation()) {
            mConfirmShowing = true;
                mCurrentDialog.showConfirmationButton(true /* show */);
            } else {
                mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED);
@@ -245,11 +236,17 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
                    handleHideDialog(false /* userCanceled */);
                }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs());
            }
        } else {
            handleBiometricHelp(mContext.getResources()
                    .getString(com.android.internal.R.string.biometric_not_recognized),
                    true /* requireTryAgain */);
            mCurrentDialog.showTryAgainButton(true /* show */);
        }
    }

    private void handleBiometricHelp(String message) {
    private void handleBiometricHelp(String message, boolean requireTryAgain) {
        if (DEBUG) Log.d(TAG, "handleBiometricHelp: " + message);
        mCurrentDialog.showHelpMessage(message);
        mCurrentDialog.showHelpMessage(message, requireTryAgain);
    }

    private void handleBiometricError(String error) {
@@ -258,7 +255,6 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
            if (DEBUG) Log.d(TAG, "Dialog already dismissed");
            return;
        }
        mTryAgainShowing = false;
        mCurrentDialog.showErrorMessage(error);
    }

@@ -279,8 +275,6 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
        }
        mReceiver = null;
        mDialogShowing = false;
        mConfirmShowing = false;
        mTryAgainShowing = false;
        mCurrentDialog.startDismiss();
    }

@@ -294,7 +288,6 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception when handling negative button", e);
        }
        mTryAgainShowing = false;
        handleHideDialog(false /* userCanceled */);
    }

@@ -308,25 +301,16 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception when handling positive button", e);
        }
        mConfirmShowing = false;
        handleHideDialog(false /* userCanceled */);
    }

    private void handleUserCanceled() {
        mTryAgainShowing = false;
        mConfirmShowing = false;
        handleHideDialog(true /* userCanceled */);
    }

    private void handleShowTryAgain() {
        mCurrentDialog.showTryAgainButton(true /* show */);
        mTryAgainShowing = true;
    }

    private void handleTryAgainPressed() {
        try {
            mCurrentDialog.clearTemporaryMessage();
            mTryAgainShowing = false;
            mReceiver.onTryAgainPressed();
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException when handling try again", e);
@@ -337,13 +321,20 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        final boolean wasShowing = mDialogShowing;

        // Save the state of the current dialog (buttons showing, etc)
        final Bundle savedState = new Bundle();
        if (mCurrentDialog != null) {
            mCurrentDialog.onSaveState(savedState);
        }

        if (mDialogShowing) {
            mCurrentDialog.forceRemove();
            mDialogShowing = false;
        }
        createDialogs();

        if (wasShowing) {
            handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */);
            handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState);
        }
    }
}
Loading