Show a dialog preventing face enrollment in split mode.

Test: atest CombinedBiometricProfileSettingsTest
Test: atest FingerprintSettingsFragmentTest
Test: manaul test- go to split screen mode and try to enroll
face
Bug: 276938441

Change-Id: I45e859b453700aa79f7774fb5deda81b1f30e5a5
This commit is contained in:
Hao Dong
2023-04-04 19:50:26 +00:00
parent 8930e6ea87
commit 64277a23bb
9 changed files with 314 additions and 146 deletions

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2023 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.
*/
package com.android.settings.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.DialogInterface;
import android.hardware.biometrics.BiometricAuthenticator;
import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
/**
* This alert dialog shows when fingerprint is being added in multi window mode.
*/
public class BiometricsSplitScreenDialog extends InstrumentedDialogFragment {
private static final String KEY_BIOMETRICS_MODALITY = "biometrics_modality";
@BiometricAuthenticator.Modality
private int mBiometricsModality;
/** Returns the new instance of the class */
public static BiometricsSplitScreenDialog newInstance(
@BiometricAuthenticator.Modality int biometricsModality) {
final BiometricsSplitScreenDialog dialog = new BiometricsSplitScreenDialog();
final Bundle args = new Bundle();
args.putInt(KEY_BIOMETRICS_MODALITY, biometricsModality);
dialog.setArguments(args);
return dialog;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mBiometricsModality = getArguments().getInt(KEY_BIOMETRICS_MODALITY);
int titleId;
int messageId;
switch (mBiometricsModality) {
case TYPE_FACE:
titleId = R.string.biometric_settings_add_face_in_split_mode_title;
messageId = R.string.biometric_settings_add_face_in_split_mode_message;
break;
default:
titleId = R.string.biometric_settings_add_fingerprint_in_split_mode_title;
messageId = R.string.biometric_settings_add_fingerprint_in_split_mode_message;
}
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(titleId)
.setMessage(messageId)
.setPositiveButton(
R.string.biometric_settings_add_biometrics_in_split_mode_ok,
(DialogInterface.OnClickListener) (dialog, which) -> dialog.dismiss());
return builder.create();
}
@Override
public int getMetricsCategory() {
switch (mBiometricsModality) {
case TYPE_FACE:
return SettingsEnums.DIALOG_ADD_FACE_ERROR_IN_SPLIT_MODE;
default:
return SettingsEnums.DIALOG_ADD_FINGERPRINT_ERROR_IN_SPLIT_MODE;
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.biometrics.combination;
import static android.app.Activity.RESULT_OK;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED;
@@ -41,7 +43,7 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment;
import com.android.settings.biometrics.BiometricsSplitScreenDialog;
import com.android.settings.core.SettingsBaseActivity;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.password.ChooseLockGeneric;
@@ -143,6 +145,18 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
// since FingerprintSettings and FaceSettings revoke the challenge when finishing.
if (getFacePreferenceKey().equals(key)) {
mDoNotFinishActivity = true;
// If it's split mode and there is no enrolled face, show the dialog. (if there is
// enrolled face, FaceSettingsEnrollButtonPreferenceController#onClick will handle
// the dialog)
if (getActivity().isInMultiWindowMode() && !mFaceManager.hasEnrolledTemplates(
mUserId)) {
BiometricsSplitScreenDialog.newInstance(TYPE_FACE).show(
getActivity().getSupportFragmentManager(),
BiometricsSplitScreenDialog.class.getName());
return true;
}
mFaceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
try {
final byte[] token = requestGatekeeperHat(context, mGkPwHandle, mUserId,
@@ -168,10 +182,14 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
} else if (getFingerprintPreferenceKey().equals(key)) {
mDoNotFinishActivity = true;
if (shouldSkipForUdfpsInMultiWindowMode()) {
new FingerprintSettingsFragment.FingerprintSplitScreenDialog().show(
// If it's split mode and there is no enrolled fingerprint, show the dialog. (if
// there is enrolled fingerprint, FingerprintSettingsFragment#onPreferenceTreeClick
// will handle the dialog)
if (getActivity().isInMultiWindowMode() && !mFingerprintManager.hasEnrolledFingerprints(
mUserId)) {
BiometricsSplitScreenDialog.newInstance(TYPE_FINGERPRINT).show(
getActivity().getSupportFragmentManager(),
FingerprintSettingsFragment.FingerprintSplitScreenDialog.class.getName());
BiometricsSplitScreenDialog.class.getName());
return true;
}
@@ -386,27 +404,4 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
return 0;
}
}
/**
* Returns whether the click should be skipped.
* True if the following conditions are all met:
* 1. It's split mode.
* 2. It's udfps.
* 3. There is no enrolled fingerprint. (If there is enrolled fingerprint, FingerprintSettings
* will handle the adding fingerprint.
*/
private boolean shouldSkipForUdfpsInMultiWindowMode() {
if (!getActivity().isInMultiWindowMode() || mFingerprintManager.hasEnrolledFingerprints(
mUserId)) {
return false;
}
for (FingerprintSensorPropertiesInternal prop :
mFingerprintManager.getSensorPropertiesInternal()) {
if (prop.isAnyUdfpsType()) {
return true;
}
}
return false;
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.biometrics.face;
import static android.app.Activity.RESULT_OK;
import static android.app.admin.DevicePolicyResources.Strings.Settings.FACE_SETTINGS_FOR_WORK_TITLE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST;
import static com.android.settings.biometrics.BiometricEnrollBase.ENROLL_REQUEST;
@@ -42,6 +43,7 @@ import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.BiometricsSplitScreenDialog;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockSettingsHelper;
@@ -101,8 +103,25 @@ public class FaceSettings extends DashboardFragment {
mEnrollButton.setVisible(true);
};
private final FaceSettingsEnrollButtonPreferenceController.Listener mEnrollListener = intent ->
startActivityForResult(intent, ENROLL_REQUEST);
private final FaceSettingsEnrollButtonPreferenceController.Listener mEnrollListener =
new FaceSettingsEnrollButtonPreferenceController.Listener() {
@Override
public boolean checkInMultiWindowMode() {
if (!getActivity().isInMultiWindowMode()) {
return false;
}
// If it's in split mode, show the error dialog.
BiometricsSplitScreenDialog.newInstance(TYPE_FACE).show(
getActivity().getSupportFragmentManager(),
BiometricsSplitScreenDialog.class.getName());
return true;
}
@Override
public void onStartEnrolling(Intent intent) {
FaceSettings.this.startActivityForResult(intent, ENROLL_REQUEST);
}
};
/**
* @param context
@@ -332,7 +351,6 @@ public class FaceSettings extends DashboardFragment {
} else if (controller instanceof FaceSettingsEnrollButtonPreferenceController) {
mEnrollController = (FaceSettingsEnrollButtonPreferenceController) controller;
mEnrollController.setListener(mEnrollListener);
mEnrollController.setActivity((SettingsActivity) getActivity());
}
}

View File

@@ -26,7 +26,6 @@ import android.widget.Button;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.widget.LayoutPreference;
@@ -47,7 +46,6 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference
private int mUserId;
private byte[] mToken;
private SettingsActivity mActivity;
private Button mButton;
private boolean mIsClicked;
private Listener mListener;
@@ -77,6 +75,11 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference
@Override
public void onClick(View v) {
// If it's in multi window mode, do not start the introduction intent.
if (mListener != null && mListener.checkInMultiWindowMode()) {
return;
}
mIsClicked = true;
final Intent intent = new Intent();
intent.setClassName(SETTINGS_PACKAGE_NAME, FaceEnrollIntroduction.class.getName());
@@ -109,10 +112,6 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference
return wasClicked;
}
public void setActivity(SettingsActivity activity) {
mActivity = activity;
}
public void setListener(Listener listener) {
mListener = listener;
}
@@ -121,6 +120,12 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference
* Interface for registering callbacks related to the face enroll preference button.
*/
public interface Listener {
/**
* Called to check whether it's in multi window mode
* @return Whether it's in multi window mode.
*/
boolean checkInMultiWindowMode();
/**
* Called when the user has indicated an intent to begin enrolling a new face.
* @param intent The Intent that should be used to launch face enrollment.

View File

@@ -20,6 +20,7 @@ package com.android.settings.biometrics.fingerprint;
import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_UNLOCK_DISABLED_EXPLANATION;
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE;
import static android.app.admin.DevicePolicyResources.UNDEFINED;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY;
@@ -67,6 +68,7 @@ import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.BiometricsSplitScreenDialog;
import com.android.settings.biometrics.GatekeeperPasswordProvider;
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
import com.android.settings.biometrics2.ui.view.FingerprintEnrollmentActivity;
@@ -695,12 +697,12 @@ public class FingerprintSettings extends SubSettings {
public boolean onPreferenceTreeClick(Preference pref) {
final String key = pref.getKey();
if (KEY_FINGERPRINT_ADD.equals(key)) {
// If it's udfps in split mode, show the error dialog and don't need to show adding
// If it's in split mode, show the error dialog and don't need to show adding
// fingerprint intent.
if (shouldSkipForUdfpsInMultiWindowMode()) {
new FingerprintSplitScreenDialog().show(
if (getActivity().isInMultiWindowMode()) {
BiometricsSplitScreenDialog.newInstance(TYPE_FINGERPRINT).show(
getActivity().getSupportFragmentManager(),
FingerprintSplitScreenDialog.class.getName());
BiometricsSplitScreenDialog.class.getName());
return true;
}
@@ -1007,14 +1009,6 @@ public class FingerprintSettings extends SubSettings {
updatePreferences();
}
/**
* Returns whether the click should be skipped.
* True if it's udfps and it's in split mode.
*/
private boolean shouldSkipForUdfpsInMultiWindowMode() {
return getActivity().isInMultiWindowMode() && isUdfps();
}
private final Runnable mFingerprintLockoutReset = new Runnable() {
@Override
public void run() {
@@ -1264,29 +1258,6 @@ public class FingerprintSettings extends SubSettings {
return alertDialog;
}
}
/**
* This alert dialog shows when fingerprint is being added in multi window mode.
*/
public static class FingerprintSplitScreenDialog extends InstrumentedDialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(
R.string.biometric_settings_add_fingerprint_in_split_mode_title)
.setMessage(
R.string.biometric_settings_add_fingerprint_in_split_mode_message)
.setPositiveButton(
R.string.biometric_settings_add_fingerprint_in_split_mode_ok,
(DialogInterface.OnClickListener) (dialog, which) -> dialog.dismiss());
return builder.create();
}
@Override
public int getMetricsCategory() {
return SettingsEnums.DIALOG_ADD_FINGERPRINT_ERROR_IN_SPLIT_MODE;
}
}
}
public static class FingerprintPreference extends TwoTargetPreference {