Refactor FingerprintEnrollFindSensor

Refactor FingerprintEnrollFindSensor to 3 pages for different sensor
types, and apply MVVM for them.

Bug: 259664912
Bug: 260957195
Bug: 260957816
Test: atest FingerprintRepositoryTest FingerprintEnrollmentActivityTest
      AutoCredentialViewModelTest FingerprintEnrollIntroViewModelTest

Change-Id: Iace790952567cac13e61e5175e90555d4da7dfe2
This commit is contained in:
Milton Wu
2022-11-18 13:33:02 +08:00
parent b8926bd868
commit 3be7385d90
24 changed files with 1706 additions and 180 deletions

View File

@@ -16,6 +16,7 @@
package com.android.settings.biometrics2.ui.view;
import static androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR;
@@ -23,24 +24,34 @@ import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewMo
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK;
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_IS_GENERATING_CHALLENGE;
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_VALID;
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_START;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorAction;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FingerprintEnrollIntroAction;
import android.annotation.StyleRes;
import android.app.Application;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.viewmodel.CreationExtras;
import androidx.lifecycle.viewmodel.MutableCreationExtras;
@@ -48,14 +59,16 @@ import androidx.lifecycle.viewmodel.MutableCreationExtras;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollEnrolling;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
import com.android.settings.biometrics2.factory.BiometricsViewModelFactory;
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel;
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel;
import com.android.settings.overlay.FeatureFactory;
@@ -66,37 +79,57 @@ import com.google.android.setupdesign.util.ThemeHelper;
*/
public class FingerprintEnrollmentActivity extends FragmentActivity {
private static final boolean DEBUG = false;
private static final String TAG = "FingerprintEnrollmentActivity";
private static final String INTRO_TAG = "enroll-intro";
private static final String FIND_UDFPS_TAG = "enroll-find-udfps";
private static final String FIND_SFPS_TAG = "enroll-find-sfps";
private static final String FIND_RFPS_TAG = "enroll-find-rfps";
private static final String SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog";
protected static final int LAUNCH_CONFIRM_LOCK_ACTIVITY = 1;
private ViewModelProvider mViewModelProvider;
private FingerprintEnrollmentViewModel mViewModel;
private AutoCredentialViewModel mAutoCredentialViewModel;
private ActivityResultLauncher<Intent> mNextActivityLauncher;
private ActivityResultLauncher<Intent> mChooseLockLauncher;
private final Observer<Integer> mIntroActionObserver = action -> {
if (DEBUG) {
Log.d(TAG, "mIntroActionObserver(" + action + ")");
}
if (action != null) {
onIntroAction(action);
}
};
private final Observer<Integer> mFindSensorActionObserver = action -> {
if (DEBUG) {
Log.d(TAG, "mFindSensorActionObserver(" + action + ")");
}
if (action != null) {
onFindSensorAction(action);
}
};
private final ActivityResultCallback<ActivityResult> mNextActivityResultCallback =
result -> mViewModel.onContinueEnrollActivityResult(result,
mAutoCredentialViewModel.getUserId());
private final ActivityResultLauncher<Intent> mNextActivityLauncher =
registerForActivityResult(new StartActivityForResult(), mNextActivityResultCallback);
private final ActivityResultCallback<ActivityResult> mChooseLockResultCallback =
result -> onChooseOrConfirmLockResult(true /* isChooseLock */, result);
private final ActivityResultLauncher<Intent> mChooseLockLauncher =
registerForActivityResult(new StartActivityForResult(), mChooseLockResultCallback);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNextActivityLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
(it) -> mViewModel.onContinueEnrollActivityResult(
it,
mAutoCredentialViewModel.getUserId())
);
mChooseLockLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
(it) -> onChooseOrConfirmLockResult(true, it)
);
mViewModelProvider = new ViewModelProvider(this);
ViewModelProvider viewModelProvider = new ViewModelProvider(this);
mViewModel = viewModelProvider.get(FingerprintEnrollmentViewModel.class);
mViewModel = mViewModelProvider.get(FingerprintEnrollmentViewModel.class);
mViewModel.setRequest(new EnrollmentRequest(getIntent(), getApplicationContext()));
mViewModel.setSavedInstanceState(savedInstanceState);
mAutoCredentialViewModel = viewModelProvider.get(AutoCredentialViewModel.class);
mAutoCredentialViewModel = mViewModelProvider.get(AutoCredentialViewModel.class);
mAutoCredentialViewModel.setCredentialModel(savedInstanceState, getIntent());
// Theme
@@ -106,20 +139,37 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
// fragment
setContentView(R.layout.biometric_enrollment_container);
final FingerprintEnrollIntroViewModel introViewModel =
viewModelProvider.get(FingerprintEnrollIntroViewModel.class);
introViewModel.setEnrollmentRequest(mViewModel.getRequest());
introViewModel.setUserId(mAutoCredentialViewModel.getUserId());
if (DEBUG) {
Log.e(TAG, "onCreate() has savedInstance:" + (savedInstanceState != null));
}
if (savedInstanceState == null) {
checkCredential();
final String tag = "FingerprintEnrollIntroFragment";
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.add(R.id.fragment_container_view, FingerprintEnrollIntroFragment.class, null,
tag)
.commit();
startIntroFragment();
} else {
final FragmentManager manager = getSupportFragmentManager();
String[] tags = new String[] {
FIND_UDFPS_TAG,
FIND_SFPS_TAG,
FIND_RFPS_TAG,
INTRO_TAG
};
for (String tag: tags) {
final Fragment fragment = manager.findFragmentByTag(tag);
if (fragment == null) {
continue;
}
if (DEBUG) {
Log.e(TAG, "onCreate() currentFragment:" + tag);
}
if (tag.equals(INTRO_TAG)) {
attachIntroViewModel();
} else { // FIND_UDFPS_TAG, FIND_SFPS_TAG, FIND_RFPS_TAG
attachFindSensorViewModel();
attachIntroViewModel();
}
break;
}
}
// observe LiveData
@@ -128,11 +178,80 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
mAutoCredentialViewModel.getGenerateChallengeFailedLiveData().observe(this,
this::onGenerateChallengeFailed);
}
private void startIntroFragment() {
attachIntroViewModel();
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.replace(R.id.fragment_container_view, FingerprintEnrollIntroFragment.class, null,
INTRO_TAG)
.commit();
}
private void attachIntroViewModel() {
final FingerprintEnrollIntroViewModel introViewModel =
mViewModelProvider.get(FingerprintEnrollIntroViewModel.class);
introViewModel.setEnrollmentRequest(mViewModel.getRequest());
introViewModel.setUserId(mAutoCredentialViewModel.getUserId());
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
// recreate, like press 'I agree' then press 'back' in FingerprintEnrollFindSensor activity.
// recreate, like press 'Agree' then press 'back' in FingerprintEnrollFindSensor activity.
introViewModel.clearActionLiveData();
introViewModel.getActionLiveData().observe(this, this::observeIntroAction);
introViewModel.getActionLiveData().observe(this, mIntroActionObserver);
}
// We need to make sure token is valid before entering find sensor page
private void startFindSensorFragment() {
attachFindSensorViewModel();
if (mViewModel.canAssumeUdfps()) {
// UDFPS does not need to start real fingerprint enrolling during finding sensor
startFindFpsFragmentWithProgressViewModel(FingerprintEnrollFindUdfpsFragment.class,
FIND_UDFPS_TAG, false /* initProgressViewModel */);
} else if (mViewModel.canAssumeSfps()) {
startFindFpsFragmentWithProgressViewModel(FingerprintEnrollFindSfpsFragment.class,
FIND_SFPS_TAG, true /* initProgressViewModel */);
} else {
startFindFpsFragmentWithProgressViewModel(FingerprintEnrollFindRfpsFragment.class,
FIND_RFPS_TAG, true /* initProgressViewModel */);
}
}
private void startFindFpsFragmentWithProgressViewModel(
@NonNull Class<? extends Fragment> findFpsClass, @NonNull String tag,
boolean initProgressViewModel) {
if (initProgressViewModel) {
final FingerprintEnrollProgressViewModel progressViewModel =
mViewModelProvider.get(FingerprintEnrollProgressViewModel.class);
progressViewModel.setUserId(mAutoCredentialViewModel.getUserId());
progressViewModel.setToken(mAutoCredentialViewModel.getToken());
}
final FingerprintEnrollFindSensorViewModel findSensorViewModel =
mViewModelProvider.get(FingerprintEnrollFindSensorViewModel.class);
findSensorViewModel.setIsSuw(mViewModel.getRequest().isSuw());
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.setCustomAnimations(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out,
R.anim.sud_slide_back_in, R.anim.sud_slide_back_out)
.replace(R.id.fragment_container_view, findFpsClass, null, tag)
.addToBackStack(tag)
.commit();
}
private void attachFindSensorViewModel() {
final FingerprintEnrollFindSensorViewModel findSensorViewModel =
mViewModelProvider.get(FingerprintEnrollFindSensorViewModel.class);
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
// recreate, like press 'Start' then press 'back' in FingerprintEnrollEnrolling activity.
findSensorViewModel.clearActionLiveData();
findSensorViewModel.getActionLiveData().observe(this, mFindSensorActionObserver);
}
private void startSkipSetupFindFpsDialog() {
new SkipSetupFindFpsDialog().show(getSupportFragmentManager(),
SKIP_SETUP_FIND_FPS_DIALOG_TAG);
}
private void onGenerateChallengeFailed(@NonNull Boolean ignoredBoolean) {
@@ -217,10 +336,7 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
}
}
private void observeIntroAction(@Nullable Integer action) {
if (action == null) {
return;
}
private void onIntroAction(@FingerprintEnrollIntroAction int action) {
switch (action) {
case FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH: {
onSetActivityResult(
@@ -233,13 +349,30 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
return;
}
case FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL: {
startFindSensorFragment();
}
}
}
private void onFindSensorAction(@FingerprintEnrollFindSensorAction int action) {
switch (action) {
case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP: {
onSetActivityResult(
new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
return;
}
case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG: {
startSkipSetupFindFpsDialog();
return;
}
case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START: {
final boolean isSuw = mViewModel.getRequest().isSuw();
if (!mViewModel.isWaitingActivityResult().compareAndSet(false, true)) {
Log.w(TAG, "startNext, isSuw:" + isSuw + ", fail to set isWaiting flag");
}
final Intent intent = new Intent(this, isSuw
? SetupFingerprintEnrollFindSensor.class
: FingerprintEnrollFindSensor.class);
Intent intent = new Intent(this, isSuw
? SetupFingerprintEnrollEnrolling.class
: FingerprintEnrollEnrolling.class);
intent.putExtras(mAutoCredentialViewModel.createCredentialIntentExtra());
intent.putExtras(mViewModel.getNextActivityBaseIntentExtras());
mNextActivityLauncher.launch(intent);
@@ -253,6 +386,12 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
mViewModel.checkFinishActivityDuringOnPause(isFinishing(), isChangingConfigurations());
}
@Override
protected void onApplyThemeResource(Resources.Theme theme, @StyleRes int resid, boolean first) {
theme.applyStyle(R.style.SetupWizardPartnerResource, true);
super.onApplyThemeResource(theme, resid, first);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == LAUNCH_CONFIRM_LOCK_ACTIVITY) {