Attach FingerprintEnrollEnrollingRfps fragment

Support enrolling RFPS on biomerics v2.

Bug: 260957939
Test: atest FingerprintEnrollFindSensorViewModelTest
      FingerprintEnrollProgressViewModelTest
      FingerprintEnrollmentViewModelTest
      FingerprintEnrollmentActivityTest
Change-Id: Ic04b934592415d03f1b119383bffd40bd5eef2bd
This commit is contained in:
Milton Wu
2023-02-07 17:59:06 +08:00
parent b6cc92a9b8
commit 81530e3f27
14 changed files with 1333 additions and 403 deletions

View File

@@ -16,26 +16,32 @@
package com.android.settings.biometrics2.ui.viewmodel;
import android.annotation.IntDef;
import android.app.Application;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.util.Log;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
import com.android.settings.biometrics2.data.repository.VibratorRepository;
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* ViewModel explaining the fingerprint enrolling page
*/
public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel
implements DefaultLifecycleObserver {
public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
private static final String TAG = FingerprintEnrollEnrollingViewModel.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -45,34 +51,117 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel
private static final VibrationAttributes FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES =
VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ACCESSIBILITY);
//Enrolling skip
/**
* Enrolling skipped
*/
public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP = 0;
//Icon touch dialog show
public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_DIALOG = 0;
/**
* Enrolling finished
*/
public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE = 1;
//Icon touch dialog dismiss
public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_DIALOG = 1;
/**
* Icon touch dialog show
*/
public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_DIALOG = 2;
/**
* Icon touch dialog dismiss
*/
public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_DIALOG = 3;
@IntDef(prefix = { "FINGERPRINT_ENROLL_ENROLLING_ACTION_" }, value = {
FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP,
FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE,
FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_DIALOG,
FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_DIALOG
})
@Retention(RetentionPolicy.SOURCE)
public @interface FingerprintEnrollEnrollingAction {}
/**
* Enrolling skipped
*/
public static final int FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH = 0;
/**
* Enrolling finished
*/
public static final int FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT = 1;
/**
* Icon touch dialog show
*/
public static final int FINGERPRINT_ERROR_DIALOG_ACTION_RESTART = 2;
@IntDef(prefix = { "FINGERPRINT_ERROR_DIALOG_ACTION_" }, value = {
FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH,
FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT,
FINGERPRINT_ERROR_DIALOG_ACTION_RESTART
})
@Retention(RetentionPolicy.SOURCE)
public @interface FingerprintErrorDialogAction {}
private final int mUserId;
private final FingerprintRepository mFingerprintRepository;
private final AccessibilityRepository mAccessibilityRepository;
private final VibratorRepository mVibratorRepository;
private EnrollmentRequest mEnrollmentRequest = null;
private final MutableLiveData<Boolean> mBackPressedLiveData = new MutableLiveData<>(false);
private final MutableLiveData<Integer> mEnrollingLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mIconTouchDialogLiveData = new MutableLiveData<>();
private final MutableLiveData<ErrorDialogData> mErrorDialogLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mErrorDialogActionLiveData = new MutableLiveData<>();
public FingerprintEnrollEnrollingViewModel(Application application,
int userId,
FingerprintRepository fingerprintRepository,
AccessibilityRepository accessibilityRepository,
VibratorRepository vibratorRepository) {
super(application);
mUserId = userId;
mFingerprintRepository = fingerprintRepository;
mAccessibilityRepository = accessibilityRepository;
mVibratorRepository = vibratorRepository;
}
/**
* Notifies activity to show error dialog
*/
public void showErrorDialog(@NonNull ErrorDialogData errorDialogData) {
mErrorDialogLiveData.postValue(errorDialogData);
}
public LiveData<ErrorDialogData> getErrorDialogLiveData() {
return mErrorDialogLiveData;
}
/**
* Saves new user dialog action to mErrorDialogActionLiveData
*/
public void onErrorDialogAction(@FingerprintErrorDialogAction int action) {
if (DEBUG) {
Log.d(TAG, "onErrorDialogAction(" + action + ")");
}
mErrorDialogActionLiveData.postValue(action);
}
/**
* Clears back press data
*/
public void clearBackPressedData() {
mBackPressedLiveData.setValue(false);
}
/**
* User trigger back pressed
*/
public void onBackPressed() {
mBackPressedLiveData.postValue(true);
}
/**
* User clicks skip button
*/
@@ -84,6 +173,17 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel
mEnrollingLiveData.postValue(action);
}
/**
* Is enrolling finished
*/
public void onEnrollingDone() {
final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP;
if (DEBUG) {
Log.d(TAG, "onEnrollingDone, post action " + action);
}
mEnrollingLiveData.postValue(action);
}
/**
* Icon touch dialog show
*/
@@ -120,20 +220,6 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel
return mFingerprintRepository.getEnrollStageCount();
}
/**
* The first sensor type is UDFPS sensor or not
*/
public boolean canAssumeUdfps() {
return mFingerprintRepository.canAssumeUdfps();
}
/**
* The first sensor type is SFPS sensor or not
*/
public boolean canAssumeSfps() {
return mFingerprintRepository.canAssumeSfps();
}
/**
* Requests interruption of the accessibility feedback from all accessibility services.
*/
@@ -154,8 +240,80 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel
* Like {@link #vibrate(VibrationEffect, VibrationAttributes)}, but allows the
* caller to specify the vibration is owned by someone else and set a reason for vibration.
*/
public void vibrateError(int uid, String opPkg, String reason) {
mVibratorRepository.vibrate(uid, opPkg, VIBRATE_EFFECT_ERROR, reason,
FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES);
public void vibrateError(String reason) {
mVibratorRepository.vibrate(mUserId, getApplication().getOpPackageName(),
VIBRATE_EFFECT_ERROR, reason, FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES);
}
/**
* Gets the first FingerprintSensorPropertiesInternal from FingerprintManager
*/
@Nullable
public FingerprintSensorPropertiesInternal getFirstFingerprintSensorPropertiesInternal() {
return mFingerprintRepository.getFirstFingerprintSensorPropertiesInternal();
}
/**
* The first sensor type is UDFPS sensor or not
*/
public boolean canAssumeUdfps() {
return mFingerprintRepository.canAssumeUdfps();
}
/**
* Saves current state to outState
*/
public void onSaveInstanceState(@NonNull Bundle outState) {
// TODO
// mRestoring = true;
// mIsCanceled = savedInstanceState.getBoolean(KEY_STATE_CANCELED, false);
// mPreviousRotation = savedInstanceState.getInt(KEY_STATE_PREVIOUS_ROTATION,
// getDisplay().getRotation());
// mIsOrientationChanged = mPreviousRotation != getDisplay().getRotation();
}
/**
* Restores saved state from previous savedInstanceState
*/
public void restoreSavedState(@Nullable Bundle savedInstanceState) {
if (savedInstanceState == null) {
return;
}
// TODO
// outState.putBoolean(KEY_STATE_CANCELED, mIsCanceled);
// outState.putInt(KEY_STATE_PREVIOUS_ROTATION, mPreviousRotation);
}
/**
* Data for passing to FingerprintEnrollEnrollingErrorDialog
*/
public static class ErrorDialogData {
@NonNull private final CharSequence mErrMsg;
@NonNull private final CharSequence mErrTitle;
@NonNull private final int mErrMsgId;
public ErrorDialogData(@NonNull CharSequence errMsg, @NonNull CharSequence errTitle,
int errMsgId) {
mErrMsg = errMsg;
mErrTitle = errTitle;
mErrMsgId = errMsgId;
}
public CharSequence getErrMsg() {
return mErrMsg;
}
public CharSequence getErrTitle() {
return mErrTitle;
}
public int getErrMsgId() {
return mErrMsgId;
}
@Override
public String toString() {
return ErrorDialogData.class.getSimpleName() + "{id:" + mErrMsgId + "}";
}
}
}

View File

@@ -55,17 +55,17 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
new MutableLiveData<>();
private final MutableLiveData<EnrollmentStatusMessage> mErrorMessageLiveData =
new MutableLiveData<>();
private final MutableLiveData<Boolean> mAcquireLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mPointerDownLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mPointerUpLiveData = new MutableLiveData<>();
private final MutableLiveData<Boolean> mDoneLiveData = new MutableLiveData<>(false);
private byte[] mToken = null;
private final int mUserId;
private final FingerprintUpdater mFingerprintUpdater;
private final MessageDisplayController mMessageDisplayController;
private EnrollmentHelper mEnrollmentHelper;
@Nullable private CancellationSignal mCancellationSignal = null;
private final EnrollmentCallback mEnrollmentCallback = new EnrollmentCallback() {
@Override
@@ -78,7 +78,11 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
+ ", post progress as " + progress);
}
mProgressLiveData.postValue(progress);
// TODO set enrolling to false when remaining is 0 during implementing b/260957933
final Boolean done = remaining == 0;
if (!done.equals(mDoneLiveData.getValue())) {
mDoneLiveData.postValue(done);
}
}
@Override
@@ -136,7 +140,10 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
* clear progress
*/
public void clearProgressLiveData() {
mDoneLiveData.setValue(false);
mProgressLiveData.setValue(new EnrollmentProgress(INITIAL_STEPS, INITIAL_REMAINING));
mHelpMessageLiveData.setValue(null);
mErrorMessageLiveData.setValue(null);
}
public LiveData<EnrollmentProgress> getProgressLiveData() {
@@ -151,18 +158,21 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
return mErrorMessageLiveData;
}
public MutableLiveData<Boolean> getAcquireLiveData() {
public LiveData<Boolean> getAcquireLiveData() {
return mAcquireLiveData;
}
public MutableLiveData<Integer> getPointerDownLiveData() {
public LiveData<Integer> getPointerDownLiveData() {
return mPointerDownLiveData;
}
public MutableLiveData<Integer> getPointerUpLiveData() {
public LiveData<Integer> getPointerUpLiveData() {
return mPointerUpLiveData;
}
public LiveData<Boolean> getDoneLiveData() {
return mDoneLiveData;
}
/**
* Starts enrollment and return latest isEnrolling() result
@@ -172,16 +182,18 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
Log.e(TAG, "Null hardware auth token for enroll");
return false;
}
if (isEnrolling()) {
if (mCancellationSignal != null) {
Log.w(TAG, "Enrolling has started, shall not start again");
return true;
}
if (DEBUG) {
Log.e(TAG, "startEnrollment(" + reason + ")");
}
mEnrollmentHelper = new EnrollmentHelper(
mMessageDisplayController != null
? mMessageDisplayController
: mEnrollmentCallback);
mEnrollmentHelper.startEnrollment(mFingerprintUpdater, mToken, mUserId, reason);
mCancellationSignal = new CancellationSignal();
mFingerprintUpdater.enroll(mToken, mCancellationSignal, mUserId,
mMessageDisplayController != null ? mMessageDisplayController : mEnrollmentCallback,
reason);
return true;
}
@@ -189,86 +201,22 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
* Cancels enrollment and return latest isEnrolling result
*/
public boolean cancelEnrollment() {
if (!isEnrolling() || mEnrollmentHelper == null) {
Log.e(TAG, "Fail to cancel enrollment, enrollmentController exist:"
+ (mEnrollmentHelper != null));
final CancellationSignal cancellationSignal = mCancellationSignal;
if (cancellationSignal == null) {
Log.e(TAG, "Fail to cancel enrollment, has cancelled or not start");
return false;
}
mEnrollmentHelper.cancelEnrollment();
mEnrollmentHelper = null;
mCancellationSignal = null;
cancellationSignal.cancel();
return true;
}
public boolean isEnrolling() {
return (mEnrollmentHelper != null);
return (mCancellationSignal != null);
}
private int getSteps() {
return mProgressLiveData.getValue().getSteps();
}
/**
* This class is used to stop latest message from onEnrollmentError() after user cancelled
* enrollment. This class will not forward message anymore after mCancellationSignal is sent.
*/
private static class EnrollmentHelper extends EnrollmentCallback {
@NonNull private final EnrollmentCallback mEnrollmentCallback;
@Nullable private CancellationSignal mCancellationSignal = new CancellationSignal();
EnrollmentHelper(@NonNull EnrollmentCallback enrollmentCallback) {
mEnrollmentCallback = enrollmentCallback;
}
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
if (mCancellationSignal == null) {
return;
}
mEnrollmentCallback.onEnrollmentError(errMsgId, errString);
}
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
if (mCancellationSignal == null) {
return;
}
mEnrollmentCallback.onEnrollmentHelp(helpMsgId, helpString);
}
@Override
public void onEnrollmentProgress(int remaining) {
if (mCancellationSignal == null) {
return;
}
mEnrollmentCallback.onEnrollmentProgress(remaining);
}
/**
* Starts enrollment
*/
public boolean startEnrollment(@NonNull FingerprintUpdater fingerprintUpdater,
@NonNull byte[] token, int userId, @EnrollReason int reason) {
if (mCancellationSignal == null) {
// Not allow enrolling twice as same instance. Allocate a new instance for second
// enrollment.
return false;
}
fingerprintUpdater.enroll(token, mCancellationSignal, userId, this, reason);
return true;
}
/**
* Cancels current enrollment
*/
public void cancelEnrollment() {
final CancellationSignal cancellationSignal = mCancellationSignal;
mCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.cancel();
}
}
}
}