ConfirmDeviceCredential should respond to cancel when launched through BP

Fixes: 128747871

Test: BiometricPrompt launched by ConfirmDeviceCredential is canceled
Test: ConfirmLock* can also now be canceled
Test: No effect on non-biometric related paths

Change-Id: I237de136e63d523fece87fad7a93f4ecd66d800b
This commit is contained in:
Kevin Chyn
2019-03-25 18:15:57 -07:00
parent 44427259e8
commit eeca918ac7
3 changed files with 46 additions and 9 deletions

View File

@@ -16,19 +16,21 @@
package com.android.settings.password; package com.android.settings.password;
import android.app.Activity;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback; import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
import android.hardware.biometrics.BiometricPrompt.AuthenticationResult; import android.hardware.biometrics.BiometricPrompt.AuthenticationResult;
import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
import android.os.Bundle; import android.os.Bundle;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment; import com.android.settings.core.InstrumentedFragment;
@@ -40,6 +42,8 @@ import java.util.concurrent.Executor;
*/ */
public class BiometricFragment extends InstrumentedFragment { public class BiometricFragment extends InstrumentedFragment {
private static final String TAG = "ConfirmDeviceCredential/BiometricFragment";
// Re-set by the application. Should be done upon orientation changes, etc // Re-set by the application. Should be done upon orientation changes, etc
private Executor mClientExecutor; private Executor mClientExecutor;
private AuthenticationCallback mClientCallback; private AuthenticationCallback mClientCallback;
@@ -48,7 +52,6 @@ public class BiometricFragment extends InstrumentedFragment {
private int mUserId; private int mUserId;
// Created/Initialized once and retained // Created/Initialized once and retained
private final Handler mHandler = new Handler(Looper.getMainLooper());
private Bundle mBundle; private Bundle mBundle;
private BiometricPrompt mBiometricPrompt; private BiometricPrompt mBiometricPrompt;
private CancellationSignal mCancellationSignal; private CancellationSignal mCancellationSignal;
@@ -82,6 +85,20 @@ public class BiometricFragment extends InstrumentedFragment {
} }
}; };
// TODO(b/123378871): Remove when moved.
private final IBiometricConfirmDeviceCredentialCallback mCancelCallback
= new IBiometricConfirmDeviceCredentialCallback.Stub() {
@Override
public void cancel() {
final Activity activity = getActivity();
if (activity != null) {
activity.finish();
} else {
Log.e(TAG, "Activity null!");
}
}
};
/** /**
* @param bundle Bundle passed from {@link BiometricPrompt.Builder#buildIntent()} * @param bundle Bundle passed from {@link BiometricPrompt.Builder#buildIntent()}
* @return * @return
@@ -123,6 +140,7 @@ public class BiometricFragment extends InstrumentedFragment {
mBiometricPrompt = new BiometricPrompt.Builder(getContext()) mBiometricPrompt = new BiometricPrompt.Builder(getContext())
.setTitle(mBundle.getString(BiometricPrompt.KEY_TITLE)) .setTitle(mBundle.getString(BiometricPrompt.KEY_TITLE))
.setUseDefaultTitle() // use default title if title is null/empty .setUseDefaultTitle() // use default title if title is null/empty
.setFromConfirmDeviceCredential()
.setSubtitle(mBundle.getString(BiometricPrompt.KEY_SUBTITLE)) .setSubtitle(mBundle.getString(BiometricPrompt.KEY_SUBTITLE))
.setDescription(mBundle.getString(BiometricPrompt.KEY_DESCRIPTION)) .setDescription(mBundle.getString(BiometricPrompt.KEY_DESCRIPTION))
.setConfirmationRequired( .setConfirmationRequired(
@@ -135,7 +153,7 @@ public class BiometricFragment extends InstrumentedFragment {
// TODO: CC doesn't use crypto for now // TODO: CC doesn't use crypto for now
mBiometricPrompt.authenticateUser(mCancellationSignal, mClientExecutor, mBiometricPrompt.authenticateUser(mCancellationSignal, mClientExecutor,
mAuthenticationCallback, mUserId); mAuthenticationCallback, mUserId, mCancelCallback);
} }
@Override @Override

View File

@@ -106,13 +106,11 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
private AuthenticationCallback mAuthenticationCallback = new AuthenticationCallback() { private AuthenticationCallback mAuthenticationCallback = new AuthenticationCallback() {
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
if (!mGoingToBackground) { if (!mGoingToBackground) {
if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED) { if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED
|| errorCode == BiometricPrompt.BIOMETRIC_ERROR_CANCELED) {
if (mIsFallback) { if (mIsFallback) {
mBiometricManager.onConfirmDeviceCredentialError( mBiometricManager.onConfirmDeviceCredentialError(
BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, errorCode, getStringForError(errorCode));
getString(
com.android.internal.R.string
.biometric_error_user_canceled));
} }
finish(); finish();
} else { } else {
@@ -139,6 +137,17 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
} }
}; };
private String getStringForError(int errorCode) {
switch (errorCode) {
case BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED:
return getString(com.android.internal.R.string.biometric_error_user_canceled);
case BiometricConstants.BIOMETRIC_ERROR_CANCELED:
return getString(com.android.internal.R.string.biometric_error_canceled);
default:
return null;
}
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -178,7 +187,6 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
intent.getBundleExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE); intent.getBundleExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE);
if (bpBundle != null) { if (bpBundle != null) {
mIsFallback = true; mIsFallback = true;
// TODO: CDC maybe should show description as well.
mTitle = bpBundle.getString(BiometricPrompt.KEY_TITLE); mTitle = bpBundle.getString(BiometricPrompt.KEY_TITLE);
mDetails = bpBundle.getString(BiometricPrompt.KEY_SUBTITLE); mDetails = bpBundle.getString(BiometricPrompt.KEY_SUBTITLE);
} else { } else {

View File

@@ -19,6 +19,7 @@ package com.android.settings.password;
import android.app.KeyguardManager; import android.app.KeyguardManager;
import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserManager; import android.os.UserManager;
import android.util.Log; import android.util.Log;
@@ -51,6 +52,15 @@ public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivi
private ConfirmCredentialTheme mConfirmCredentialTheme; private ConfirmCredentialTheme mConfirmCredentialTheme;
private BiometricManager mBiometricManager; private BiometricManager mBiometricManager;
// TODO(b/123378871): Remove when moved.
private final IBiometricConfirmDeviceCredentialCallback mCancelCallback
= new IBiometricConfirmDeviceCredentialCallback.Stub() {
@Override
public void cancel() {
finish();
}
};
private boolean isInternalActivity() { private boolean isInternalActivity() {
return (this instanceof ConfirmLockPassword.InternalActivity) return (this instanceof ConfirmLockPassword.InternalActivity)
|| (this instanceof ConfirmLockPattern.InternalActivity); || (this instanceof ConfirmLockPattern.InternalActivity);
@@ -81,6 +91,7 @@ public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivi
super.onCreate(savedState); super.onCreate(savedState);
mBiometricManager = getSystemService(BiometricManager.class); mBiometricManager = getSystemService(BiometricManager.class);
mBiometricManager.registerCancellationCallback(mCancelCallback);
if (mConfirmCredentialTheme == ConfirmCredentialTheme.NORMAL) { if (mConfirmCredentialTheme == ConfirmCredentialTheme.NORMAL) {
// Prevent the content parent from consuming the window insets because GlifLayout uses // Prevent the content parent from consuming the window insets because GlifLayout uses