diff --git a/res/values/strings.xml b/res/values/strings.xml index 5a5bc27b3ec..f4e90a0b12f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -871,12 +871,16 @@ Using face or fingerprint OK + + Can\u2019t set up Face Unlock + + Exit split screen to set up Face Unlock Can\u2019t set up fingerprint Exit split screen to set up Fingerprint Unlock - - OK + + OK Skip screen lock? diff --git a/src/com/android/settings/biometrics/BiometricsSplitScreenDialog.java b/src/com/android/settings/biometrics/BiometricsSplitScreenDialog.java new file mode 100644 index 00000000000..c1ecee8a852 --- /dev/null +++ b/src/com/android/settings/biometrics/BiometricsSplitScreenDialog.java @@ -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; + } + } +} diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java index a57426f631d..7b02b9dabe2 100644 --- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java +++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java @@ -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; - } } diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index bc9e8e2cd60..cf2c09bc930 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -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()); } } diff --git a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java index b3e0e1ea88d..a35e865a9ca 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java @@ -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. diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 0e2c3d6fc62..88a05c3d037 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -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 { diff --git a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java index 8da4a419842..d879401be30 100644 --- a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java @@ -16,11 +16,9 @@ package com.android.settings.biometrics.combination; -import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; import static com.android.settings.biometrics.combination.BiometricsSettingsBase.CONFIRM_REQUEST; -import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment; import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED; import static com.google.common.truth.Truth.assertThat; @@ -35,7 +33,6 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; @@ -44,7 +41,6 @@ import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; -import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Bundle; import android.view.LayoutInflater; @@ -62,6 +58,7 @@ import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; +import com.android.settings.biometrics.BiometricsSplitScreenDialog; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowFragment; @@ -322,46 +319,24 @@ public class CombinedBiometricProfileSettingsTest { } @Test - public void testClickFingerprintUnlockInMultiWindow_onUdfpsDevice_withoutEnrolledFp_showsDialog() { - clickFingerprintUnlockInSplitScreenMode(TYPE_UDFPS_OPTICAL, /*hasEnrolledFingerprint*/ - false); - - verify(mBiometricSettingsAppPreferenceController, times(0)).handlePreferenceTreeClick( - any()); - verify(mFragmentTransaction).add(any(), - eq(FingerprintSettingsFragment.FingerprintSplitScreenDialog.class.getName())); + public void testClickFingerprintUnlock_inMultiWindow_withoutEnrolledFp_showsDialog() { + testClickFingerprintUnlock(true /* isInMultiWindow */, false /* hasEnrolledFingerprint */); + verifyShowsDialogAfterClickingUnlock(); } @Test - public void testClickFingerprintUnlockInMultiWindow_onUdfpsDevice_withEnrolledFp_noDialog() { - clickFingerprintUnlockInSplitScreenMode(TYPE_UDFPS_OPTICAL, /*hasEnrolledFingerprint*/true); - - verify(mBiometricSettingsAppPreferenceController).handlePreferenceTreeClick( - mPreferenceCaptor.capture()); - List capturedPreferences = mPreferenceCaptor.getAllValues(); - assertThat(capturedPreferences.size()).isEqualTo(1); - assertThat(capturedPreferences.get(0).getKey()).isEqualTo( - mFragment.getFingerprintPreferenceKey()); - verify(mFragmentTransaction, never()).add(any(), - eq(FingerprintSettingsFragment.FingerprintSplitScreenDialog.class.getName())); + public void testClickFingerprintUnlock_inMultiWindow_withEnrolledFp_noDialog() { + testClickFingerprintUnlock(true /* isInMultiWindow */, true /* hasEnrolledFingerprint */); + verifyNoDialogAfterClickingUnlock(mFragment.getFingerprintPreferenceKey()); } @Test - public void testClickFingerprintUnlockInMultiWindow_onSfpsDevice_withoutEnrolledFp_noDialog() { - clickFingerprintUnlockInSplitScreenMode(TYPE_POWER_BUTTON, /*hasEnrolledFingerprint*/false); - - verify(mBiometricSettingsAppPreferenceController).handlePreferenceTreeClick( - mPreferenceCaptor.capture()); - List capturedPreferences = mPreferenceCaptor.getAllValues(); - assertThat(capturedPreferences.size()).isEqualTo(1); - assertThat(capturedPreferences.get(0).getKey()).isEqualTo( - mFragment.getFingerprintPreferenceKey()); - verify(mFragmentTransaction, never()).add(any(), - eq(FingerprintSettingsFragment.FingerprintSplitScreenDialog.class.getName())); + public void testClickFingerprintUnlock_inFullScreen_withoutEnrolledFp_noDialog() { + testClickFingerprintUnlock(false /* isInMultiWindow */, false /* hasEnrolledFingerprint */); + verifyNoDialogAfterClickingUnlock(mFragment.getFingerprintPreferenceKey()); } - private void clickFingerprintUnlockInSplitScreenMode( - @FingerprintSensorProperties.SensorType int sensorType, + private void testClickFingerprintUnlock(boolean isInMultiWindow, boolean hasEnrolledFingerprint) { final ArrayList props = new ArrayList<>(); props.add(new FingerprintSensorPropertiesInternal( @@ -369,7 +344,7 @@ public class CombinedBiometricProfileSettingsTest { SensorProperties.STRENGTH_STRONG, 1 /* maxEnrollmentsPerUser */, new ArrayList(), - sensorType, + TYPE_UDFPS_OPTICAL, true /* resetLockoutRequiresHardwareAuthToken */)); doReturn(props).when(mFingerprintManager).getSensorPropertiesInternal(); @@ -384,7 +359,7 @@ public class CombinedBiometricProfileSettingsTest { FragmentManager fragmentManager = mock(FragmentManager.class); doReturn(fragmentManager).when(mActivity).getSupportFragmentManager(); doReturn(mFragmentTransaction).when(fragmentManager).beginTransaction(); - doReturn(true).when(mActivity).isInMultiWindowMode(); + doReturn(isInMultiWindow).when(mActivity).isInMultiWindowMode(); doReturn(hasEnrolledFingerprint).when(mFingerprintManager).hasEnrolledFingerprints( anyInt()); @@ -399,6 +374,69 @@ public class CombinedBiometricProfileSettingsTest { preference.setKey(mFragment.getFingerprintPreferenceKey()); mFragment.onPreferenceTreeClick(preference); } + + @Test + public void testClickFaceUnlock_inMultiWindow_withoutEnrolledFp_showsDialog() { + testClickFaceUnlock(true /* isInMultiWindow */, false /*hasEnrolledFace*/); + verifyShowsDialogAfterClickingUnlock(); + } + + @Test + public void testClickFaceUnlock_inMultiWindow_withEnrolledFp_noDialog() { + testClickFaceUnlock(true /* isInMultiWindow */, true /* hasEnrolledFace */); + verifyNoDialogAfterClickingUnlock(mFragment.getFacePreferenceKey()); + } + + @Test + public void testClickFaceUnlock_inFullScreen_withoutEnrolledFp_noDialog() { + testClickFaceUnlock(false /* isInMultiWindow */ , false /* hasEnrolledFace */); + verifyNoDialogAfterClickingUnlock(mFragment.getFacePreferenceKey()); + } + + private void testClickFaceUnlock(boolean isInMultiWindow, boolean hasEnrolledFace) { + doAnswer(invocation -> { + final FaceManager.GenerateChallengeCallback callback = + invocation.getArgument(1); + callback.onGenerateChallengeResult(0, 0, 1L); + return null; + }).when(mFaceManager).generateChallenge(anyInt(), any()); + doReturn(new byte[] { 1 }).when(mFragment).requestGatekeeperHat(any(), anyLong(), anyInt(), + anyLong()); + FragmentManager fragmentManager = mock(FragmentManager.class); + doReturn(fragmentManager).when(mActivity).getSupportFragmentManager(); + doReturn(mFragmentTransaction).when(fragmentManager).beginTransaction(); + doReturn(isInMultiWindow).when(mActivity).isInMultiWindowMode(); + doReturn(hasEnrolledFace).when(mFaceManager).hasEnrolledTemplates( + anyInt()); + + // Start fragment + mFragment.onAttach(mContext); + mFragment.onCreate(null); + mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY); + mFragment.onResume(); + + // User clicks on "Face Unlock" + final Preference preference = new Preference(mContext); + preference.setKey(mFragment.getFacePreferenceKey()); + mFragment.onPreferenceTreeClick(preference); + } + + private void verifyNoDialogAfterClickingUnlock(String preferenceKey) { + verify(mBiometricSettingsAppPreferenceController).handlePreferenceTreeClick( + mPreferenceCaptor.capture()); + List capturedPreferences = mPreferenceCaptor.getAllValues(); + assertThat(capturedPreferences).hasSize(1); + assertThat(capturedPreferences.get(0).getKey()).isEqualTo(preferenceKey); + verify(mFragmentTransaction, never()).add(any(), + eq(BiometricsSplitScreenDialog.class.getName())); + } + + private void verifyShowsDialogAfterClickingUnlock() { + verify(mBiometricSettingsAppPreferenceController, never()).handlePreferenceTreeClick(any()); + verify(mFragmentTransaction).add(any(), + eq(BiometricsSplitScreenDialog.class.getName())); + } + /** * a test fragment that initializes PreferenceScreen for testing. */ diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java index 19eb42c419c..2bc81e60a06 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java @@ -16,7 +16,6 @@ package com.android.settings.biometrics.fingerprint; -import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment; @@ -40,7 +39,6 @@ import android.content.Intent; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.fingerprint.FingerprintManager; -import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Bundle; import android.view.LayoutInflater; @@ -52,6 +50,7 @@ import androidx.fragment.app.FragmentTransaction; import androidx.preference.Preference; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.biometrics.BiometricsSplitScreenDialog; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowFragment; @@ -111,6 +110,8 @@ public class FingerprintSettingsFragmentTest { doReturn(fragmentManager).when(mActivity).getSupportFragmentManager(); doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt()); + + setSensor(); } @After @@ -119,9 +120,7 @@ public class FingerprintSettingsFragmentTest { } @Test - public void testAddFingerprint_onUdfpsDevice_inFullScreen_noDialog() { - setSensorType(TYPE_UDFPS_OPTICAL); - + public void testAddFingerprint_inFullScreen_noDialog() { // Start fragment mFragment.onAttach(mContext); mFragment.onCreate(null); @@ -135,14 +134,12 @@ public class FingerprintSettingsFragmentTest { verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST)); verify(mFragmentTransaction, never()).add(any(), - eq(FingerprintSettingsFragment.FingerprintSplitScreenDialog.class.getName())); + eq(BiometricsSplitScreenDialog.class.getName())); } @Test - public void testAddFingerprint_onUdfpsDevice_inMultiWindow_showsDialog() { - setSensorType(TYPE_UDFPS_OPTICAL); - + public void testAddFingerprint_inMultiWindow_showsDialog() { // Start fragment mFragment.onAttach(mContext); mFragment.onCreate(null); @@ -157,40 +154,17 @@ public class FingerprintSettingsFragmentTest { mFragment.onPreferenceTreeClick(preference); verify(mFragment, times(0)).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST)); - verify(mFragmentTransaction).add(any(), - eq(FingerprintSettingsFragment.FingerprintSplitScreenDialog.class.getName())); + verify(mFragmentTransaction).add(any(), eq(BiometricsSplitScreenDialog.class.getName())); } - @Test - public void testAddFingerprint_onSfpsDevice_inMultiWindow_noDialog() { - setSensorType(TYPE_POWER_BUTTON); - - // Start fragment - mFragment.onAttach(mContext); - mFragment.onCreate(null); - mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY); - mFragment.onResume(); - - doReturn(true).when(mActivity).isInMultiWindowMode(); - - // Click "Add Fingerprint" - final Preference preference = new Preference(mContext); - preference.setKey(KEY_FINGERPRINT_ADD); - mFragment.onPreferenceTreeClick(preference); - - verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST)); - verify(mFragmentTransaction, never()).add(any(), - eq(FingerprintSettingsFragment.FingerprintSplitScreenDialog.class.getName())); - } - - private void setSensorType(@FingerprintSensorProperties.SensorType int sensorType) { + private void setSensor() { final ArrayList props = new ArrayList<>(); props.add(new FingerprintSensorPropertiesInternal( 0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 1 /* maxEnrollmentsPerUser */, new ArrayList(), - sensorType, + TYPE_UDFPS_OPTICAL, true /* resetLockoutRequiresHardwareAuthToken */)); doReturn(props).when(mFingerprintManager).getSensorPropertiesInternal(); } diff --git a/tests/unit/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceControllerTest.java b/tests/unit/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceControllerTest.java new file mode 100644 index 00000000000..64745614cee --- /dev/null +++ b/tests/unit/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceControllerTest.java @@ -0,0 +1,80 @@ +/* + * 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.face; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.widget.Button; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +@RunWith(AndroidJUnit4.class) +public class FaceSettingsEnrollButtonPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Mock + private Context mContext; + @Mock + private Button mButton; + @Mock + private FaceSettingsEnrollButtonPreferenceController.Listener mListener; + + private FaceSettingsEnrollButtonPreferenceController mController; + + @Before + public void setUp() { + mController = new FaceSettingsEnrollButtonPreferenceController(mContext); + mController.setListener(mListener); + } + + @Test + public void isSliceable_returnFalse() { + assertThat(mController.isSliceable()).isFalse(); + } + + @Test + public void testOnClick_inFullScreen() { + when(mListener.checkInMultiWindowMode()).thenReturn(false); + mController.onClick(mButton); + + assertThat(mController.isClicked()).isTrue(); + verify(mListener).onStartEnrolling(any()); + } + + @Test + public void testOnClick_inMultiWindow() { + when(mListener.checkInMultiWindowMode()).thenReturn(true); + mController.onClick(mButton); + + assertThat(mController.isClicked()).isFalse(); + verify(mListener, never()).onStartEnrolling(any()); + } +}