[BiometricsV2] Refine fingerprint ui and flow

1. Fix "No thanks" become 2 lines, and fix the status when new
   fingerprint enrolled.
2. Fix Finish page shows again after pressing back from a new Finish
   page
3. Fix FindSensor page shows again after max number of fingerprint
   has reached.
4. Add missing tests, and remove some bypass-only tests

Bug: 279134177
Bug: 279380583
Bug: 279386539
Bug: 279394069
Test: atest FingerprintEnrollIntroViewModelTest
    FingerprintEnrollFindSensorViewModelTest
    FingerprintEnrollEnrollingViewModelTest
    FingerprintEnrollmentViewModelTest FingerprintEnrollmentActivityTest
Test: manually test 1, 2, and 3
Change-Id: I3797ceed8e7d6c10a4b4711f8bff8d7f222f0923
This commit is contained in:
Milton Wu
2023-04-26 18:46:11 +08:00
parent cb00c675e5
commit 8b0fc14f94
9 changed files with 265 additions and 104 deletions

View File

@@ -78,4 +78,11 @@ public final class FingerprintEnrollIntroStatus {
public boolean hasScrollToBottom() { public boolean hasScrollToBottom() {
return mHasScrollToBottom; return mHasScrollToBottom;
} }
@Override
public String toString() {
return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode())
+ "{scrollToBottom:" + mHasScrollToBottom
+ ", enrollableStatus:" + mEnrollableStatus + "}";
}
} }

View File

@@ -63,6 +63,7 @@ import com.google.android.setupdesign.util.DynamicColorPalette;
public class FingerprintEnrollIntroFragment extends Fragment { public class FingerprintEnrollIntroFragment extends Fragment {
private static final String TAG = "FingerprintEnrollIntroFragment"; private static final String TAG = "FingerprintEnrollIntroFragment";
private static final boolean DEBUG = false;
private FingerprintEnrollIntroViewModel mViewModel = null; private FingerprintEnrollIntroViewModel mViewModel = null;
@@ -128,17 +129,6 @@ public class FingerprintEnrollIntroFragment extends Fragment {
footerLink.setText(Html.fromHtml(footerLinkStr)); footerLink.setText(Html.fromHtml(footerLinkStr));
// footer buttons // footer buttons
mPrimaryFooterButton = new FooterButton.Builder(context)
.setText(R.string.security_settings_fingerprint_enroll_introduction_agree)
.setButtonType(FooterButton.ButtonType.OPT_IN)
.setTheme(R.style.SudGlifButton_Primary)
.build();
mSecondaryFooterButton = new FooterButton.Builder(context)
.setButtonType(FooterButton.ButtonType.NEXT)
.setTheme(R.style.SudGlifButton_Primary)
.build();
getFooterBarMixin().setPrimaryButton(mPrimaryFooterButton);
getFooterBarMixin().setSecondaryButton(mSecondaryFooterButton, true /* usePrimaryStyle */);
return mView; return mView;
} }
@@ -149,9 +139,6 @@ public class FingerprintEnrollIntroFragment extends Fragment {
final Context context = view.getContext(); final Context context = view.getContext();
mPrimaryFooterButton.setOnClickListener(mOnNextClickListener);
mSecondaryFooterButton.setOnClickListener(mOnSkipOrCancelClickListener);
if (mViewModel.canAssumeUdfps()) { if (mViewModel.canAssumeUdfps()) {
mFooterMessage6.setVisibility(View.VISIBLE); mFooterMessage6.setVisibility(View.VISIBLE);
mIconShield.setVisibility(View.VISIBLE); mIconShield.setVisibility(View.VISIBLE);
@@ -159,10 +146,6 @@ public class FingerprintEnrollIntroFragment extends Fragment {
mFooterMessage6.setVisibility(View.GONE); mFooterMessage6.setVisibility(View.GONE);
mIconShield.setVisibility(View.GONE); mIconShield.setVisibility(View.GONE);
} }
mSecondaryFooterButton.setText(context,
mViewModel.getRequest().isAfterSuwOrSuwSuggestedAction()
? R.string.security_settings_fingerprint_enroll_introduction_cancel
: R.string.security_settings_fingerprint_enroll_introduction_no_thanks);
final GlifLayoutHelper glifLayoutHelper = new GlifLayoutHelper(getActivity(), getLayout()); final GlifLayoutHelper glifLayoutHelper = new GlifLayoutHelper(getActivity(), getLayout());
if (mViewModel.isBiometricUnlockDisabledByAdmin() if (mViewModel.isBiometricUnlockDisabledByAdmin()
@@ -178,16 +161,64 @@ public class FingerprintEnrollIntroFragment extends Fragment {
R.string.security_settings_fingerprint_enroll_introduction_v3_message, R.string.security_settings_fingerprint_enroll_introduction_v3_message,
DeviceHelper.getDeviceName(context))); DeviceHelper.getDeviceName(context)));
} }
}
@Override
public void onStart() {
final Context context = requireContext();
final FooterBarMixin footerBarMixin = getFooterBarMixin();
initPrimaryFooterButton(context, footerBarMixin);
initSecondaryFooterButton(context, footerBarMixin);
observePageStatusLiveDataIfNeed(); observePageStatusLiveDataIfNeed();
super.onStart();
}
private void initPrimaryFooterButton(@NonNull Context context,
@NonNull FooterBarMixin footerBarMixin) {
if (footerBarMixin.getPrimaryButton() != null) {
return;
}
mPrimaryFooterButton = new FooterButton.Builder(context)
.setText(R.string.security_settings_fingerprint_enroll_introduction_agree)
.setButtonType(FooterButton.ButtonType.OPT_IN)
.setTheme(R.style.SudGlifButton_Primary)
.build();
mPrimaryFooterButton.setOnClickListener(mOnNextClickListener);
footerBarMixin.setPrimaryButton(mPrimaryFooterButton);
}
private void initSecondaryFooterButton(@NonNull Context context,
@NonNull FooterBarMixin footerBarMixin) {
if (footerBarMixin.getSecondaryButton() != null) {
return;
}
mSecondaryFooterButton = new FooterButton.Builder(context)
.setText(mViewModel.getRequest().isAfterSuwOrSuwSuggestedAction()
? R.string.security_settings_fingerprint_enroll_introduction_cancel
: R.string.security_settings_fingerprint_enroll_introduction_no_thanks)
.setButtonType(FooterButton.ButtonType.NEXT)
.setTheme(R.style.SudGlifButton_Primary)
.build();
mSecondaryFooterButton.setOnClickListener(mOnSkipOrCancelClickListener);
footerBarMixin.setSecondaryButton(mSecondaryFooterButton, true /* usePrimaryStyle */);
} }
private void observePageStatusLiveDataIfNeed() { private void observePageStatusLiveDataIfNeed() {
final LiveData<FingerprintEnrollIntroStatus> statusLiveData = final LiveData<FingerprintEnrollIntroStatus> statusLiveData =
mViewModel.getPageStatusLiveData(); mViewModel.getPageStatusLiveData();
final FingerprintEnrollIntroStatus status = statusLiveData.getValue(); final FingerprintEnrollIntroStatus status = statusLiveData.getValue();
if (status != null && status.hasScrollToBottom()) { if (DEBUG) {
// Do not requireScrollWithButton() again when "I agree" or "Done" button is visible, Log.e(TAG, "observePageStatusLiveDataIfNeed() requireScrollWithButton, status:"
// because if we requireScrollWithButton() again, it will become "More" after scroll-up. + status);
}
if (status != null && (status.hasScrollToBottom()
|| status.getEnrollableStatus() == FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)) {
// Update once and do not requireScrollWithButton() again when page has scrolled to
// bottom or User has enrolled at least a fingerprint, because if we
// requireScrollWithButton() again, primary button will become "More" after scrolling.
updateFooterButtons(status);
return; return;
} }
@@ -196,10 +227,6 @@ public class FingerprintEnrollIntroFragment extends Fragment {
requireScrollMixin.requireScrollWithButton(getActivity(), mPrimaryFooterButton, requireScrollMixin.requireScrollWithButton(getActivity(), mPrimaryFooterButton,
getMoreButtonTextRes(), mOnNextClickListener); getMoreButtonTextRes(), mOnNextClickListener);
// Always set true to setHasScrolledToBottom() before registering listener through
// setOnRequireScrollStateChangedListener(), because listener will not be called if first
// scrollNeeded is true
mViewModel.setHasScrolledToBottom(true);
requireScrollMixin.setOnRequireScrollStateChangedListener( requireScrollMixin.setOnRequireScrollStateChangedListener(
scrollNeeded -> mViewModel.setHasScrolledToBottom(!scrollNeeded)); scrollNeeded -> mViewModel.setHasScrolledToBottom(!scrollNeeded));
statusLiveData.observe(this, this::updateFooterButtons); statusLiveData.observe(this, this::updateFooterButtons);
@@ -249,15 +276,19 @@ public class FingerprintEnrollIntroFragment extends Fragment {
} }
void updateFooterButtons(@NonNull FingerprintEnrollIntroStatus status) { void updateFooterButtons(@NonNull FingerprintEnrollIntroStatus status) {
@StringRes final int scrollToBottomPrimaryResId = if (DEBUG) {
status.getEnrollableStatus() == FINGERPRINT_ENROLLABLE_OK Log.d(TAG, "updateFooterButtons(" + status + ")");
? R.string.security_settings_fingerprint_enroll_introduction_agree }
: R.string.done;
mPrimaryFooterButton.setText(getContext(), mPrimaryFooterButton.setText(getContext(),
status.hasScrollToBottom() ? scrollToBottomPrimaryResId : getMoreButtonTextRes()); status.getEnrollableStatus() == FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
mSecondaryFooterButton.setVisibility( ? R.string.done
status.hasScrollToBottom() ? View.VISIBLE : View.INVISIBLE); : status.hasScrollToBottom()
? R.string.security_settings_fingerprint_enroll_introduction_agree
: getMoreButtonTextRes());
mSecondaryFooterButton.setVisibility(status.hasScrollToBottom()
&& status.getEnrollableStatus() != FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
? View.VISIBLE
: View.INVISIBLE);
final TextView errorTextView = mView.findViewById(R.id.error_text); final TextView errorTextView = mView.findViewById(R.id.error_text);
switch (status.getEnrollableStatus()) { switch (status.getEnrollableStatus()) {

View File

@@ -17,6 +17,7 @@
package com.android.settings.biometrics2.ui.view; package com.android.settings.biometrics2.ui.view;
import static androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import static androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
import static androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY; import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR_KEY; import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR_KEY;
@@ -100,12 +101,8 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
private static final String TAG = "FingerprintEnrollmentActivity"; private static final String TAG = "FingerprintEnrollmentActivity";
private static final String INTRO_TAG = "intro"; private static final String INTRO_TAG = "intro";
private static final String FIND_UDFPS_TAG = "find-udfps"; private static final String FIND_SENSOR_TAG = "find-sensor";
private static final String FIND_SFPS_TAG = "find-sfps"; private static final String ENROLLING_TAG = "enrolling";
private static final String FIND_RFPS_TAG = "find-rfps";
private static final String ENROLLING_UDFPS_TAG = "enrolling-udfps";
private static final String ENROLLING_SFPS_TAG = "enrolling-sfps";
private static final String ENROLLING_RFPS_TAG = "enrolling-rfps";
private static final String FINISH_TAG = "finish"; private static final String FINISH_TAG = "finish";
private static final String SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog"; private static final String SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog";
private static final String ENROLLING_ERROR_DIALOG_TAG = "enrolling-error-dialog"; private static final String ENROLLING_ERROR_DIALOG_TAG = "enrolling-error-dialog";
@@ -213,12 +210,10 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
final String tag = fragment.getTag(); final String tag = fragment.getTag();
if (INTRO_TAG.equals(tag)) { if (INTRO_TAG.equals(tag)) {
attachIntroViewModel(); attachIntroViewModel();
} else if (FIND_UDFPS_TAG.equals(tag) || FIND_SFPS_TAG.equals(tag) } else if (FIND_SENSOR_TAG.equals(tag)) {
|| FIND_RFPS_TAG.equals(tag)) {
attachFindSensorViewModel(); attachFindSensorViewModel();
attachIntroViewModel(); attachIntroViewModel();
} else if (ENROLLING_UDFPS_TAG.equals(tag) || ENROLLING_SFPS_TAG.equals(tag) } else if (ENROLLING_TAG.equals(tag)) {
|| ENROLLING_RFPS_TAG.equals(tag)) {
attachEnrollingViewModel(); attachEnrollingViewModel();
attachFindSensorViewModel(); attachFindSensorViewModel();
attachIntroViewModel(); attachIntroViewModel();
@@ -289,19 +284,15 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
attachFindSensorViewModel(); attachFindSensorViewModel();
final String tag;
final Class<? extends Fragment> fragmentClass; final Class<? extends Fragment> fragmentClass;
if (mViewModel.canAssumeUdfps()) { if (mViewModel.canAssumeUdfps()) {
tag = FIND_UDFPS_TAG;
fragmentClass = FingerprintEnrollFindUdfpsFragment.class; fragmentClass = FingerprintEnrollFindUdfpsFragment.class;
} else if (mViewModel.canAssumeSfps()) { } else if (mViewModel.canAssumeSfps()) {
tag = FIND_SFPS_TAG;
fragmentClass = FingerprintEnrollFindSfpsFragment.class; fragmentClass = FingerprintEnrollFindSfpsFragment.class;
} else { } else {
tag = FIND_RFPS_TAG;
fragmentClass = FingerprintEnrollFindRfpsFragment.class; fragmentClass = FingerprintEnrollFindRfpsFragment.class;
} }
startFragment(fragmentClass, tag); startFragment(fragmentClass, FIND_SENSOR_TAG);
} }
private void attachFindSensorViewModel() { private void attachFindSensorViewModel() {
@@ -325,19 +316,15 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
attachEnrollingViewModel(); attachEnrollingViewModel();
final String tag;
final Class<? extends Fragment> fragmentClass; final Class<? extends Fragment> fragmentClass;
if (mViewModel.canAssumeUdfps()) { if (mViewModel.canAssumeUdfps()) {
tag = ENROLLING_UDFPS_TAG;
fragmentClass = FingerprintEnrollEnrollingUdfpsFragment.class; fragmentClass = FingerprintEnrollEnrollingUdfpsFragment.class;
} else if (mViewModel.canAssumeSfps()) { } else if (mViewModel.canAssumeSfps()) {
tag = ENROLLING_SFPS_TAG;
fragmentClass = FingerprintEnrollEnrollingSfpsFragment.class; fragmentClass = FingerprintEnrollEnrollingSfpsFragment.class;
} else { } else {
tag = ENROLLING_RFPS_TAG;
fragmentClass = FingerprintEnrollEnrollingRfpsFragment.class; fragmentClass = FingerprintEnrollEnrollingRfpsFragment.class;
} }
startFragment(fragmentClass, tag); startFragment(fragmentClass, ENROLLING_TAG);
} }
private void attachEnrollingViewModel() { private void attachEnrollingViewModel() {
@@ -354,9 +341,8 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
mViewModel.setIsNewFingerprintAdded(); mViewModel.setIsNewFingerprintAdded();
attachFinishViewModel(); attachFinishViewModel();
getSupportFragmentManager().popBackStack(); if (mViewModel.getRequest().isSkipFindSensor()) {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) { // Set page to Finish
// Replace enrolling page
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true) .setReorderingAllowed(true)
.setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color, .setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color,
@@ -367,8 +353,21 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
null, FINISH_TAG) null, FINISH_TAG)
.commit(); .commit();
} else { } else {
// Remove Enrolling page from backstack, and add Finish page. Latest backstack will // Remove Enrolling page
// be changed from Intro->FindSensor->Enrolling to Intro->FindSensor->Finish getSupportFragmentManager().popBackStack();
// Remove old Finish page if any
if (getSupportFragmentManager().findFragmentByTag(FINISH_TAG) != null) {
getSupportFragmentManager().popBackStack(FINISH_TAG, POP_BACK_STACK_INCLUSIVE);
}
// Remove FindSensor page if maxEnrolled
if (mViewModel.isMaxEnrolledReached(mAutoCredentialViewModel.getUserId())
&& getSupportFragmentManager().findFragmentByTag(FIND_SENSOR_TAG) != null) {
getSupportFragmentManager().popBackStack(FIND_SENSOR_TAG, POP_BACK_STACK_INCLUSIVE);
}
// Add Finish page
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true) .setReorderingAllowed(true)
.setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color, .setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color,

View File

@@ -107,8 +107,6 @@ public class FingerprintEnrollIntroViewModel extends AndroidViewModel {
enrollableValue != null ? enrollableValue : ENROLLABLE_STATUS_DEFAULT); enrollableValue != null ? enrollableValue : ENROLLABLE_STATUS_DEFAULT);
mPageStatusLiveData.setValue(status); mPageStatusLiveData.setValue(status);
}); });
updateEnrollableStatus();
} }
/** /**
@@ -133,6 +131,7 @@ public class FingerprintEnrollIntroViewModel extends AndroidViewModel {
* Get enrollable status and hasScrollToBottom live data * Get enrollable status and hasScrollToBottom live data
*/ */
public LiveData<FingerprintEnrollIntroStatus> getPageStatusLiveData() { public LiveData<FingerprintEnrollIntroStatus> getPageStatusLiveData() {
updateEnrollableStatus();
return mPageStatusLiveData; return mPageStatusLiveData;
} }

View File

@@ -87,7 +87,6 @@ public class FingerprintEnrollmentViewModel extends AndroidViewModel {
@NonNull @NonNull
public ActivityResult getOverrideActivityResult(@NonNull ActivityResult result, public ActivityResult getOverrideActivityResult(@NonNull ActivityResult result,
@Nullable Bundle generatingChallengeExtras) { @Nullable Bundle generatingChallengeExtras) {
// TODO write tests
final int newResultCode = mIsNewFingerprintAdded final int newResultCode = mIsNewFingerprintAdded
? BiometricEnrollBase.RESULT_FINISHED ? BiometricEnrollBase.RESULT_FINISHED
: (mRequest.isAfterSuwOrSuwSuggestedAction() : (mRequest.isAfterSuwOrSuwSuggestedAction()
@@ -165,6 +164,14 @@ public class FingerprintEnrollmentViewModel extends AndroidViewModel {
outState.putBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED, mIsNewFingerprintAdded); outState.putBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED, mIsNewFingerprintAdded);
} }
/**
* Gets the result about fingerprint enrollable
*/
public boolean isMaxEnrolledReached(int userId) {
return mFingerprintRepository.getMaxFingerprints()
<= mFingerprintRepository.getNumOfEnrolledFingerprintsSize(userId);
}
/** /**
* The first sensor type is UDFPS sensor or not * The first sensor type is UDFPS sensor or not
*/ */

View File

@@ -16,9 +16,7 @@
package com.android.settings.biometrics2.ui.viewmodel; package com.android.settings.biometrics2.ui.viewmodel;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData; import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG; import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
@@ -151,26 +149,6 @@ public class FingerprintEnrollEnrollingViewModelTest {
FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP); FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP);
} }
@Test
public void testCanAssumeUdfps_forUdfpsUltrasonicSensor() {
mViewModel = new FingerprintEnrollEnrollingViewModel(
mApplication,
TEST_USER_ID,
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_ULTRASONIC, 5)
);
assertThat(mViewModel.canAssumeUdfps()).isEqualTo(true);
}
@Test
public void testCanAssumeUdfps_forRearSensor() {
mViewModel = new FingerprintEnrollEnrollingViewModel(
mApplication,
TEST_USER_ID,
newFingerprintRepository(mFingerprintManager, TYPE_REAR, 5)
);
assertThat(mViewModel.canAssumeUdfps()).isEqualTo(false);
}
@Test @Test
public void testGetFirstFingerprintSensorPropertiesInternal() { public void testGetFirstFingerprintSensorPropertiesInternal() {
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();

View File

@@ -18,6 +18,7 @@ package com.android.settings.biometrics2.ui.viewmodel;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG; import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP; import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
@@ -70,6 +71,13 @@ public class FingerprintEnrollFindSensorViewModelTest {
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP); FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP);
} }
@Test
public void testClickStartDialogButton() {
mViewModel.onStartButtonClick();
assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START);
}
@Test @Test
public void testClearActionLiveData() { public void testClearActionLiveData() {
assertThat(mViewModel.getActionLiveData().getValue()).isNull(); assertThat(mViewModel.getActionLiveData().getValue()).isNull();

View File

@@ -16,9 +16,7 @@
package com.android.settings.biometrics2.ui.viewmodel; package com.android.settings.biometrics2.ui.viewmodel;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX; import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX;
import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus.FINGERPRINT_ENROLLABLE_OK; import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus.FINGERPRINT_ENROLLABLE_OK;
@@ -100,6 +98,25 @@ public class FingerprintEnrollIntroViewModelTest {
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK); assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
} }
@Test
public void testPageStatusLiveDataRefreshWhenRefetch() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UDFPS_OPTICAL, 1);
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
repository,
newAllFalseRequest(mApplication));
FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.hasScrollToBottom()).isFalse();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
setupFingerprintEnrolledFingerprints(mFingerprintManager, TEST_USER_ID, 1);
// Refetch PageStatusLiveData
status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.hasScrollToBottom()).isFalse();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
}
@Test @Test
public void testClearActionLiveData() { public void testClearActionLiveData() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel( final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
@@ -210,24 +227,6 @@ public class FingerprintEnrollIntroViewModelTest {
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX); assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
} }
@Test
public void testCanAssumeUdfps_forUdfpsUltrasonicSensor() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_ULTRASONIC, 5),
newAllFalseRequest(mApplication));
assertThat(viewModel.canAssumeUdfps()).isEqualTo(true);
}
@Test
public void testCanAssumeUdfps_forRearSensor() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_REAR, 5),
newAllFalseRequest(mApplication));
assertThat(viewModel.canAssumeUdfps()).isEqualTo(false);
}
@Test @Test
public void testIsParentalConsentRequired() { public void testIsParentalConsentRequired() {
// We shall not mock FingerprintRepository, but // We shall not mock FingerprintRepository, but

View File

@@ -16,16 +16,22 @@
package com.android.settings.biometrics2.ui.viewmodel; package com.android.settings.biometrics2.ui.viewmodel;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel.SAVED_STATE_IS_NEW_FINGERPRINT_ADDED; import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel.SAVED_STATE_IS_NEW_FINGERPRINT_ADDED;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel.SAVED_STATE_IS_WAITING_ACTIVITY_RESULT; import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel.SAVED_STATE_IS_WAITING_ACTIVITY_RESULT;
import static com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newAllFalseRequest; import static com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newAllFalseRequest;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.app.Application; import android.app.Application;
import android.content.Intent;
import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle; import android.os.Bundle;
import androidx.activity.result.ActivityResult;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -55,7 +61,8 @@ public class FingerprintEnrollmentViewModelTest {
@Before @Before
public void setUp() { public void setUp() {
mApplication = ApplicationProvider.getApplicationContext(); mApplication = ApplicationProvider.getApplicationContext();
mFingerprintRepository = new FingerprintRepository(mFingerprintManager); mFingerprintRepository = newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL,
5);
mViewModel = new FingerprintEnrollmentViewModel(mApplication, mFingerprintRepository, mViewModel = new FingerprintEnrollmentViewModel(mApplication, mFingerprintRepository,
newAllFalseRequest(mApplication)); newAllFalseRequest(mApplication));
} }
@@ -124,4 +131,130 @@ public class FingerprintEnrollmentViewModelTest {
mViewModel.onSaveInstanceState(bundle); mViewModel.onSaveInstanceState(bundle);
assertThat(bundle.getBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED)).isTrue(); assertThat(bundle.getBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED)).isTrue();
} }
@Test
public void testOverrideActivityResult_shallKeepNullIntent_woChallengeExtra() {
final ActivityResult retResult = mViewModel.getOverrideActivityResult(
new ActivityResult(22, null), null);
assertThat(retResult).isNotNull();
assertThat(retResult.getData()).isNull();
}
@Test
public void testOverrideActivityResult_shallKeepNullIntent_noIntent_woChallengeExtra() {
final Intent intent = new Intent();
final ActivityResult retResult = mViewModel.getOverrideActivityResult(
new ActivityResult(33, intent), null);
assertThat(retResult).isNotNull();
assertThat(retResult.getData()).isEqualTo(intent);
}
@Test
public void testOverrideActivityResult_shallKeepNull_woAdded_woIntent_withChallenge() {
final Bundle extra = new Bundle();
extra.putString("test1", "test123");
final ActivityResult retResult = mViewModel.getOverrideActivityResult(
new ActivityResult(33, null), extra);
assertThat(retResult).isNotNull();
assertThat(retResult.getData()).isNull();
}
@Test
public void testOverrideActivityResult_shallCreateNew_woIntent_withChallenge() {
final String key1 = "test1";
final String key2 = "test2";
final Bundle extra = new Bundle();
extra.putString(key1, "test123");
extra.putInt(key2, 9999);
mViewModel.setIsNewFingerprintAdded();
final ActivityResult retResult = mViewModel.getOverrideActivityResult(
new ActivityResult(33, null), extra);
assertThat(retResult).isNotNull();
final Intent retIntent = retResult.getData();
assertThat(retIntent).isNotNull();
final Bundle retExtra = retIntent.getExtras();
assertThat(retExtra).isNotNull();
assertThat(retExtra.getSize()).isEqualTo(extra.getSize());
assertThat(retExtra.getString(key1)).isEqualTo(extra.getString(key1));
assertThat(retExtra.getInt(key2)).isEqualTo(extra.getInt(key2));
}
@Test
public void testOverrideActivityResult_shallNotMerge_nonAdded_woIntent_withChallenge() {
final Bundle extra = new Bundle();
extra.putString("test2", "test123");
final Intent intent = new Intent();
final String key2 = "test2";
intent.putExtra(key2, 3456L);
final ActivityResult retResult = mViewModel.getOverrideActivityResult(
new ActivityResult(33, intent), extra);
assertThat(retResult).isNotNull();
final Intent retIntent = retResult.getData();
assertThat(retIntent).isNotNull();
final Bundle retExtra = retIntent.getExtras();
assertThat(retExtra).isNotNull();
assertThat(retExtra.getSize()).isEqualTo(intent.getExtras().getSize());
assertThat(retExtra.getString(key2)).isEqualTo(intent.getExtras().getString(key2));
}
@Test
public void testOverrideActivityResult_shallMerge_added_woIntent_withChallenge() {
final String key1 = "test1";
final String key2 = "test2";
final Bundle extra = new Bundle();
extra.putString(key1, "test123");
extra.putInt(key2, 9999);
final Intent intent = new Intent();
final String key3 = "test3";
intent.putExtra(key3, 3456L);
mViewModel.setIsNewFingerprintAdded();
final ActivityResult retResult = mViewModel.getOverrideActivityResult(
new ActivityResult(33, intent), extra);
assertThat(retResult).isNotNull();
final Intent retIntent = retResult.getData();
assertThat(retIntent).isNotNull();
final Bundle retExtra = retIntent.getExtras();
assertThat(retExtra).isNotNull();
assertThat(retExtra.getSize()).isEqualTo(extra.getSize() + intent.getExtras().getSize());
assertThat(retExtra.getString(key1)).isEqualTo(extra.getString(key1));
assertThat(retExtra.getInt(key2)).isEqualTo(extra.getInt(key2));
assertThat(retExtra.getLong(key3)).isEqualTo(intent.getExtras().getLong(key3));
}
@Test
public void testIsMaxEnrolledReached() {
final int uid = 100;
mFingerprintRepository = newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL,
3);
mViewModel = new FingerprintEnrollmentViewModel(mApplication, mFingerprintRepository,
newAllFalseRequest(mApplication));
setupFingerprintEnrolledFingerprints(mFingerprintManager, uid, 0);
assertThat(mViewModel.isMaxEnrolledReached(uid)).isFalse();
setupFingerprintEnrolledFingerprints(mFingerprintManager, uid, 1);
assertThat(mViewModel.isMaxEnrolledReached(uid)).isFalse();
setupFingerprintEnrolledFingerprints(mFingerprintManager, uid, 2);
assertThat(mViewModel.isMaxEnrolledReached(uid)).isFalse();
setupFingerprintEnrolledFingerprints(mFingerprintManager, uid, 3);
assertThat(mViewModel.isMaxEnrolledReached(uid)).isTrue();
setupFingerprintEnrolledFingerprints(mFingerprintManager, uid, 4);
assertThat(mViewModel.isMaxEnrolledReached(uid)).isTrue();
}
} }