diff --git a/src/com/android/settings/password/BiometricFragment.java b/src/com/android/settings/password/BiometricFragment.java index 13ec5431d68..3809a4a5b48 100644 --- a/src/com/android/settings/password/BiometricFragment.java +++ b/src/com/android/settings/password/BiometricFragment.java @@ -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); - } - } - } } diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java index 5eb1f322c27..3fa2f6ac08b 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java @@ -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 diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java index c00f9ab124c..56e6573d768 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java @@ -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(); diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java index 2de7625b9ed..e14ec811353 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java @@ -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 diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java index 7344077d742..f8938703bd7 100644 --- a/src/com/android/settings/password/ConfirmLockPassword.java +++ b/src/com/android/settings/password/ConfirmLockPassword.java @@ -437,6 +437,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils, mUserManager, mEffectiveUserId); } + mBiometricManager.onConfirmDeviceCredentialSuccess(); startDisappearAnimation(intent); ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity()); } else { diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java index 5645193c01a..29cdfef0516 100644 --- a/src/com/android/settings/password/ConfirmLockPattern.java +++ b/src/com/android/settings/password/ConfirmLockPattern.java @@ -490,6 +490,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils, mUserManager, mEffectiveUserId); } + mBiometricManager.onConfirmDeviceCredentialSuccess(); startDisappearAnimation(intent); ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity()); } else {