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

Commit e56df887 authored by Kevin Chyn's avatar Kevin Chyn
Browse files

CDCA is plumbed through BP

CDCA can be invoked with a bundle extra originating from BiometricService.
This allows us to add/forward new BP builder options to CDCA without having
duplicate API each time.

Bug: 111461540
Test: test app, receives correct callbacks
Test: CDC still works

Change-Id: Ia2080d161abba87949338176b34cdf440ed4ed53
parent 29aaf60a
Loading
Loading
Loading
Loading
+17 −75
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment;

import java.util.concurrent.Executor;
@@ -39,11 +40,6 @@ import java.util.concurrent.Executor;
 */
public class BiometricFragment extends InstrumentedFragment {

    private static final String KEY_TITLE = "title";
    private static final String KEY_SUBTITLE = "subtitle";
    private static final String KEY_DESCRIPTION = "description";
    private static final String KEY_NEGATIVE_TEXT = "negative_text";

    // Re-set by the application. Should be done upon orientation changes, etc
    private Executor mClientExecutor;
    private AuthenticationCallback mClientCallback;
@@ -53,7 +49,7 @@ public class BiometricFragment extends InstrumentedFragment {

    // Created/Initialized once and retained
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private PromptInfo mPromptInfo;
    private Bundle mBundle;
    private BiometricPrompt mBiometricPrompt;
    private CancellationSignal mCancellationSignal;

@@ -82,13 +78,17 @@ public class BiometricFragment extends InstrumentedFragment {
        public void onClick(DialogInterface dialog, int which) {
            mAuthenticationCallback.onAuthenticationError(
                    BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON,
                    mPromptInfo.getNegativeButtonText());
                    mBundle.getString(BiometricPrompt.KEY_NEGATIVE_TEXT));
        }
    };

    public static BiometricFragment newInstance(PromptInfo info) {
    /**
     * @param bundle Bundle passed from {@link BiometricPrompt.Builder#buildIntent()}
     * @return
     */
    public static BiometricFragment newInstance(Bundle bundle) {
        BiometricFragment biometricFragment = new BiometricFragment();
        biometricFragment.setArguments(info.getBundle());
        biometricFragment.setArguments(bundle);
        return biometricFragment;
    }

@@ -119,14 +119,16 @@ public class BiometricFragment extends InstrumentedFragment {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

        mPromptInfo = new PromptInfo(getArguments());
        mBundle = getArguments();
        mBiometricPrompt = new BiometricPrompt.Builder(getContext())
            .setTitle(mPromptInfo.getTitle())
            .setTitle(mBundle.getString(BiometricPrompt.KEY_TITLE))
            .setUseDefaultTitle() // use default title if title is null/empty
            .setSubtitle(mPromptInfo.getSubtitle())
            .setDescription(mPromptInfo.getDescription())
            .setNegativeButton(mPromptInfo.getNegativeButtonText(), mClientExecutor,
                    mNegativeButtonListener)
            .setSubtitle(mBundle.getString(BiometricPrompt.KEY_SUBTITLE))
            .setDescription(mBundle.getString(BiometricPrompt.KEY_DESCRIPTION))
            .setRequireConfirmation(mBundle.getBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION))
            .setNegativeButton(getResources().getString(
                    R.string.confirm_device_credential_use_alternate_method),
                    mClientExecutor, mNegativeButtonListener)
            .build();
        mCancellationSignal = new CancellationSignal();

@@ -139,65 +141,5 @@ public class BiometricFragment extends InstrumentedFragment {
    public int getMetricsCategory() {
        return SettingsEnums.BIOMETRIC_FRAGMENT;
    }

    /**
     * A simple wrapper for BiometricPrompt.PromptInfo. Since we want to manage the lifecycle
     * of BiometricPrompt correctly, the information needs to be stored in here.
     */
    static class PromptInfo {
        private final Bundle mBundle;

        private PromptInfo(Bundle bundle) {
            mBundle = bundle;
        }

        Bundle getBundle() {
            return mBundle;
        }

        public CharSequence getTitle() {
            return mBundle.getCharSequence(KEY_TITLE);
        }

        public CharSequence getSubtitle() {
            return mBundle.getCharSequence(KEY_SUBTITLE);
        }

        public CharSequence getDescription() {
            return mBundle.getCharSequence(KEY_DESCRIPTION);
        }

        public CharSequence getNegativeButtonText() {
            return mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
        }

        public static class Builder {
            private final Bundle mBundle = new Bundle();

            public Builder setTitle(@NonNull CharSequence title) {
                mBundle.putCharSequence(KEY_TITLE, title);
                return this;
            }

            public Builder setSubtitle(@Nullable CharSequence subtitle) {
                mBundle.putCharSequence(KEY_SUBTITLE, subtitle);
                return this;
            }

            public Builder setDescription(@Nullable CharSequence description) {
                mBundle.putCharSequence(KEY_DESCRIPTION, description);
                return this;
            }

            public Builder setNegativeButtonText(@NonNull CharSequence text) {
                mBundle.putCharSequence(KEY_NEGATIVE_TEXT, text);
                return this;
            }

            public PromptInfo build() {
                return new PromptInfo(mBundle);
            }
        }
    }
}
+39 −10
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.Context;
import android.content.Intent;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
@@ -87,6 +88,8 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
    private TrustManager mTrustManager;
    private ChooseLockSettingsHelper mChooseLockSettingsHelper;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private boolean mIsFallback; // BiometricPrompt fallback
    private boolean mCCLaunched;

    private String mTitle;
    private String mDetails;
@@ -102,6 +105,13 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
        public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
            if (!mGoingToBackground) {
                if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED) {
                    if (mIsFallback) {
                        mBiometricManager.onConfirmDeviceCredentialError(
                                BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
                                getString(
                                        com.android.internal.R.string
                                                .biometric_error_user_canceled));
                    }
                    finish();
                } else {
                    // All other errors go to some version of CC
@@ -118,6 +128,10 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
            ConfirmDeviceCredentialUtils.checkForPendingIntent(
                    ConfirmDeviceCredentialActivity.this);

            if (mIsFallback) {
                mBiometricManager.onConfirmDeviceCredentialSuccess();
            }

            setResult(Activity.RESULT_OK);
            finish();
        }
@@ -158,6 +172,19 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
        mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
        final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);

        Bundle bpBundle =
                intent.getBundleExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE);
        if (bpBundle != null) {
            mIsFallback = true;
            // TODO: CDC maybe should show description as well.
            mTitle = bpBundle.getString(BiometricPrompt.KEY_TITLE);
            mDetails = bpBundle.getString(BiometricPrompt.KEY_SUBTITLE);
        } else {
            bpBundle = new Bundle();
            bpBundle.putString(BiometricPrompt.KEY_TITLE, mTitle);
            bpBundle.putString(BiometricPrompt.KEY_SUBTITLE, mDetails);
        }

        boolean launchedBiometric = false;
        boolean launchedCDC = false;
        // If the target is a managed user and user key not unlocked yet, we will force unlock
@@ -170,7 +197,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
                && !lockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
            mCredentialMode = CREDENTIAL_MANAGED;
            if (isBiometricAllowed(effectiveUserId)) {
                showBiometricPrompt();
                showBiometricPrompt(bpBundle);
                launchedBiometric = true;
            } else {
                showConfirmCredentials();
@@ -181,7 +208,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
            if (isBiometricAllowed(effectiveUserId)) {
                // Don't need to check if biometrics / pin/pattern/pass are enrolled. It will go to
                // onAuthenticationError and do the right thing automatically.
                showBiometricPrompt();
                showBiometricPrompt(bpBundle);
                launchedBiometric = true;
            } else {
                showConfirmCredentials();
@@ -216,6 +243,13 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
            if (mBiometricFragment != null) {
                mBiometricFragment.cancel();
            }

            if (mIsFallback && !mCCLaunched) {
                mBiometricManager.onConfirmDeviceCredentialError(
                        BiometricConstants.BIOMETRIC_ERROR_CANCELED,
                        getString(com.android.internal.R.string.biometric_error_user_canceled));
            }

            finish();
        } else {
            mGoingToBackground = false;
@@ -242,7 +276,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
                && !isBiometricDisabledByAdmin(effectiveUserId);
    }

    private void showBiometricPrompt() {
    private void showBiometricPrompt(Bundle bundle) {
        mBiometricManager.setActiveUser(mUserId);

        mBiometricFragment = (BiometricFragment) getSupportFragmentManager()
@@ -250,13 +284,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
        boolean newFragment = false;

        if (mBiometricFragment == null) {
            final BiometricFragment.PromptInfo info = new BiometricFragment.PromptInfo.Builder()
                    .setTitle(mTitle)
                    .setSubtitle(mDetails)
                    .setNegativeButtonText(getResources()
                            .getString(R.string.confirm_device_credential_use_alternate_method))
                    .build();
            mBiometricFragment = BiometricFragment.newInstance(info);
            mBiometricFragment = BiometricFragment.newInstance(bundle);
            newFragment = true;
        }
        mBiometricFragment.setCallbacks(mExecutor, mAuthenticationCallback);
@@ -272,6 +300,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
     * Shows ConfirmDeviceCredentials for normal apps.
     */
    private void showConfirmCredentials() {
        mCCLaunched = true;
        boolean launched = false;
        if (mCredentialMode == CREDENTIAL_MANAGED) {
            // We set the challenge as 0L, so it will force to unlock managed profile when it
+16 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.settings.password;

import android.app.KeyguardManager;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.os.Bundle;
import android.os.UserManager;
import android.view.MenuItem;
@@ -45,6 +47,7 @@ public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivi
    private boolean mFirstTimeVisible = true;
    private boolean mIsKeyguardLocked = false;
    private ConfirmCredentialTheme mConfirmCredentialTheme;
    private BiometricManager mBiometricManager;

    private boolean isInternalActivity() {
        return (this instanceof ConfirmLockPassword.InternalActivity)
@@ -68,6 +71,8 @@ public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivi
        }
        super.onCreate(savedState);

        mBiometricManager = getSystemService(BiometricManager.class);

        if (mConfirmCredentialTheme == ConfirmCredentialTheme.NORMAL) {
            // Prevent the content parent from consuming the window insets because GlifLayout uses
            // it to show the status bar background.
@@ -140,6 +145,17 @@ public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivi
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        // TODO(b/123378871): Remove when moved.
        if (!isChangingConfigurations()) {
            mBiometricManager.onConfirmDeviceCredentialError(
                    BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
                    getString(com.android.internal.R.string.biometric_error_user_canceled));
        }
    }

    @Override
    public void finish() {
        super.finish();
+3 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserManager;
@@ -84,6 +85,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
    protected final Handler mHandler = new Handler();
    protected boolean mFrp;
    private CharSequence mFrpAlternateButtonText;
    protected BiometricManager mBiometricManager;

    private boolean isInternalActivity() {
        return (getActivity() instanceof ConfirmLockPassword.InternalActivity)
@@ -107,6 +109,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
        mLockPatternUtils = new LockPatternUtils(getActivity());
        mDevicePolicyManager = (DevicePolicyManager) getActivity().getSystemService(
                Context.DEVICE_POLICY_SERVICE);
        mBiometricManager = getActivity().getSystemService(BiometricManager.class);
    }

    @Override
+1 −0
Original line number Diff line number Diff line
@@ -437,6 +437,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
                    ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils,
                            mUserManager, mEffectiveUserId);
                }
                mBiometricManager.onConfirmDeviceCredentialSuccess();
                startDisappearAnimation(intent);
                ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity());
            } else {
Loading