Refine FingerprintEnrollmentActivity

1. Fix backstacks after enrolling finish
2. Support skipFindSensor and skipIntro

Bug: 260957939
Test: Manually test it on different sensor devices
Change-Id: I4061e29999a47bf4859d6562ad82330fb0f6f620
This commit is contained in:
Milton Wu
2023-02-25 00:17:10 +08:00
parent d078d1f00a
commit 94b421b253
9 changed files with 208 additions and 284 deletions

View File

@@ -22,8 +22,7 @@ import android.annotation.RawRes;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
@@ -37,16 +36,16 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.transition.Transition;
import androidx.transition.TransitionSet;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog;
import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel;
@@ -78,8 +77,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private DeviceRotationViewModel mRotationViewModel;
private FingerprintEnrollProgressViewModel mProgressViewModel;
private boolean mAnimationCancelled;
private LottieAnimationView mIllustrationLottie;
private boolean mHaveShownUdfpsTipLottie;
private boolean mHaveShownUdfpsLeftEdgeLottie;
@@ -87,12 +84,8 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private boolean mHaveShownUdfpsCenterLottie;
private boolean mHaveShownUdfpsGuideLottie;
private RelativeLayout mView;
private ImageView mIcon;
private TextView mErrorText;
private TextView mTitleText;
private TextView mSubTitleText;
private Button mSkipBtn;
private UdfpsEnrollView mUdfpsEnrollView;
private boolean mShouldShowLottie;
@@ -101,20 +94,22 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private final View.OnClickListener mOnSkipClickListener =
(v) -> mEnrollingViewModel.onCancelledDueToOnSkipPressed();
private Observer<EnrollmentProgress> mProgressObserver = progress -> {
private final Observer<EnrollmentProgress> mProgressObserver = progress -> {
if (progress != null) {
onEnrollmentProgressChange(progress);
}
};
private Observer<EnrollmentStatusMessage> mHelpMessageObserver = helpMessage -> {
private final Observer<EnrollmentStatusMessage> mHelpMessageObserver = helpMessage -> {
if (helpMessage != null) {
onEnrollmentHelp(helpMessage.getMsgId(), helpMessage.getStr());
onEnrollmentHelp(helpMessage.getStr());
}
};
private Observer<EnrollmentStatusMessage> mErrorMessageObserver = errorMessage -> {
// TODO
private final Observer<EnrollmentStatusMessage> mErrorMessageObserver = errorMessage -> {
if (errorMessage != null) {
onEnrollmentError(errorMessage);
}
};
private Observer<Boolean> mAcquireObserver = isAcquiredGood -> {
private final Observer<Boolean> mAcquireObserver = isAcquiredGood -> {
if (isAcquiredGood != null) {
onAcquired(isAcquiredGood);
}
@@ -129,8 +124,14 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
onPointerUp(sensorId);
}
};
private int mIconTouchCount;
private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
setEnabled(false);
mEnrollingViewModel.setOnBackPressed();
cancelEnrollment();
}
};
@Override
@@ -141,81 +142,42 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
mRotationViewModel = provider.get(DeviceRotationViewModel.class);
mProgressViewModel = provider.get(FingerprintEnrollProgressViewModel.class);
super.onAttach(context);
final TransitionSet transitionSet = (TransitionSet) getSharedElementEnterTransition();
if (transitionSet != null) {
transitionSet.addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(@NonNull Transition transition) {
activity.getOnBackPressedDispatcher().addCallback(mOnBackPressedCallback);
}
}
@Override
public void onTransitionEnd(@NonNull Transition transition) {
transition.removeListener(this);
startEnrollment();
mAnimationCancelled = false;
startIconAnimation();
}
@Override
public void onTransitionCancel(@NonNull Transition transition) {
}
@Override
public void onTransitionPause(@NonNull Transition transition) {
}
@Override
public void onTransitionResume(@NonNull Transition transition) {
}
});
}
@Override
public void onDetach() {
mOnBackPressedCallback.setEnabled(false);
super.onDetach();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mEnrollingViewModel.restoreSavedState(savedInstanceState);
mIsAccessibilityEnabled = mEnrollingViewModel.isAccessibilityEnabled();
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
mEnrollingViewModel.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mView = initUdfpsLayout(inflater, container);
return mView;
}
private RelativeLayout initUdfpsLayout(LayoutInflater inflater, ViewGroup container) {
final RelativeLayout containView = (RelativeLayout) inflater.inflate(
R.layout.udfps_enroll_enrolling_v2, container, false);
final Activity activity = getActivity();
mIcon = containView.findViewById(R.id.sud_layout_icon);
final ImageView icon = containView.findViewById(R.id.sud_layout_icon);
mTitleText = containView.findViewById(R.id.suc_layout_title);
mSubTitleText = containView.findViewById(R.id.sud_layout_subtitle);
mErrorText = containView.findViewById(R.id.error_text);
mSkipBtn = containView.findViewById(R.id.skip_btn);
mSkipBtn.setOnClickListener(mOnSkipClickListener);
final Button skipBtn = containView.findViewById(R.id.skip_btn);
skipBtn.setOnClickListener(mOnSkipClickListener);
mUdfpsEnrollView = containView.findViewById(R.id.udfps_animation_view);
mUdfpsEnrollView.setSensorProperties(
mEnrollingViewModel.getFirstFingerprintSensorPropertiesInternal());
mShouldShowLottie = shouldShowLottie();
boolean isLandscape = BiometricUtils.isReverseLandscape(activity)
final boolean isLandscape = BiometricUtils.isReverseLandscape(activity)
|| BiometricUtils.isLandscape(activity);
updateOrientation(containView, (isLandscape
? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT));
final int rotation = mRotationViewModel.getLiveData().getValue();
if (rotation == Surface.ROTATION_270) {
RelativeLayout.LayoutParams iconLP = new RelativeLayout.LayoutParams(-2, -2);
@@ -223,7 +185,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
iconLP.addRule(RelativeLayout.END_OF, R.id.udfps_animation_view);
iconLP.topMargin = (int) convertDpToPixel(76.64f, activity);
iconLP.leftMargin = (int) convertDpToPixel(151.54f, activity);
mIcon.setLayoutParams(iconLP);
icon.setLayoutParams(iconLP);
RelativeLayout.LayoutParams titleLP = new RelativeLayout.LayoutParams(-1, -2);
titleLP.addRule(RelativeLayout.ALIGN_PARENT_TOP);
@@ -245,7 +207,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
iconLP.addRule(RelativeLayout.ALIGN_PARENT_START);
iconLP.topMargin = (int) convertDpToPixel(76.64f, activity);
iconLP.leftMargin = (int) convertDpToPixel(71.99f, activity);
mIcon.setLayoutParams(iconLP);
icon.setLayoutParams(iconLP);
RelativeLayout.LayoutParams titleLP = new RelativeLayout.LayoutParams(
metrics.widthPixels / 2, -2);
@@ -266,10 +228,10 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
RelativeLayout.LayoutParams skipBtnLP =
(RelativeLayout.LayoutParams) mIcon.getLayoutParams();
(RelativeLayout.LayoutParams) icon.getLayoutParams();
skipBtnLP.topMargin = (int) convertDpToPixel(26f, activity);
skipBtnLP.leftMargin = (int) convertDpToPixel(54f, activity);
mSkipBtn.requestLayout();
skipBtn.requestLayout();
}
return containView;
}
@@ -277,43 +239,49 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
@Override
public void onStart() {
super.onStart();
if (true /* TODO mRestoring && !mIsCanceled */) {
startEnrollment();
}
startEnrollment();
updateProgress(false /* animate */, mProgressViewModel.getProgressLiveData().getValue());
updateTitleAndDescription();
if (true /* TODO mRestoring */) {
startIconAnimation();
}
}
@Override
public void onStop() {
stopIconAnimation();
removeEnrollmentObserver();
if (!getActivity().isChangingConfigurations()) {
removeEnrollmentObservers();
if (!getActivity().isChangingConfigurations() && mProgressViewModel.isEnrolling()) {
mProgressViewModel.cancelEnrollment();
}
super.onStop();
}
private void removeEnrollmentObserver() {
private void removeEnrollmentObservers() {
preRemoveEnrollmentObservers();
mProgressViewModel.getErrorMessageLiveData().removeObserver(mErrorMessageObserver);
}
private void preRemoveEnrollmentObservers() {
mProgressViewModel.getProgressLiveData().removeObserver(mProgressObserver);
mProgressViewModel.getHelpMessageLiveData().removeObserver(mHelpMessageObserver);
mProgressViewModel.getErrorMessageLiveData().removeObserver(mErrorMessageObserver);
mProgressViewModel.getAcquireLiveData().removeObserver(mAcquireObserver);
mProgressViewModel.getPointerDownLiveData().removeObserver(mPointerDownObserver);
mProgressViewModel.getPointerUpLiveData().removeObserver(mPointerUpObserver);
}
private void cancelEnrollment() {
preRemoveEnrollmentObservers();
mProgressViewModel.cancelEnrollment();
}
private void startEnrollment() {
final boolean startResult = mProgressViewModel.startEnrollment(ENROLL_ENROLL);
if (!startResult) {
Log.e(TAG, "startEnrollment(), failed");
}
mProgressViewModel.getProgressLiveData().observe(this, mProgressObserver);
mProgressViewModel.getHelpMessageLiveData().observe(this, mHelpMessageObserver);
mProgressViewModel.getErrorMessageLiveData().observe(this, mErrorMessageObserver);
mProgressViewModel.getAcquireLiveData().observe(this, mAcquireObserver);
mProgressViewModel.getPointerDownLiveData().observe(this, mPointerDownObserver);
mProgressViewModel.getPointerUpLiveData().observe(this, mPointerUpObserver);
mProgressViewModel.startEnrollment(ENROLL_ENROLL);
}
private void updateProgress(boolean animate, @NonNull EnrollmentProgress enrollmentProgress) {
@@ -343,12 +311,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
return PROGRESS_BAR_MAX * displayProgress / (progress.getSteps() + 1);
}
@Override
public void onDestroy() {
// TODO stopListenOrientationEvent();
super.onDestroy();
}
private void animateProgress(int progress) {
// UDFPS animations are owned by SystemUI
if (progress >= PROGRESS_BAR_MAX) {
@@ -363,13 +325,13 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
mTitleText.setText(R.string.security_settings_fingerprint_enroll_repeat_title);
if (mIsAccessibilityEnabled || mIllustrationLottie == null) {
mSubTitleText.setText(R.string.security_settings_udfps_enroll_start_message);
} else if (!mHaveShownUdfpsCenterLottie && mIllustrationLottie != null) {
} else if (!mHaveShownUdfpsCenterLottie) {
mHaveShownUdfpsCenterLottie = true;
// Note: Update string reference when differentiate in between udfps & sfps
mIllustrationLottie.setContentDescription(
getString(R.string.security_settings_sfps_enroll_finger_center_title)
);
configureEnrollmentStage("", R.raw.udfps_center_hint_lottie);
configureEnrollmentStage(R.raw.udfps_center_hint_lottie);
}
break;
@@ -378,13 +340,13 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
if (mIsAccessibilityEnabled || mIllustrationLottie == null) {
mSubTitleText.setText(
R.string.security_settings_udfps_enroll_repeat_a11y_message);
} else if (!mHaveShownUdfpsGuideLottie && mIllustrationLottie != null) {
} else if (!mHaveShownUdfpsGuideLottie) {
mHaveShownUdfpsGuideLottie = true;
mIllustrationLottie.setContentDescription(
getString(R.string.security_settings_fingerprint_enroll_repeat_message)
);
// TODO(b/228100413) Could customize guided lottie animation
configureEnrollmentStage("", R.raw.udfps_center_hint_lottie);
configureEnrollmentStage(R.raw.udfps_center_hint_lottie);
}
break;
case STAGE_FINGERTIP:
@@ -394,7 +356,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
mIllustrationLottie.setContentDescription(
getString(R.string.security_settings_udfps_tip_fingerprint_help)
);
configureEnrollmentStage("", R.raw.udfps_tip_hint_lottie);
configureEnrollmentStage(R.raw.udfps_tip_hint_lottie);
}
break;
case STAGE_LEFT_EDGE:
@@ -404,7 +366,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
mIllustrationLottie.setContentDescription(
getString(R.string.security_settings_udfps_side_fingerprint_help)
);
configureEnrollmentStage("", R.raw.udfps_left_edge_hint_lottie);
configureEnrollmentStage(R.raw.udfps_left_edge_hint_lottie);
} else if (mIllustrationLottie == null) {
if (isStageHalfCompleted()) {
mSubTitleText.setText(
@@ -421,7 +383,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
mIllustrationLottie.setContentDescription(
getString(R.string.security_settings_udfps_side_fingerprint_help)
);
configureEnrollmentStage("", R.raw.udfps_right_edge_hint_lottie);
configureEnrollmentStage(R.raw.udfps_right_edge_hint_lottie);
} else if (mIllustrationLottie == null) {
if (isStageHalfCompleted()) {
@@ -471,13 +433,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
}
private void startIconAnimation() {
}
private void stopIconAnimation() {
mAnimationCancelled = true;
}
private int getCurrentStage() {
EnrollmentProgress progressLiveData = mProgressViewModel.getProgressLiveData().getValue();
@@ -533,14 +488,8 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
* mEnrollingViewModel.getEnrollStageThreshold(index));
}
private void showIconTouchDialog() {
mIconTouchCount = 0;
//TODO EnrollingActivity should observe live data and add dialog fragment
mEnrollingViewModel.onIconTouchDialogShow();
}
private void configureEnrollmentStage(CharSequence description, @RawRes int lottie) {
mSubTitleText.setText(description);
private void configureEnrollmentStage(@RawRes int lottie) {
mSubTitleText.setText("");
LottieCompositionFactory.fromRawRes(getActivity(), lottie)
.addListener((c) -> {
mIllustrationLottie.setComposition(c);
@@ -565,13 +514,34 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
private void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
private void onEnrollmentHelp(CharSequence helpString) {
if (!TextUtils.isEmpty(helpString)) {
showError(helpString);
mUdfpsEnrollView.onEnrollmentHelp();
}
}
private void onEnrollmentError(@NonNull EnrollmentStatusMessage errorMessage) {
removeEnrollmentObservers();
if (mEnrollingViewModel.getOnBackPressed()
&& errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
mEnrollingViewModel.onCancelledDueToOnBackPressed();
} else if (mEnrollingViewModel.getOnSkipPressed()
&& errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
mEnrollingViewModel.onCancelledDueToOnSkipPressed();
} else {
final int errMsgId = errorMessage.getMsgId();
mEnrollingViewModel.showErrorDialog(
new FingerprintEnrollEnrollingViewModel.ErrorDialogData(
getString(FingerprintErrorDialog.getErrorMessage(errMsgId)),
getString(FingerprintErrorDialog.getErrorTitle(errMsgId)),
errMsgId
));
mProgressViewModel.cancelEnrollment();
}
}
private void onAcquired(boolean isAcquiredGood) {
if (mUdfpsEnrollView != null) {
mUdfpsEnrollView.onAcquired(isAcquiredGood);
@@ -597,8 +567,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
private float convertDpToPixel(float dp, Context context) {
float px = dp * getDensity(context);
return px;
return dp * getDensity(context);
}
private float getDensity(Context context) {
@@ -606,38 +575,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
return metrics.density;
}
private final Runnable mShowDialogRunnable = new Runnable() {
@Override
public void run() {
showIconTouchDialog();
}
};
// Give the user a chance to see progress completed before jumping to the next stage.
private final Runnable mDelayedFinishRunnable = new Runnable() {
@Override
public void run() {
/* TODO launchFinish(); */
}
};
private final Animatable2.AnimationCallback mIconAnimationCallback =
new Animatable2.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable d) {
if (mAnimationCancelled) {
return;
}
// Start animation after it has ended.
/* TODO check mProgressBar?
mProgressBar.post(new Runnable() {
@Override
public void run() {
startIconAnimation();
}
});
*/
}
};
private final Runnable mDelayedFinishRunnable = () -> mEnrollingViewModel.onEnrollingDone();
}