Is there any way to add our own custom layout to biometric prompt as I have seen various similar threads but there seems to be no solution provided for it yet and fingerprintmanager is deprecated so i don't want to use that.
I don't think this is possible. The latest version of Android's BiometricPrompt class is designed to display its own custom activity/fragment/dialogue. There is no API that allows a user to modify the layout attached to BiometricPrompt either. Take a look at the source code hosted on Google's repository: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:biometric/biometric/src/main/java/androidx/biometric/
The only possibility would be to build a biometric authenticator program/class from the ground up (like Google did). But that is an Everest of its own.
Here is Google's code that runs the custom fingerprint dialogue. Notice that it creates a BiometricFragment object:
/**
* Shows the biometric prompt to the user and begins authentication.
*
* @param info A {@link PromptInfo} object describing the appearance and behavior of the prompt.
* @param crypto A crypto object to be associated with this authentication.
*/
private void authenticateInternal(@NonNull PromptInfo info, @Nullable CryptoObject crypto) {
if (mClientFragmentManager == null) {
Log.e(TAG, "Unable to start authentication. Client fragment manager was null.");
return;
}
if (mClientFragmentManager.isStateSaved()) {
Log.e(TAG, "Unable to start authentication. Called after onSaveInstanceState().");
return;
}
final BiometricFragment biometricFragment =
findOrAddBiometricFragment(mClientFragmentManager);
biometricFragment.authenticate(info, crypto);
}
Going to the code for BiometricFragment, we see where the FingerprintDialogFragment dialogue object is displayed to the user at dialog.show(...) towards the end:
/**
* Shows the fingerprint dialog UI to the user and begins authentication.
*/
@SuppressWarnings("deprecation")
private void showFingerprintDialogForAuthentication() {
final Context context = requireContext();
androidx.core.hardware.fingerprint.FingerprintManagerCompat fingerprintManagerCompat =
androidx.core.hardware.fingerprint.FingerprintManagerCompat.from(context);
final int errorCode = checkForFingerprintPreAuthenticationErrors(fingerprintManagerCompat);
if (errorCode != 0) {
sendErrorAndDismiss(
errorCode, ErrorUtils.getFingerprintErrorString(getContext(), errorCode));
return;
}
if (isAdded()) {
final boolean shouldHideFingerprintDialog =
DeviceUtils.shouldHideFingerprintDialog(context, Build.MODEL);
if (mViewModel.isFingerprintDialogDismissedInstantly() != shouldHideFingerprintDialog) {
mHandler.postDelayed(
new Runnable() {
@Override
public void run() {
mViewModel.setFingerprintDialogDismissedInstantly(
shouldHideFingerprintDialog);
}
},
DISMISS_INSTANTLY_DELAY_MS);
}
if (!shouldHideFingerprintDialog) {
final FingerprintDialogFragment dialog = FingerprintDialogFragment.newInstance();
dialog.show(getParentFragmentManager(), FINGERPRINT_DIALOG_FRAGMENT_TAG);
}
mViewModel.setCanceledFrom(CANCELED_FROM_NONE);
fingerprintManagerCompat.authenticate(
CryptoObjectUtils.wrapForFingerprintManager(mViewModel.getCryptoObject()),
0 /* flags */,
mViewModel.getCancellationSignalProvider().getFingerprintCancellationSignal(),
mViewModel.getAuthenticationCallbackProvider().getFingerprintCallback(),
null /* handler */);
}
}
Going to Google's FingerprintDialogFrament class, we see where the dialog is created. Notice where View layout inflates the R.layout.fingerprint_dialog_layout towards the top, which is the built-in layout that displays the fingerprint dialog:
@Override
@NonNull
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle(mViewModel.getTitle());
// We have to use builder.getContext() instead of the usual getContext() in order to get
// the appropriately themed context for this dialog.
final View layout = LayoutInflater.from(builder.getContext())
.inflate(R.layout.fingerprint_dialog_layout, null);
final TextView subtitleView = layout.findViewById(R.id.fingerprint_subtitle);
final TextView descriptionView = layout.findViewById(R.id.fingerprint_description);
final CharSequence subtitle = mViewModel.getSubtitle();
if (TextUtils.isEmpty(subtitle)) {
subtitleView.setVisibility(View.GONE);
} else {
subtitleView.setVisibility(View.VISIBLE);
subtitleView.setText(subtitle);
}
final CharSequence description = mViewModel.getDescription();
if (TextUtils.isEmpty(description)) {
descriptionView.setVisibility(View.GONE);
} else {
descriptionView.setVisibility(View.VISIBLE);
descriptionView.setText(description);
}
mFingerprintIcon = layout.findViewById(R.id.fingerprint_icon);
mHelpMessageView = layout.findViewById(R.id.fingerprint_error);
final CharSequence negativeButtonText =
mViewModel.isDeviceCredentialAllowed()
? getString(R.string.confirm_device_credential_password)
: mViewModel.getNegativeButtonText();
builder.setNegativeButton(negativeButtonText, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mViewModel.setNegativeButtonPressPending(true);
}
});
builder.setView(layout);
Dialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
return dialog;
}
Here is the code for R.layout.fingerprint_dialog_layout, the built-in fingerprint dialog:
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 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.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/fingerprint_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:textColor="?android:attr/textColorSecondary"
android:textSize="16sp"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"/>
<TextView
android:id="@+id/fingerprint_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="0dp"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:textColor="?android:attr/textColorSecondary"
android:textSize="16sp"
android:maxLines="4"/>
<ImageView
android:id="@+id/fingerprint_icon"
android:layout_width="@dimen/fingerprint_icon_size"
android:layout_height="@dimen/fingerprint_icon_size"
android:layout_gravity="center_horizontal"
android:layout_marginTop="32dp"
android:scaleType="fitXY" />
<TextView
android:id="@+id/fingerprint_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:paddingTop="16dp"
android:paddingBottom="24dp"
android:textSize="14sp"
android:gravity="center_horizontal"
android:accessibilityLiveRegion="polite"
android:text="@string/fingerprint_dialog_touch_sensor"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
</ScrollView>
© 2022 - 2024 — McMap. All rights reserved.