[BiometricsV2] Add retry button
Add retry button for FingerprintEnrollErrorDialog and make sure that
this button works well in the whole enrollment flow.
Bug: 287168522
Test: manually test this dialog with error and rotate devices
Test: atest FingerprintEnrollEnrollingViewModelTest
Test: atest FingerprintEnrollErrorDialogViewModelTest
Test: atest FingerprintEnrollProgressViewModelTest
Test: atest FingerprintEnrollmentActivityTest
Test: atest biometrics-enrollment-test
Change-Id: Ica1d91d077ca322caca5551068f2a3c23b544361
diff --git a/Android.bp b/Android.bp
index 1351d03..baf9914 100644
--- a/Android.bp
+++ b/Android.bp
@@ -77,6 +77,7 @@
"setupcompat",
"setupdesign",
"androidx.lifecycle_lifecycle-runtime",
+ "androidx.lifecycle_lifecycle-runtime-ktx",
"androidx.lifecycle_lifecycle-viewmodel",
"guava",
"jsr305",
diff --git a/res/layout/udfps_enroll_enrolling_v2.xml b/res/layout/udfps_enroll_enrolling_v2.xml
index 4675606..b579bed 100644
--- a/res/layout/udfps_enroll_enrolling_v2.xml
+++ b/res/layout/udfps_enroll_enrolling_v2.xml
@@ -70,25 +70,7 @@
app:lottie_loop="true"
app:lottie_speed=".85" />
- <com.android.settings.biometrics2.ui.widget.UdfpsEnrollView
- android:id="@+id/udfps_animation_view"
- android:layout_width="218.42dp"
- android:layout_height="216dp"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="553dp">
-
- <ImageView
- android:id="@+id/udfps_enroll_animation_fp_progress_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <!-- Fingerprint -->
- <ImageView
- android:id="@+id/udfps_enroll_animation_fp_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </com.android.settings.biometrics2.ui.widget.UdfpsEnrollView>
+ <include layout="@layout/udfps_enroll_enrolling_v2_udfps_view"/>
<Button
style="@style/SudGlifButton.Secondary"
diff --git a/res/layout/udfps_enroll_enrolling_v2_udfps_view.xml b/res/layout/udfps_enroll_enrolling_v2_udfps_view.xml
new file mode 100644
index 0000000..a29b2fd
--- /dev/null
+++ b/res/layout/udfps_enroll_enrolling_v2_udfps_view.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<com.android.settings.biometrics2.ui.widget.UdfpsEnrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/udfps_animation_view"
+ android:layout_width="218.42dp"
+ android:layout_height="216dp"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="553dp">
+
+ <ImageView
+ android:id="@+id/udfps_enroll_animation_fp_progress_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <!-- Fingerprint -->
+ <ImageView
+ android:id="@+id/udfps_enroll_animation_fp_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</com.android.settings.biometrics2.ui.widget.UdfpsEnrollView>
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java b/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
index dd5b673..b83614c 100644
--- a/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
+++ b/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
@@ -34,6 +34,7 @@
import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel;
import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel;
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel;
@@ -47,7 +48,7 @@
*/
public class BiometricsViewModelFactory implements ViewModelProvider.Factory {
- private static final String TAG = "BiometricsViewModelFact";
+ private static final String TAG = "BiometricsViewModelFactory";
public static final CreationExtras.Key<ChallengeGenerator> CHALLENGE_GENERATOR_KEY =
new CreationExtras.Key<ChallengeGenerator>() {};
@@ -113,7 +114,7 @@
final Integer userId = extras.get(USER_ID_KEY);
final FingerprintRepository fingerprint = provider.getFingerprintRepository(
application);
- if (fingerprint != null) {
+ if (fingerprint != null && userId != null) {
return (T) new FingerprintEnrollEnrollingViewModel(application, userId,
fingerprint);
}
@@ -122,10 +123,15 @@
final EnrollmentRequest request = extras.get(ENROLLMENT_REQUEST_KEY);
final FingerprintRepository fingerprint = provider.getFingerprintRepository(
application);
- if (fingerprint != null && userId != null) {
+ if (fingerprint != null && userId != null && request != null) {
return (T) new FingerprintEnrollFinishViewModel(application, userId, request,
fingerprint);
}
+ } else if (modelClass.isAssignableFrom(FingerprintEnrollErrorDialogViewModel.class)) {
+ final EnrollmentRequest request = extras.get(ENROLLMENT_REQUEST_KEY);
+ if (request != null) {
+ return (T) new FingerprintEnrollErrorDialogViewModel(application, request.isSuw());
+ }
}
return create(modelClass);
}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingErrorDialog.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingErrorDialog.kt
deleted file mode 100644
index 8fb1118..0000000
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingErrorDialog.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 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.biometrics2.ui.view
-
-import android.app.Dialog
-import android.content.Context
-import android.content.DialogInterface
-import android.hardware.biometrics.BiometricConstants
-import android.os.Bundle
-import androidx.appcompat.app.AlertDialog
-import androidx.fragment.app.DialogFragment
-import androidx.lifecycle.ViewModelProvider
-import com.android.settings.R
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
-
-/**
- * Fingerprint error dialog, will be shown when an error occurs during fingerprint enrollment.
- */
-class FingerprintEnrollEnrollingErrorDialog : DialogFragment() {
-
- private var mViewModel: FingerprintEnrollEnrollingViewModel? = null
-
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- val value = mViewModel!!.errorDialogLiveData.value!!
- return requireActivity().bindFingerprintEnrollEnrollingErrorDialog(
- title = value.errTitle,
- message = value.errMsg,
- positiveButtonClickListener = { dialog: DialogInterface?, _: Int ->
- dialog?.dismiss()
- mViewModel?.onErrorDialogAction(
- if (value.errMsgId == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT)
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
- else
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
- )
- }
- )
- }
-
- override fun onAttach(context: Context) {
- mViewModel = ViewModelProvider(requireActivity())[
- FingerprintEnrollEnrollingViewModel::class.java]
- super.onAttach(context)
- }
-}
-
-fun Context.bindFingerprintEnrollEnrollingErrorDialog(
- title: CharSequence?,
- message: CharSequence?,
- positiveButtonClickListener: DialogInterface.OnClickListener
-): AlertDialog = AlertDialog.Builder(this)
- .setTitle(title)
- .setMessage(message)
- .setCancelable(false)
- .setPositiveButton(
- R.string.security_settings_fingerprint_enroll_dialog_ok,
- positiveButtonClickListener
- )
- .create()
- .apply { setCanceledOnTouchOutside(false) }
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.kt
index 66a9c00..08a8217 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.kt
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.kt
@@ -23,13 +23,14 @@
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
-import android.hardware.fingerprint.FingerprintManager
-import android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_CANCELED
+import android.hardware.biometrics.BiometricFingerprintConstants
+import android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
+import android.view.Surface
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils.loadInterpolator
@@ -39,17 +40,22 @@
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.android.settings.R
-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.FingerprintEnrollEnrollingViewModel
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton
import com.google.android.setupdesign.GlifLayout
+import kotlinx.coroutines.launch
/**
* Fragment is used to handle enrolling process for rfps
@@ -64,25 +70,24 @@
private val progressViewModel: FingerprintEnrollProgressViewModel
get() = _progressViewModel!!
- private val fastOutSlowInInterpolator: Interpolator
- get() = loadInterpolator(requireActivity(), android.R.interpolator.fast_out_slow_in)
+ private var _errorDialogViewModel: FingerprintEnrollErrorDialogViewModel? = null
+ private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel
+ get() = _errorDialogViewModel!!
- private val linearOutSlowInInterpolator: Interpolator
- get() = loadInterpolator(requireActivity(), android.R.interpolator.linear_out_slow_in)
-
- private val fastOutLinearInInterpolator: Interpolator
- get() = loadInterpolator(requireActivity(), android.R.interpolator.fast_out_linear_in)
+ private var fastOutSlowInInterpolator: Interpolator? = null
+ private var linearOutSlowInInterpolator: Interpolator? = null
+ private var fastOutLinearInInterpolator: Interpolator? = null
private var isAnimationCancelled = false
- private var enrollingRfpsView: GlifLayout? = null
+ private var enrollingView: GlifLayout? = null
private val progressBar: ProgressBar
- get() = enrollingRfpsView!!.findViewById<ProgressBar>(R.id.fingerprint_progress_bar)!!
+ get() = enrollingView!!.findViewById(R.id.fingerprint_progress_bar)!!
private var progressAnim: ObjectAnimator? = null
private val errorText: TextView
- get() = enrollingRfpsView!!.findViewById<TextView>(R.id.error_text)!!
+ get() = enrollingView!!.findViewById(R.id.error_text)!!
private val iconAnimationDrawable: AnimatedVectorDrawable?
get() = (progressBar.background as LayerDrawable)
@@ -94,53 +99,47 @@
private var iconTouchCount = 0
- private val touchAgainRunnable =
- Runnable {
- showError(
- // Use enrollingRfpsView to getString to prevent activity is missing during rotation
- enrollingRfpsView!!.context.getString(
- R.string.security_settings_fingerprint_enroll_lift_touch_again
- )
+ private val touchAgainRunnable = Runnable {
+ showError(
+ // Use enrollingView to getString to prevent activity is missing during rotation
+ enrollingView!!.context.getString(
+ R.string.security_settings_fingerprint_enroll_lift_touch_again
)
- }
+ )
+ }
private val onSkipClickListener = View.OnClickListener { _: View? ->
enrollingViewModel.setOnSkipPressed()
- cancelEnrollment()
+ cancelEnrollment(true)
}
- private val progressObserver: Observer<EnrollmentProgress> =
- Observer<EnrollmentProgress> { progress: EnrollmentProgress? ->
- if (DEBUG) {
- Log.d(TAG, "progressObserver($progress)")
- }
- if (progress != null && progress.steps >= 0) {
- onEnrollmentProgressChange(progress)
- }
- }
+ private var enrollingCancelSignal: Any? = null
- private val helpMessageObserver: Observer<EnrollmentStatusMessage> =
- Observer<EnrollmentStatusMessage> { helpMessage: EnrollmentStatusMessage? ->
- if (DEBUG) {
- Log.d(TAG, "helpMessageObserver($helpMessage)")
- }
- helpMessage?.let { onEnrollmentHelp(it) }
+ private val progressObserver = Observer { progress: EnrollmentProgress? ->
+ if (progress != null && progress.steps >= 0) {
+ onEnrollmentProgressChange(progress)
}
+ }
- private val errorMessageObserver: Observer<EnrollmentStatusMessage> =
- Observer<EnrollmentStatusMessage> { errorMessage: EnrollmentStatusMessage? ->
- if (DEBUG) {
- Log.d(TAG, "errorMessageObserver($errorMessage)")
- }
- errorMessage?.let { onEnrollmentError(it) }
- }
+ private val helpMessageObserver = Observer { helpMessage: EnrollmentStatusMessage? ->
+ helpMessage?.let { onEnrollmentHelp(it) }
+ }
+
+ private val errorMessageObserver = Observer { errorMessage: EnrollmentStatusMessage? ->
+ Log.d(TAG, "errorMessageObserver($errorMessage)")
+ errorMessage?.let { onEnrollmentError(it) }
+ }
+
+ private val canceledSignalObserver = Observer { canceledSignal: Any? ->
+ canceledSignal?.let { onEnrollmentCanceled(it) }
+ }
private val onBackPressedCallback: OnBackPressedCallback =
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
isEnabled = false
enrollingViewModel.setOnBackPressed()
- cancelEnrollment()
+ cancelEnrollment(true)
}
}
@@ -148,6 +147,7 @@
ViewModelProvider(requireActivity()).let { provider ->
_enrollingViewModel = provider[FingerprintEnrollEnrollingViewModel::class.java]
_progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
+ _errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
}
super.onAttach(context)
requireActivity().onBackPressedDispatcher.addCallback(onBackPressedCallback)
@@ -162,10 +162,10 @@
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- enrollingRfpsView = inflater.inflate(
+ enrollingView = inflater.inflate(
R.layout.fingerprint_enroll_enrolling, container, false
) as GlifLayout
- return enrollingRfpsView!!
+ return enrollingView!!
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -193,16 +193,46 @@
}
requireActivity().bindFingerprintEnrollEnrollingRfpsView(
- view = enrollingRfpsView!!,
+ view = enrollingView!!,
onSkipClickListener = onSkipClickListener
)
+
+ fastOutSlowInInterpolator =
+ loadInterpolator(requireContext(), android.R.interpolator.fast_out_slow_in)
+ linearOutSlowInInterpolator =
+ loadInterpolator(requireContext(), android.R.interpolator.linear_out_slow_in)
+ fastOutLinearInInterpolator =
+ loadInterpolator(requireContext(), android.R.interpolator.fast_out_linear_in)
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ errorDialogViewModel.triggerRetryFlow.collect { retryEnrollment() }
+ }
+ }
+ }
+
+ private fun retryEnrollment() {
+ isAnimationCancelled = false
+ startIconAnimation()
+ startEnrollment()
+
+ clearError()
+ updateProgress(false /* animate */, progressViewModel.progressLiveData.value!!)
+ updateTitleAndDescription()
}
override fun onStart() {
super.onStart()
- isAnimationCancelled = false
- startIconAnimation()
- startEnrollment()
+
+ val isEnrolling = progressViewModel.isEnrolling
+ val isErrorDialogShown = errorDialogViewModel.isDialogShown
+ Log.d(TAG, "onStart(), isEnrolling:$isEnrolling, isErrorDialog:$isErrorDialogShown")
+ if (!isErrorDialogShown) {
+ isAnimationCancelled = false
+ startIconAnimation()
+ startEnrollment()
+ }
+
updateProgress(false /* animate */, progressViewModel.progressLiveData.value!!)
updateTitleAndDescription()
}
@@ -219,32 +249,44 @@
override fun onStop() {
stopIconAnimation()
removeEnrollmentObservers()
- if (!activity!!.isChangingConfigurations && progressViewModel.isEnrolling) {
- progressViewModel.cancelEnrollment()
+ val isEnrolling = progressViewModel.isEnrolling
+ val isConfigChange = requireActivity().isChangingConfigurations
+ Log.d(TAG, "onStop(), enrolling:$isEnrolling isConfigChange:$isConfigChange")
+ if (isEnrolling && !isConfigChange) {
+ cancelEnrollment(false)
}
super.onStop()
}
private fun removeEnrollmentObservers() {
- preRemoveEnrollmentObservers()
progressViewModel.errorMessageLiveData.removeObserver(errorMessageObserver)
- }
-
- private fun preRemoveEnrollmentObservers() {
progressViewModel.progressLiveData.removeObserver(progressObserver)
progressViewModel.helpMessageLiveData.removeObserver(helpMessageObserver)
}
- private fun cancelEnrollment() {
- preRemoveEnrollmentObservers()
- progressViewModel.cancelEnrollment()
+ private fun cancelEnrollment(waitForLastCancelErrMsg: Boolean) {
+ if (!progressViewModel.isEnrolling) {
+ Log.d(TAG, "cancelEnrollment(), failed because isEnrolling is false")
+ return
+ }
+ removeEnrollmentObservers()
+ if (waitForLastCancelErrMsg) {
+ progressViewModel.canceledSignalLiveData.observe(this, canceledSignalObserver)
+ } else {
+ enrollingCancelSignal = null
+ }
+ val cancelResult: Boolean = progressViewModel.cancelEnrollment()
+ if (!cancelResult) {
+ Log.e(TAG, "cancelEnrollment(), failed to cancel enrollment")
+ }
}
private fun startEnrollment() {
- val startResult: Boolean =
- progressViewModel.startEnrollment(FingerprintManager.ENROLL_ENROLL)
- if (!startResult) {
+ enrollingCancelSignal = progressViewModel.startEnrollment(ENROLL_ENROLL)
+ if (enrollingCancelSignal == null) {
Log.e(TAG, "startEnrollment(), failed")
+ } else {
+ Log.d(TAG, "startEnrollment(), success")
}
progressViewModel.progressLiveData.observe(this, progressObserver)
progressViewModel.helpMessageLiveData.observe(this, helpMessageObserver)
@@ -252,6 +294,7 @@
}
private fun onEnrollmentHelp(helpMessage: EnrollmentStatusMessage) {
+ Log.d(TAG, "onEnrollmentHelp($helpMessage)")
val helpStr: CharSequence = helpMessage.str
if (!TextUtils.isEmpty(helpStr)) {
errorText.removeCallbacks(touchAgainRunnable)
@@ -261,29 +304,27 @@
private fun onEnrollmentError(errorMessage: EnrollmentStatusMessage) {
stopIconAnimation()
- removeEnrollmentObservers()
- if (enrollingViewModel.onBackPressed
- && errorMessage.msgId == FINGERPRINT_ERROR_CANCELED
- ) {
- enrollingViewModel.onCancelledDueToOnBackPressed()
- } else if (enrollingViewModel.onSkipPressed
- && errorMessage.msgId == FINGERPRINT_ERROR_CANCELED
- ) {
- enrollingViewModel.onCancelledDueToOnSkipPressed()
- } else {
- val errMsgId: Int = errorMessage.msgId
- enrollingViewModel.showErrorDialog(
- FingerprintEnrollEnrollingViewModel.ErrorDialogData(
- enrollingRfpsView!!.context.getString(
- FingerprintErrorDialog.getErrorMessage(errMsgId)
- ),
- enrollingRfpsView!!.context.getString(
- FingerprintErrorDialog.getErrorTitle(errMsgId)
- ),
- errMsgId
- )
- )
- progressViewModel.cancelEnrollment()
+
+ cancelEnrollment(true)
+ lifecycleScope.launch {
+ Log.d(TAG, "newDialog $errorMessage")
+ errorDialogViewModel.newDialog(errorMessage.msgId)
+ }
+ }
+
+ private fun onEnrollmentCanceled(canceledSignal: Any) {
+ Log.d(
+ TAG,
+ "onEnrollmentCanceled enrolling:$enrollingCancelSignal, canceled:$canceledSignal"
+ )
+ if (enrollingCancelSignal === canceledSignal) {
+ progressViewModel.canceledSignalLiveData.removeObserver(canceledSignalObserver)
+ progressViewModel.clearProgressLiveData()
+ if (enrollingViewModel.onBackPressed) {
+ enrollingViewModel.onCancelledDueToOnBackPressed()
+ } else if (enrollingViewModel.onSkipPressed) {
+ enrollingViewModel.onCancelledDueToOnSkipPressed()
+ }
}
}
@@ -296,11 +337,10 @@
}
private fun updateProgress(animate: Boolean, enrollmentProgress: EnrollmentProgress) {
- if (!progressViewModel.isEnrolling) {
- Log.d(TAG, "Enrollment not started yet")
- return
- }
val progress = getProgress(enrollmentProgress)
+ Log.d(TAG, "updateProgress($animate, $enrollmentProgress), old:${progressBar.progress}"
+ + ", new:$progress")
+
// Only clear the error when progress has been made.
// TODO (b/234772728) Add tests.
if (progressBar.progress < progress) {
@@ -328,7 +368,7 @@
errorText.text = error
if (errorText.visibility == View.INVISIBLE) {
errorText.visibility = View.VISIBLE
- errorText.translationY = enrollingRfpsView!!.context.resources.getDimensionPixelSize(
+ errorText.translationY = enrollingView!!.context.resources.getDimensionPixelSize(
R.dimen.fingerprint_error_text_appear_distance
).toFloat()
errorText.alpha = 0f
@@ -359,7 +399,7 @@
)
.setDuration(100)
.setInterpolator(fastOutLinearInInterpolator)
- .withEndAction { errorText!!.visibility = View.INVISIBLE }
+ .withEndAction { errorText.visibility = View.INVISIBLE }
.start()
}
}
@@ -385,8 +425,8 @@
private fun updateTitleAndDescription() {
val progressLiveData: EnrollmentProgress = progressViewModel.progressLiveData.value!!
- GlifLayoutHelper(activity!!, enrollingRfpsView!!).setDescriptionText(
- enrollingRfpsView!!.context.getString(
+ GlifLayoutHelper(activity!!, enrollingView!!).setDescriptionText(
+ enrollingView!!.context.getString(
if (progressLiveData.steps == -1)
R.string.security_settings_fingerprint_enroll_start_message
else
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.kt
index 980f800..fbdfc81 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.kt
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.kt
@@ -21,10 +21,11 @@
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Configuration
-import android.graphics.ColorFilter
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
-import android.hardware.fingerprint.FingerprintManager
+import android.hardware.biometrics.BiometricFingerprintConstants
+import android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL
+import android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_CANCELED
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@@ -39,24 +40,29 @@
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieComposition
import com.airbnb.lottie.LottieCompositionFactory
import com.airbnb.lottie.LottieProperty
import com.airbnb.lottie.model.KeyPath
import com.android.settings.R
-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.FingerprintEnrollEnrollingViewModel
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton
import com.google.android.setupdesign.GlifLayout
import com.google.android.setupdesign.template.DescriptionMixin
import com.google.android.setupdesign.template.HeaderMixin
+import kotlinx.coroutines.launch
import kotlin.math.roundToInt
/**
@@ -72,13 +78,17 @@
private val progressViewModel: FingerprintEnrollProgressViewModel
get() = _progressViewModel!!
+ private var _errorDialogViewModel: FingerprintEnrollErrorDialogViewModel? = null
+ private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel
+ get() = _errorDialogViewModel!!
+
private val fastOutSlowInInterpolator: Interpolator
get() = AnimationUtils.loadInterpolator(activity, R.interpolator.fast_out_slow_in)
- private var enrollingSfpsView: GlifLayout? = null
+ private var enrollingView: GlifLayout? = null
private val progressBar: ProgressBar
- get() = enrollingSfpsView!!.findViewById<ProgressBar>(R.id.fingerprint_progress_bar)!!
+ get() = enrollingView!!.findViewById(R.id.fingerprint_progress_bar)!!
private var progressAnim: ObjectAnimator? = null
@@ -96,7 +106,7 @@
}
private val illustrationLottie: LottieAnimationView
- get() = enrollingSfpsView!!.findViewById<LottieAnimationView>(R.id.illustration_lottie)!!
+ get() = enrollingView!!.findViewById(R.id.illustration_lottie)!!
private var haveShownSfpsNoAnimationLottie = false
private var haveShownSfpsCenterLottie = false
@@ -110,78 +120,82 @@
private val showIconTouchDialogRunnable = Runnable { showIconTouchDialog() }
+ private var enrollingCancelSignal: Any? = null
+
// Give the user a chance to see progress completed before jumping to the next stage.
private val delayedFinishRunnable = Runnable { enrollingViewModel.onEnrollingDone() }
private val onSkipClickListener = View.OnClickListener { _: View? ->
enrollingViewModel.setOnSkipPressed()
- cancelEnrollment()
+ cancelEnrollment(true)
}
- private val progressObserver: Observer<EnrollmentProgress> =
- Observer<EnrollmentProgress> { progress: EnrollmentProgress? ->
- if (DEBUG) {
- Log.d(TAG, "progressObserver($progress)")
- }
- if (progress != null && progress.steps >= 0) {
- onEnrollmentProgressChange(progress)
- }
+ private val progressObserver = Observer { progress: EnrollmentProgress? ->
+ if (progress != null && progress.steps >= 0) {
+ onEnrollmentProgressChange(progress)
}
+ }
- private val helpMessageObserver: Observer<EnrollmentStatusMessage> =
- Observer<EnrollmentStatusMessage> { helpMessage: EnrollmentStatusMessage? ->
- if (DEBUG) {
- Log.d(TAG, "helpMessageObserver($helpMessage)")
- }
- helpMessage?.let { onEnrollmentHelp(it) }
- }
+ private val helpMessageObserver = Observer { helpMessage: EnrollmentStatusMessage? ->
+ helpMessage?.let { onEnrollmentHelp(it) }
+ }
- private val errorMessageObserver: Observer<EnrollmentStatusMessage> =
- Observer<EnrollmentStatusMessage> { errorMessage: EnrollmentStatusMessage? ->
- if (DEBUG) {
- Log.d(TAG, "errorMessageObserver($errorMessage)")
+ private val errorMessageObserver = Observer { errorMessage: EnrollmentStatusMessage? ->
+ Log.d(TAG, "errorMessageObserver($errorMessage)")
+ errorMessage?.let { onEnrollmentError(it) }
+ }
+
+ private val canceledSignalObserver = Observer { canceledSignal: Any? ->
+ Log.d(TAG, "canceledSignalObserver($canceledSignal)")
+ canceledSignal?.let { onEnrollmentCanceled(it) }
+ }
+
+ private val onBackPressedCallback: OnBackPressedCallback =
+ object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ isEnabled = false
+ enrollingViewModel.setOnBackPressed()
+ cancelEnrollment(true)
}
- errorMessage?.let { onEnrollmentError(it) }
}
override fun onAttach(context: Context) {
ViewModelProvider(requireActivity()).let { provider ->
_enrollingViewModel = provider[FingerprintEnrollEnrollingViewModel::class.java]
_progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
+ _errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
}
super.onAttach(context)
- requireActivity().onBackPressedDispatcher.addCallback(
- object : OnBackPressedCallback(true) {
- override fun handleOnBackPressed() {
- isEnabled = false
- enrollingViewModel.setOnBackPressed()
- cancelEnrollment()
- }
- })
+ requireActivity().onBackPressedDispatcher.addCallback(onBackPressedCallback)
+ }
+
+ override fun onDetach() {
+ onBackPressedCallback.isEnabled = false
+ super.onDetach()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- enrollingSfpsView = inflater.inflate(
+ enrollingView = inflater.inflate(
R.layout.sfps_enroll_enrolling,
container, false
) as GlifLayout
- return enrollingSfpsView
+ return enrollingView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requireActivity().bindFingerprintEnrollEnrollingSfpsView(
- view = enrollingSfpsView!!,
+ view = enrollingView!!,
onSkipClickListener = onSkipClickListener
)
// setHelpAnimation()
helpAnimation = ObjectAnimator.ofFloat(
- enrollingSfpsView!!.findViewById<RelativeLayout>(R.id.progress_lottie)!!,
+ enrollingView!!.findViewById<RelativeLayout>(R.id.progress_lottie)!!,
"translationX" /* propertyName */,
0f,
HELP_ANIMATION_TRANSLATION_X,
@@ -212,48 +226,79 @@
}
true
}
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ errorDialogViewModel.triggerRetryFlow.collect { retryEnrollment() }
+ }
+ }
+ }
+
+ private fun retryEnrollment() {
+ startEnrollment()
+ updateProgress(false /* animate */, progressViewModel.progressLiveData.value!!)
}
override fun onStart() {
super.onStart()
- startEnrollment()
+ val isEnrolling = progressViewModel.isEnrolling
+ val isErrorDialogShown = errorDialogViewModel.isDialogShown
+ Log.d(TAG, "onStart(), isEnrolling:$isEnrolling, isErrorDialog:$isErrorDialogShown")
+ if (!isErrorDialogShown) {
+ startEnrollment()
+ }
+
updateProgress(false /* animate */, progressViewModel.progressLiveData.value!!)
- progressViewModel.helpMessageLiveData.value?.let {
- onEnrollmentHelp(it)
- } ?: run {
- clearError()
- updateTitleAndDescription()
+ progressViewModel.helpMessageLiveData.value.let {
+ if (it != null) {
+ onEnrollmentHelp(it)
+ } else {
+ clearError()
+ updateTitleAndDescription()
+ }
}
}
override fun onStop() {
removeEnrollmentObservers()
- if (!activity!!.isChangingConfigurations && progressViewModel.isEnrolling) {
- progressViewModel.cancelEnrollment()
+ val isEnrolling = progressViewModel.isEnrolling
+ val isConfigChange = requireActivity().isChangingConfigurations
+ Log.d(TAG, "onStop(), enrolling:$isEnrolling isConfigChange:$isConfigChange")
+ if (isEnrolling && !isConfigChange) {
+ cancelEnrollment(false)
}
super.onStop()
}
private fun removeEnrollmentObservers() {
- preRemoveEnrollmentObservers()
progressViewModel.errorMessageLiveData.removeObserver(errorMessageObserver)
- }
-
- private fun preRemoveEnrollmentObservers() {
progressViewModel.progressLiveData.removeObserver(progressObserver)
progressViewModel.helpMessageLiveData.removeObserver(helpMessageObserver)
}
- private fun cancelEnrollment() {
- preRemoveEnrollmentObservers()
- progressViewModel.cancelEnrollment()
+ private fun cancelEnrollment(waitForLastCancelErrMsg: Boolean) {
+ if (!progressViewModel.isEnrolling) {
+ Log.d(TAG, "cancelEnrollment(), failed because isEnrolling is false")
+ return
+ }
+ removeEnrollmentObservers()
+ if (waitForLastCancelErrMsg) {
+ progressViewModel.canceledSignalLiveData.observe(this, canceledSignalObserver)
+ } else {
+ enrollingCancelSignal = null
+ }
+ val cancelResult: Boolean = progressViewModel.cancelEnrollment()
+ if (!cancelResult) {
+ Log.e(TAG, "cancelEnrollment(), failed to cancel enrollment")
+ }
}
private fun startEnrollment() {
- val startResult: Boolean =
- progressViewModel.startEnrollment(FingerprintManager.ENROLL_ENROLL)
- if (!startResult) {
+ enrollingCancelSignal = progressViewModel.startEnrollment(ENROLL_ENROLL)
+ if (enrollingCancelSignal == null) {
Log.e(TAG, "startEnrollment(), failed")
+ } else {
+ Log.d(TAG, "startEnrollment(), success")
}
progressViewModel.progressLiveData.observe(this, progressObserver)
progressViewModel.helpMessageLiveData.observe(this, helpMessageObserver)
@@ -261,7 +306,7 @@
}
private fun configureEnrollmentStage(description: CharSequence, @RawRes lottie: Int) {
- GlifLayoutHelper(requireActivity(), enrollingSfpsView!!).setDescriptionText(description)
+ GlifLayoutHelper(requireActivity(), enrollingView!!).setDescriptionText(description)
LottieCompositionFactory.fromRawRes(activity, lottie)
.addListener { c: LottieComposition ->
illustrationLottie.setComposition(c)
@@ -290,6 +335,7 @@
}
private fun onEnrollmentHelp(helpMessage: EnrollmentStatusMessage) {
+ Log.d(TAG, "onEnrollmentHelp($helpMessage)")
val helpStr: CharSequence = helpMessage.str
if (helpStr.isNotEmpty()) {
showError(helpStr)
@@ -297,25 +343,26 @@
}
private fun onEnrollmentError(errorMessage: EnrollmentStatusMessage) {
- removeEnrollmentObservers()
- if (enrollingViewModel.onBackPressed
- && errorMessage.msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
- ) {
- enrollingViewModel.onCancelledDueToOnBackPressed()
- } else if (enrollingViewModel.onSkipPressed
- && errorMessage.msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
- ) {
- enrollingViewModel.onCancelledDueToOnSkipPressed()
- } else {
- val errMsgId: Int = errorMessage.msgId
- enrollingViewModel.showErrorDialog(
- FingerprintEnrollEnrollingViewModel.ErrorDialogData(
- getString(FingerprintErrorDialog.getErrorMessage(errMsgId)),
- getString(FingerprintErrorDialog.getErrorTitle(errMsgId)),
- errMsgId
- )
- )
- progressViewModel.cancelEnrollment()
+ cancelEnrollment(true)
+ lifecycleScope.launch {
+ Log.d(TAG, "newDialog $errorMessage")
+ errorDialogViewModel.newDialog(errorMessage.msgId)
+ }
+ }
+
+ private fun onEnrollmentCanceled(canceledSignal: Any) {
+ Log.d(
+ TAG,
+ "onEnrollmentCanceled enrolling:$enrollingCancelSignal, canceled:$canceledSignal"
+ )
+ if (enrollingCancelSignal === canceledSignal) {
+ progressViewModel.canceledSignalLiveData.removeObserver(canceledSignalObserver)
+ progressViewModel.clearProgressLiveData()
+ if (enrollingViewModel.onBackPressed) {
+ enrollingViewModel.onCancelledDueToOnBackPressed()
+ } else if (enrollingViewModel.onSkipPressed) {
+ enrollingViewModel.onCancelledDueToOnSkipPressed()
+ }
}
}
@@ -345,6 +392,8 @@
}
val progress = getProgress(enrollmentProgress)
+ Log.d(TAG, "updateProgress($animate, $enrollmentProgress), old:${progressBar.progress}"
+ + ", new:$progress")
// Only clear the error when progress has been made.
// TODO (b/234772728) Add tests.
@@ -365,12 +414,12 @@
if (progress.steps == -1) {
return 0
}
- val displayProgress = Math.max(0, progress.steps + 1 - progress.remaining)
+ val displayProgress = 0.coerceAtLeast(progress.steps + 1 - progress.remaining)
return PROGRESS_BAR_MAX * displayProgress / (progress.steps + 1)
}
private fun showError(error: CharSequence) {
- enrollingSfpsView!!.let {
+ enrollingView!!.let {
it.headerText = error
it.headerTextView.contentDescription = error
GlifLayoutHelper(requireActivity(), it).setDescriptionText("")
@@ -425,7 +474,7 @@
}
private fun updateTitleAndDescription() {
- val helper = GlifLayoutHelper(requireActivity(), enrollingSfpsView!!)
+ val helper = GlifLayoutHelper(requireActivity(), enrollingView!!)
if (enrollingViewModel.isAccessibilityEnabled) {
enrollingViewModel.clearTalkback()
helper.glifLayout.descriptionTextView.accessibilityLiveRegion =
@@ -584,7 +633,7 @@
}
fun LottieAnimationView.applyLottieDynamicColor(context: Context, isError: Boolean) {
- addValueCallback<ColorFilter>(
+ addValueCallback(
KeyPath(".blue100", "**"),
LottieProperty.COLOR_FILTER
) {
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.kt
index a71c007..34b491d 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.kt
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.kt
@@ -17,8 +17,8 @@
import android.annotation.RawRes
import android.content.Context
+import android.hardware.biometrics.BiometricFingerprintConstants
import android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL
-import android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_CANCELED
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.os.Bundle
import android.util.Log
@@ -35,20 +35,25 @@
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieComposition
import com.airbnb.lottie.LottieCompositionFactory
import com.android.settings.R
-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
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
import com.android.settings.biometrics2.ui.widget.UdfpsEnrollView
import com.android.settingslib.display.DisplayDensityUtils
+import kotlinx.coroutines.launch
import kotlin.math.roundToInt
/**
@@ -68,6 +73,10 @@
private val progressViewModel: FingerprintEnrollProgressViewModel
get() = _progressViewModel!!
+ private var _errorDialogViewModel: FingerprintEnrollErrorDialogViewModel? = null
+ private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel
+ get() = _errorDialogViewModel!!
+
private var illustrationLottie: LottieAnimationView? = null
private var haveShownTipLottie = false
@@ -76,22 +85,22 @@
private var haveShownCenterLottie = false
private var haveShownGuideLottie = false
- private var enrollingUdfpsView: RelativeLayout? = null
+ private var enrollingView: RelativeLayout? = null
private val titleText: TextView
- get() = enrollingUdfpsView!!.findViewById<TextView>(R.id.suc_layout_title)!!
+ get() = enrollingView!!.findViewById(R.id.suc_layout_title)!!
private val subTitleText: TextView
- get() = enrollingUdfpsView!!.findViewById<TextView>(R.id.sud_layout_subtitle)!!
+ get() = enrollingView!!.findViewById(R.id.sud_layout_subtitle)!!
private val udfpsEnrollView: UdfpsEnrollView
- get() = enrollingUdfpsView!!.findViewById<UdfpsEnrollView>(R.id.udfps_animation_view)!!
+ get() = enrollingView!!.findViewById(R.id.udfps_animation_view)!!
private val skipBtn: Button
- get() = enrollingUdfpsView!!.findViewById<Button>(R.id.skip_btn)!!
+ get() = enrollingView!!.findViewById(R.id.skip_btn)!!
private val icon: ImageView
- get() = enrollingUdfpsView!!.findViewById<ImageView>(R.id.sud_layout_icon)!!
+ get() = enrollingView!!.findViewById(R.id.sud_layout_icon)!!
private val shouldShowLottie: Boolean
get() {
@@ -108,24 +117,33 @@
private var rotation = -1
+ private var enrollingCancelSignal: Any? = null
+
private val onSkipClickListener = View.OnClickListener { _: View? ->
enrollingViewModel.setOnSkipPressed()
- cancelEnrollment()
+ cancelEnrollment(false)
}
- private val progressObserver: Observer<EnrollmentProgress> =
- Observer<EnrollmentProgress> { progress: EnrollmentProgress? ->
- progress?.let { onEnrollmentProgressChange(it) }
+ private val progressObserver = Observer { progress: EnrollmentProgress? ->
+ if (progress != null && progress.steps >= 0) {
+ onEnrollmentProgressChange(progress)
}
+ }
- private val helpMessageObserver: Observer<EnrollmentStatusMessage> =
- Observer<EnrollmentStatusMessage> { helpMessage: EnrollmentStatusMessage? ->
- helpMessage?.let { onEnrollmentHelp(it) }
- }
- private val errorMessageObserver: Observer<EnrollmentStatusMessage> =
- Observer<EnrollmentStatusMessage> { errorMessage: EnrollmentStatusMessage? ->
- errorMessage?.let { onEnrollmentError(it) }
- }
+ private val helpMessageObserver = Observer { helpMessage: EnrollmentStatusMessage? ->
+ Log.d(TAG, "helpMessageObserver($helpMessage)")
+ helpMessage?.let { onEnrollmentHelp(it) }
+ }
+
+ private val errorMessageObserver = Observer { errorMessage: EnrollmentStatusMessage? ->
+ Log.d(TAG, "errorMessageObserver($errorMessage)")
+ errorMessage?.let { onEnrollmentError(it) }
+ }
+
+ private val canceledSignalObserver = Observer { canceledSignal: Any? ->
+ Log.d(TAG, "canceledSignalObserver($canceledSignal)")
+ canceledSignal?.let { onEnrollmentCanceled(it) }
+ }
private val acquireObserver =
Observer { isAcquiredGood: Boolean? -> isAcquiredGood?.let { onAcquired(it) } }
@@ -144,7 +162,7 @@
override fun handleOnBackPressed() {
isEnabled = false
enrollingViewModel.setOnBackPressed()
- cancelEnrollment()
+ cancelEnrollment(true)
}
}
@@ -156,6 +174,7 @@
_enrollingViewModel = provider[FingerprintEnrollEnrollingViewModel::class.java]
_rotationViewModel = provider[DeviceRotationViewModel::class.java]
_progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
+ _errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
}
super.onAttach(context)
requireActivity().onBackPressedDispatcher.addCallback(onBackPressedCallback)
@@ -172,7 +191,7 @@
): View = (inflater.inflate(
R.layout.udfps_enroll_enrolling_v2, container, false
) as RelativeLayout).also {
- enrollingUdfpsView = it
+ enrollingView = it
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -181,23 +200,78 @@
updateIllustrationLottie(rotation)
requireActivity().bindFingerprintEnrollEnrollingUdfpsView(
- view = enrollingUdfpsView!!,
+ view = enrollingView!!,
sensorProperties = enrollingViewModel.firstFingerprintSensorPropertiesInternal!!,
rotation = rotation,
onSkipClickListener = onSkipClickListener,
)
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ errorDialogViewModel.triggerRetryFlow.collect { retryEnrollment() }
+ }
+ }
}
+ private fun retryEnrollment() {
+ reattachUdfpsEnrollView()
+
+ startEnrollment()
+
+ updateProgress(false /* animate */, progressViewModel.progressLiveData.value!!)
+ progressViewModel.helpMessageLiveData.value.let {
+ if (it != null) {
+ onEnrollmentHelp(it)
+ } else {
+ updateTitleAndDescription()
+ }
+ }
+ }
override fun onStart() {
super.onStart()
- startEnrollment()
+ val isEnrolling = progressViewModel.isEnrolling
+ val isErrorDialogShown = errorDialogViewModel.isDialogShown
+ Log.d(TAG, "onStart(), isEnrolling:$isEnrolling, isErrorDialog:$isErrorDialogShown")
+ if (!isErrorDialogShown) {
+ startEnrollment()
+ }
+
updateProgress(false /* animate */, progressViewModel.progressLiveData.value!!)
- val msg: EnrollmentStatusMessage? = progressViewModel.helpMessageLiveData.value
- if (msg != null) {
- onEnrollmentHelp(msg)
- } else {
- updateTitleAndDescription()
+ progressViewModel.helpMessageLiveData.value.let {
+ if (it != null) {
+ onEnrollmentHelp(it)
+ } else {
+ updateTitleAndDescription()
+ }
+ }
+ }
+
+ private fun reattachUdfpsEnrollView() {
+ enrollingView!!.let {
+ val newUdfpsView = LayoutInflater.from(requireActivity()).inflate(
+ R.layout.udfps_enroll_enrolling_v2_udfps_view,
+ null
+ )
+ val index = it.indexOfChild(udfpsEnrollView)
+ val lp = udfpsEnrollView.layoutParams
+
+ it.removeView(udfpsEnrollView)
+ it.addView(newUdfpsView, index, lp)
+ udfpsEnrollView.setSensorProperties(
+ enrollingViewModel.firstFingerprintSensorPropertiesInternal
+ )
+ }
+
+ // Clear lottie status
+ haveShownTipLottie = false
+ haveShownLeftEdgeLottie = false
+ haveShownRightEdgeLottie = false
+ haveShownCenterLottie = false
+ haveShownGuideLottie = false
+ illustrationLottie?.let {
+ it.contentDescription = ""
+ it.visibility = View.GONE
}
}
@@ -213,18 +287,17 @@
override fun onStop() {
removeEnrollmentObservers()
- if (!activity!!.isChangingConfigurations && progressViewModel.isEnrolling) {
- progressViewModel.cancelEnrollment()
+ val isEnrolling = progressViewModel.isEnrolling
+ val isConfigChange = requireActivity().isChangingConfigurations
+ Log.d(TAG, "onStop(), enrolling:$isEnrolling isConfigChange:$isConfigChange")
+ if (isEnrolling && !isConfigChange) {
+ cancelEnrollment(false)
}
super.onStop()
}
private fun removeEnrollmentObservers() {
- preRemoveEnrollmentObservers()
progressViewModel.errorMessageLiveData.removeObserver(errorMessageObserver)
- }
-
- private fun preRemoveEnrollmentObservers() {
progressViewModel.progressLiveData.removeObserver(progressObserver)
progressViewModel.helpMessageLiveData.removeObserver(helpMessageObserver)
progressViewModel.acquireLiveData.removeObserver(acquireObserver)
@@ -232,16 +305,29 @@
progressViewModel.pointerUpLiveData.removeObserver(pointerUpObserver)
}
- private fun cancelEnrollment() {
- preRemoveEnrollmentObservers()
- progressViewModel.cancelEnrollment()
+ private fun cancelEnrollment(waitForLastCancelErrMsg: Boolean) {
+ if (!progressViewModel.isEnrolling) {
+ Log.d(TAG, "cancelEnrollment(), failed because isEnrolling is false")
+ return
+ }
+ removeEnrollmentObservers()
+ if (waitForLastCancelErrMsg) {
+ progressViewModel.canceledSignalLiveData.observe(this, canceledSignalObserver)
+ } else {
+ enrollingCancelSignal = null
+ }
+ val cancelResult: Boolean = progressViewModel.cancelEnrollment()
+ if (!cancelResult) {
+ Log.e(TAG, "cancelEnrollment(), failed to cancel enrollment")
+ }
}
private fun startEnrollment() {
- val startResult: Boolean =
- progressViewModel.startEnrollment(ENROLL_ENROLL)
- if (!startResult) {
+ enrollingCancelSignal = progressViewModel.startEnrollment(ENROLL_ENROLL)
+ if (enrollingCancelSignal == null) {
Log.e(TAG, "startEnrollment(), failed")
+ } else {
+ Log.d(TAG, "startEnrollment(), success")
}
progressViewModel.progressLiveData.observe(this, progressObserver)
progressViewModel.helpMessageLiveData.observe(this, helpMessageObserver)
@@ -256,17 +342,24 @@
Log.d(TAG, "Enrollment not started yet")
return
}
+
val progress = getProgress(enrollmentProgress)
- if (progressViewModel.progressLiveData.value!!.steps != -1) {
+ Log.d(TAG, "updateProgress($animate, $enrollmentProgress), progress:$progress")
+
+ if (enrollmentProgress.steps != -1) {
udfpsEnrollView.onEnrollmentProgress(
enrollmentProgress.remaining,
enrollmentProgress.steps
)
}
- if (animate) {
- animateProgress(progress)
- } else if (progress >= PROGRESS_BAR_MAX) {
- delayedFinishRunnable.run()
+
+ if (progress >= PROGRESS_BAR_MAX) {
+ if (animate) {
+ // Wait animations to finish, then proceed to next page
+ activity!!.mainThreadHandler.postDelayed(delayedFinishRunnable, 400L)
+ } else {
+ delayedFinishRunnable.run()
+ }
}
}
@@ -278,15 +371,8 @@
return PROGRESS_BAR_MAX * displayProgress / (progress.steps + 1)
}
- private fun animateProgress(progress: Int) {
- // UDFPS animations are owned by SystemUI
- if (progress >= PROGRESS_BAR_MAX) {
- // Wait for any animations in SysUI to finish, then proceed to next page
- activity!!.mainThreadHandler.postDelayed(delayedFinishRunnable, 400L)
- }
- }
-
private fun updateTitleAndDescription() {
+ Log.d(TAG, "updateTitleAndDescription($currentStage)")
when (currentStage) {
STAGE_CENTER -> {
titleText.setText(R.string.security_settings_fingerprint_enroll_repeat_title)
@@ -386,7 +472,7 @@
illustrationLottie = null
} else if (shouldShowLottie) {
illustrationLottie =
- enrollingUdfpsView!!.findViewById<LottieAnimationView>(R.id.illustration_lottie)
+ enrollingView!!.findViewById(R.id.illustration_lottie)
}
}
@@ -468,6 +554,7 @@
}
private fun onEnrollmentHelp(helpMessage: EnrollmentStatusMessage) {
+ Log.d(TAG, "onEnrollmentHelp($helpMessage)")
val helpStr: CharSequence = helpMessage.str
if (helpStr.isNotEmpty()) {
showError(helpStr)
@@ -476,25 +563,26 @@
}
private fun onEnrollmentError(errorMessage: EnrollmentStatusMessage) {
- removeEnrollmentObservers()
- if (enrollingViewModel.onBackPressed
- && errorMessage.msgId == FINGERPRINT_ERROR_CANCELED
- ) {
- enrollingViewModel.onCancelledDueToOnBackPressed()
- } else if (enrollingViewModel.onSkipPressed
- && errorMessage.msgId == FINGERPRINT_ERROR_CANCELED
- ) {
- enrollingViewModel.onCancelledDueToOnSkipPressed()
- } else {
- val errMsgId: Int = errorMessage.msgId
- enrollingViewModel.showErrorDialog(
- FingerprintEnrollEnrollingViewModel.ErrorDialogData(
- getString(FingerprintErrorDialog.getErrorMessage(errMsgId)),
- getString(FingerprintErrorDialog.getErrorTitle(errMsgId)),
- errMsgId
- )
- )
- progressViewModel.cancelEnrollment()
+ cancelEnrollment(true)
+ lifecycleScope.launch {
+ Log.d(TAG, "newDialog $errorMessage")
+ errorDialogViewModel.newDialog(errorMessage.msgId)
+ }
+ }
+
+ private fun onEnrollmentCanceled(canceledSignal: Any) {
+ Log.d(
+ TAG,
+ "onEnrollmentCanceled enrolling:$enrollingCancelSignal, canceled:$canceledSignal"
+ )
+ if (enrollingCancelSignal === canceledSignal) {
+ progressViewModel.canceledSignalLiveData.removeObserver(canceledSignalObserver)
+ progressViewModel.clearProgressLiveData()
+ if (enrollingViewModel.onBackPressed) {
+ enrollingViewModel.onCancelledDueToOnBackPressed()
+ } else if (enrollingViewModel.onSkipPressed) {
+ enrollingViewModel.onCancelledDueToOnSkipPressed()
+ }
}
}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollErrorDialog.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollErrorDialog.kt
new file mode 100644
index 0000000..882cbcf
--- /dev/null
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollErrorDialog.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright 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.biometrics2.ui.view
+
+import android.app.Dialog
+import android.content.Context
+import android.content.DialogInterface
+import android.hardware.biometrics.BiometricConstants
+import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_UNABLE_TO_PROCESS
+import android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.android.settings.R
+import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog.getErrorMessage
+import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog.getErrorTitle
+import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog.getSetupErrorMessage
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
+import kotlinx.coroutines.launch
+
+/**
+ * Fingerprint error dialog, will be shown when an error occurs during fingerprint enrollment.
+ */
+class FingerprintEnrollErrorDialog : DialogFragment() {
+
+ private val viewModel: FingerprintEnrollErrorDialogViewModel?
+ get() = activity?.let {
+ ViewModelProvider(it)[FingerprintEnrollErrorDialogViewModel::class.java]
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val errorMsgId: Int = requireArguments().getInt(KEY_ERROR_MSG_ID)
+ val okButtonSetResultAction =
+ if (errorMsgId == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT)
+ FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
+ else
+ FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
+ return requireActivity().bindFingerprintEnrollEnrollingErrorDialog(
+ errorMsgId = errorMsgId,
+ isSuw = viewModel!!.isSuw,
+ tryAgainButtonClickListener = { dialog: DialogInterface?, _: Int ->
+ activity?.lifecycleScope?.launch {
+ Log.d(TAG, "tryAgain flow")
+ viewModel?.triggerRetry()
+ dialog?.dismiss()
+ }
+ },
+ okButtonClickListener = { dialog: DialogInterface?, _: Int ->
+ activity?.lifecycleScope?.launch {
+ Log.d(TAG, "ok flow as $okButtonSetResultAction")
+ viewModel?.setResultAndFinish(okButtonSetResultAction)
+ dialog?.dismiss()
+ }
+ }
+ )
+ }
+
+ companion object {
+ private const val TAG = "FingerprintEnrollErrorDialog"
+ private const val KEY_ERROR_MSG_ID = "error_msg_id"
+
+ fun newInstance(errorMsgId: Int): FingerprintEnrollErrorDialog {
+ val dialog = FingerprintEnrollErrorDialog()
+ val args = Bundle()
+ args.putInt(KEY_ERROR_MSG_ID, errorMsgId)
+ dialog.arguments = args
+ return dialog
+ }
+ }
+}
+
+fun Context.bindFingerprintEnrollEnrollingErrorDialog(
+ errorMsgId: Int,
+ isSuw: Boolean,
+ tryAgainButtonClickListener: DialogInterface.OnClickListener,
+ okButtonClickListener: DialogInterface.OnClickListener
+): AlertDialog = AlertDialog.Builder(this)
+ .setTitle(getString(getErrorTitle(errorMsgId)))
+ .setMessage(
+ getString(
+ if (isSuw)
+ getSetupErrorMessage(errorMsgId)
+ else
+ getErrorMessage(errorMsgId)
+ )
+ )
+ .setCancelable(false).apply {
+ if (errorMsgId == FINGERPRINT_ERROR_UNABLE_TO_PROCESS) {
+ setPositiveButton(
+ R.string.security_settings_fingerprint_enroll_dialog_try_again,
+ tryAgainButtonClickListener
+ )
+ setNegativeButton(
+ R.string.security_settings_fingerprint_enroll_dialog_ok,
+ okButtonClickListener
+ )
+ } else {
+ setPositiveButton(
+ R.string.security_settings_fingerprint_enroll_dialog_ok,
+ okButtonClickListener
+ )
+ }
+ }
+ .create()
+ .apply { setCanceledOnTouchOutside(false) }
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindRfpsFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindRfpsFragment.kt
index 8f47abc..ee5ca56 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindRfpsFragment.kt
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindRfpsFragment.kt
@@ -16,7 +16,7 @@
package com.android.settings.biometrics2.ui.view
import android.content.Context
-import android.hardware.fingerprint.FingerprintManager
+import android.hardware.biometrics.BiometricFingerprintConstants
import android.hardware.fingerprint.FingerprintManager.ENROLL_FIND_SENSOR
import android.os.Bundle
import android.util.Log
@@ -26,19 +26,25 @@
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.android.settings.R
import com.android.settings.biometrics.fingerprint.FingerprintFindSensorAnimation
import com.android.settings.biometrics2.ui.model.EnrollmentProgress
import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage
import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton
import com.google.android.setupdesign.GlifLayout
+import kotlinx.coroutines.launch
/**
* Fragment explaining the side fingerprint sensor location for fingerprint enrollment.
@@ -68,6 +74,10 @@
private val rotationViewModel: DeviceRotationViewModel
get() = _rotationViewModel!!
+ private var _errorDialogViewModel: FingerprintEnrollErrorDialogViewModel? = null
+ private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel
+ get() = _errorDialogViewModel!!
+
private var findRfpsView: GlifLayout? = null
private val onSkipClickListener =
@@ -75,33 +85,25 @@
private var animation: FingerprintFindSensorAnimation? = null
+ private var enrollingCancelSignal: Any? = null
+
@Surface.Rotation
private var lastRotation = -1
- private val rotationObserver = Observer { rotation: Int? ->
- if (DEBUG) {
- Log.d(TAG, "rotationObserver $rotation")
+ private val progressObserver = Observer { progress: EnrollmentProgress? ->
+ if (progress != null && !progress.isInitialStep) {
+ cancelEnrollment(true)
}
- rotation?.let { onRotationChanged(it) }
}
- private val progressObserver: Observer<EnrollmentProgress> =
- Observer<EnrollmentProgress> { progress: EnrollmentProgress? ->
- if (DEBUG) {
- Log.d(TAG, "progressObserver($progress)")
- }
- if (progress != null && !progress.isInitialStep) {
- stopLookingForFingerprint(true)
- }
- }
+ private val errorMessageObserver = Observer { errorMessage: EnrollmentStatusMessage? ->
+ Log.d(TAG, "errorMessageObserver($errorMessage)")
+ errorMessage?.let { onEnrollmentError(it) }
+ }
- private val lastCancelMessageObserver: Observer<EnrollmentStatusMessage> =
- Observer<EnrollmentStatusMessage> { errorMessage: EnrollmentStatusMessage? ->
- if (DEBUG) {
- Log.d(TAG, "lastCancelMessageObserver($errorMessage)")
- }
- errorMessage?.let { onLastCancelMessage(it) }
- }
+ private val canceledSignalObserver = Observer { canceledSignal: Any? ->
+ canceledSignal?.let { onEnrollmentCanceled(it) }
+ }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@@ -129,28 +131,40 @@
view = findRfpsView!!,
onSkipClickListener = onSkipClickListener
)
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ errorDialogViewModel.triggerRetryFlow.collect { retryLookingForFingerprint() }
+ }
+ }
+ }
+
+ private fun retryLookingForFingerprint() {
+ startEnrollment()
+ animation?.let {
+ Log.d(TAG, "retry, start animation")
+ it.startAnimation()
+ }
}
override fun onStart() {
super.onStart()
- if (DEBUG) {
- Log.d(
- TAG,
- "onStart(), start looking for fingerprint, animation exist:${animation != null}"
- )
+ val isErrorDialogShown = errorDialogViewModel.isDialogShown
+ Log.d(TAG, "onStart(), isEnrolling:${progressViewModel.isEnrolling}"
+ + ", isErrorDialog:$isErrorDialogShown")
+ if (!isErrorDialogShown) {
+ startEnrollment()
}
- startLookingForFingerprint()
}
override fun onResume() {
val rotationLiveData: LiveData<Int> = rotationViewModel.liveData
lastRotation = rotationLiveData.value!!
- rotationLiveData.observe(this, rotationObserver)
- animation?.let {
- if (DEBUG) {
+ if (!errorDialogViewModel.isDialogShown) {
+ animation?.let {
Log.d(TAG, "onResume(), start animation")
+ it.startAnimation()
}
- it.startAnimation()
}
super.onResume()
}
@@ -167,72 +181,68 @@
override fun onStop() {
super.onStop()
- val isEnrolling: Boolean = progressViewModel.isEnrolling
- if (DEBUG) {
- Log.d(
- TAG,
- "onStop(), current enrolling: ${isEnrolling}, animation exist:${animation != null}"
- )
- }
- if (isEnrolling) {
- stopLookingForFingerprint(false)
+ removeEnrollmentObservers()
+ val isEnrolling = progressViewModel.isEnrolling
+ val isConfigChange = requireActivity().isChangingConfigurations
+ Log.d(TAG, "onStop(), enrolling:$isEnrolling isConfigChange:$isConfigChange")
+ if (isEnrolling && !isConfigChange) {
+ cancelEnrollment(false)
}
}
- private fun startLookingForFingerprint() {
- if (progressViewModel.isEnrolling) {
- Log.d(
- TAG,
- "startLookingForFingerprint(), failed because isEnrolling is true before starting"
- )
- return
- }
- val startResult: Boolean = progressViewModel.startEnrollment(ENROLL_FIND_SENSOR)
- if (!startResult) {
- Log.e(TAG, "startLookingForFingerprint(), failed to start enrollment")
+ private fun removeEnrollmentObservers() {
+ progressViewModel.progressLiveData.removeObserver(progressObserver)
+ progressViewModel.helpMessageLiveData.removeObserver(errorMessageObserver)
+ }
+
+ private fun startEnrollment() {
+ enrollingCancelSignal = progressViewModel.startEnrollment(ENROLL_FIND_SENSOR)
+ if (enrollingCancelSignal == null) {
+ Log.e(TAG, "startEnrollment(), failed to start enrollment")
+ } else {
+ Log.d(TAG, "startEnrollment(), success")
}
progressViewModel.progressLiveData.observe(this, progressObserver)
+ progressViewModel.errorMessageLiveData.observe(this, errorMessageObserver)
}
- private fun stopLookingForFingerprint(waitForLastCancelErrMsg: Boolean) {
+ private fun cancelEnrollment(waitForLastCancelErrMsg: Boolean) {
if (!progressViewModel.isEnrolling) {
- Log.d(
- TAG,
- "stopLookingForFingerprint(), failed because isEnrolling is false before stopping"
- )
+ Log.d(TAG, "cancelEnrollment(), failed because isEnrolling is false")
return
}
+ removeEnrollmentObservers()
if (waitForLastCancelErrMsg) {
- progressViewModel.clearErrorMessageLiveData() // Prevent got previous error message
- progressViewModel.errorMessageLiveData.observe(this, lastCancelMessageObserver)
+ progressViewModel.canceledSignalLiveData.observe(this, canceledSignalObserver)
+ } else {
+ enrollingCancelSignal = null
}
- progressViewModel.progressLiveData.removeObserver(progressObserver)
val cancelResult: Boolean = progressViewModel.cancelEnrollment()
if (!cancelResult) {
- Log.e(TAG, "stopLookingForFingerprint(), failed to cancel enrollment")
+ Log.e(TAG, "cancelEnrollment(), failed to cancel enrollment")
}
}
- private fun onRotationChanged(@Surface.Rotation newRotation: Int) {
- if (DEBUG) {
- Log.d(TAG, "onRotationChanged() from $lastRotation to $newRotation")
- }
- if (newRotation % 2 != lastRotation % 2) {
- // Fragment is going to be recreated, just stopLookingForFingerprint() here.
- stopLookingForFingerprint(true)
+ private fun onEnrollmentError(errorMessage: EnrollmentStatusMessage) {
+ cancelEnrollment(false)
+ lifecycleScope.launch {
+ Log.d(TAG, "newDialogFlow as $errorMessage")
+ errorDialogViewModel.newDialog(errorMessage.msgId)
}
}
- private fun onLastCancelMessage(errorMessage: EnrollmentStatusMessage) {
- if (errorMessage.msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+ private fun onEnrollmentCanceled(canceledSignal: Any) {
+ Log.d(
+ TAG,
+ "onEnrollmentCanceled enrolling:$enrollingCancelSignal, canceled:$canceledSignal"
+ )
+ if (enrollingCancelSignal === canceledSignal) {
val progress: EnrollmentProgress? = progressViewModel.progressLiveData.value
+ progressViewModel.canceledSignalLiveData.removeObserver(canceledSignalObserver)
progressViewModel.clearProgressLiveData()
- progressViewModel.errorMessageLiveData.removeObserver(lastCancelMessageObserver)
if (progress != null && !progress.isInitialStep) {
viewModel.onStartButtonClick()
}
- } else {
- Log.e(TAG, "errorMessageObserver($errorMessage)")
}
}
@@ -251,6 +261,7 @@
_viewModel = provider[FingerprintEnrollFindSensorViewModel::class.java]
_progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
_rotationViewModel = provider[DeviceRotationViewModel::class.java]
+ _errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
}
super.onAttach(context)
}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.kt
index 16dfefa..ab31dbc 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.kt
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.kt
@@ -16,7 +16,8 @@
package com.android.settings.biometrics2.ui.view
import android.content.Context
-import android.hardware.fingerprint.FingerprintManager
+import android.hardware.biometrics.BiometricFingerprintConstants
+import android.hardware.fingerprint.FingerprintManager.ENROLL_FIND_SENSOR
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@@ -26,21 +27,27 @@
import androidx.annotation.RawRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.lottie.LottieAnimationView
import com.android.settings.R
import com.android.settings.biometrics2.ui.model.EnrollmentProgress
import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage
import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel
import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
import com.android.settingslib.widget.LottieColorUtils
import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton
import com.google.android.setupdesign.GlifLayout
+import kotlinx.coroutines.launch
/**
* Fragment explaining the side fingerprint sensor location for fingerprint enrollment.
@@ -75,41 +82,41 @@
private val foldedViewModel: DeviceFoldedViewModel
get() = _foldedViewModel!!
+ private var _errorDialogViewModel: FingerprintEnrollErrorDialogViewModel? = null
+ private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel
+ get() = _errorDialogViewModel!!
+
private var findSfpsView: GlifLayout? = null
private val onSkipClickListener =
View.OnClickListener { _: View? -> viewModel.onSkipButtonClick() }
private val illustrationLottie: LottieAnimationView
- get() = findSfpsView!!.findViewById<LottieAnimationView>(R.id.illustration_lottie)!!
+ get() = findSfpsView!!.findViewById(R.id.illustration_lottie)!!
+
+ private var enrollingCancelSignal: Any? = null
@Surface.Rotation
private var animationRotation = -1
private val rotationObserver = Observer { rotation: Int? ->
- if (DEBUG) {
- Log.d(TAG, "rotationObserver $rotation")
- }
rotation?.let { onRotationChanged(it) }
}
- private val progressObserver: Observer<EnrollmentProgress> =
- Observer<EnrollmentProgress> { progress: EnrollmentProgress? ->
- if (DEBUG) {
- Log.d(TAG, "progressObserver($progress)")
- }
- if (progress != null && !progress.isInitialStep) {
- stopLookingForFingerprint(true)
- }
+ private val progressObserver = Observer { progress: EnrollmentProgress? ->
+ if (progress != null && !progress.isInitialStep) {
+ cancelEnrollment(true)
}
+ }
- private val lastCancelMessageObserver: Observer<EnrollmentStatusMessage> =
- Observer<EnrollmentStatusMessage> { errorMessage: EnrollmentStatusMessage? ->
- if (DEBUG) {
- Log.d(TAG, "lastCancelMessageObserver($errorMessage)")
- }
- errorMessage?.let { onLastCancelMessage(it) }
- }
+ private val errorMessageObserver = Observer{ errorMessage: EnrollmentStatusMessage? ->
+ Log.d(TAG, "errorMessageObserver($errorMessage)")
+ errorMessage?.let { onEnrollmentError(it) }
+ }
+
+ private val canceledSignalObserver = Observer { canceledSignal: Any? ->
+ canceledSignal?.let { onEnrollmentCanceled(it) }
+ }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@@ -128,16 +135,21 @@
view = findSfpsView!!,
onSkipClickListener = onSkipClickListener
)
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ errorDialogViewModel.triggerRetryFlow.collect { startEnrollment() }
+ }
+ }
}
override fun onStart() {
super.onStart()
- val isEnrolling: Boolean = progressViewModel.isEnrolling
- if (DEBUG) {
- Log.d(TAG, "onStart(), isEnrolling:$isEnrolling")
- }
- if (!isEnrolling) {
- startLookingForFingerprint()
+ val isErrorDialogShown = errorDialogViewModel.isDialogShown
+ Log.d(TAG, "onStart(), isEnrolling:${progressViewModel.isEnrolling}"
+ + ", isErrorDialog:$isErrorDialogShown")
+ if (!isErrorDialogShown) {
+ startEnrollment()
}
}
@@ -155,51 +167,44 @@
override fun onStop() {
super.onStop()
- val isEnrolling: Boolean = progressViewModel.isEnrolling
- if (DEBUG) {
- Log.d(TAG, "onStop(), isEnrolling:$isEnrolling")
- }
- if (isEnrolling) {
- stopLookingForFingerprint(false)
+ val isEnrolling = progressViewModel.isEnrolling
+ val isConfigChange = requireActivity().isChangingConfigurations
+ Log.d(TAG, "onStop(), enrolling:$isEnrolling isConfigChange:$isConfigChange")
+ if (isEnrolling && !isConfigChange) {
+ cancelEnrollment(false)
}
}
- private fun startLookingForFingerprint() {
- if (progressViewModel.isEnrolling) {
- Log.d(
- TAG,
- "startLookingForFingerprint(), failed because isEnrolling is true before starting"
- )
- return
- }
- progressViewModel.clearProgressLiveData()
- progressViewModel.progressLiveData.observe(this, progressObserver)
- val startResult: Boolean =
- progressViewModel.startEnrollment(FingerprintManager.ENROLL_FIND_SENSOR)
- if (!startResult) {
- Log.e(TAG, "startLookingForFingerprint(), failed to start enrollment")
- }
- }
-
- private fun stopLookingForFingerprint(waitForLastCancelErrMsg: Boolean) {
- if (!progressViewModel.isEnrolling) {
- Log.d(
- TAG, "stopLookingForFingerprint(), failed because isEnrolling is false before"
- + " stopping"
- )
- return
- }
- if (waitForLastCancelErrMsg) {
- progressViewModel.clearErrorMessageLiveData() // Prevent got previous error message
- progressViewModel.errorMessageLiveData.observe(
- this,
- lastCancelMessageObserver
- )
- }
+ private fun removeEnrollmentObservers() {
+ progressViewModel.errorMessageLiveData.removeObserver(errorMessageObserver)
progressViewModel.progressLiveData.removeObserver(progressObserver)
+ }
+
+ private fun startEnrollment() {
+ enrollingCancelSignal = progressViewModel.startEnrollment(ENROLL_FIND_SENSOR)
+ if (enrollingCancelSignal == null) {
+ Log.e(TAG, "startEnrollment(), failed to start enrollment")
+ } else {
+ Log.d(TAG, "startEnrollment(), success")
+ }
+ progressViewModel.progressLiveData.observe(this, progressObserver)
+ progressViewModel.errorMessageLiveData.observe(this, errorMessageObserver)
+ }
+
+ private fun cancelEnrollment(waitForLastCancelErrMsg: Boolean) {
+ if (!progressViewModel.isEnrolling) {
+ Log.d(TAG, "cancelEnrollment(), failed because isEnrolling is false")
+ return
+ }
+ removeEnrollmentObservers()
+ if (waitForLastCancelErrMsg) {
+ progressViewModel.canceledSignalLiveData.observe(this, canceledSignalObserver)
+ } else {
+ enrollingCancelSignal = null
+ }
val cancelResult: Boolean = progressViewModel.cancelEnrollment()
if (!cancelResult) {
- Log.e(TAG, "stopLookingForFingerprint(), failed to cancel enrollment")
+ Log.e(TAG, "cancelEnrollment(), failed to cancel enrollment")
}
}
@@ -210,34 +215,39 @@
if ((newRotation + 2) % 4 == animationRotation) {
// Fragment not changed, we just need to play correct rotation animation
playLottieAnimation(newRotation)
- } else if (newRotation % 2 != animationRotation % 2) {
- // Fragment is going to be recreated, just stopLookingForFingerprint() here.
- stopLookingForFingerprint(true)
}
}
- private fun onLastCancelMessage(errorMessage: EnrollmentStatusMessage) {
- if (errorMessage.msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+ private fun onEnrollmentError(errorMessage: EnrollmentStatusMessage) {
+ progressViewModel.cancelEnrollment()
+ lifecycleScope.launch {
+ Log.d(TAG, "newDialogFlow as $errorMessage")
+ errorDialogViewModel.newDialog(errorMessage.msgId)
+ }
+ }
+
+ private fun onEnrollmentCanceled(canceledSignal: Any) {
+ Log.d(
+ TAG,
+ "onEnrollmentCanceled enrolling:$enrollingCancelSignal, canceled:$canceledSignal"
+ )
+ if (enrollingCancelSignal === canceledSignal) {
val progress: EnrollmentProgress? = progressViewModel.progressLiveData.value
+ progressViewModel.canceledSignalLiveData.removeObserver(canceledSignalObserver)
progressViewModel.clearProgressLiveData()
- progressViewModel.errorMessageLiveData.removeObserver(lastCancelMessageObserver)
if (progress != null && !progress.isInitialStep) {
viewModel.onStartButtonClick()
}
- } else {
- Log.e(TAG, "errorMessageObserver($errorMessage)")
}
}
private fun playLottieAnimation(@Surface.Rotation rotation: Int) {
@RawRes val animationRawRes = getSfpsLottieAnimationRawRes(rotation)
- if (DEBUG) {
- Log.d(
- TAG,
- "play lottie animation $animationRawRes, previous rotation:$animationRotation"
- + ", new rotation:" + rotation
- )
- }
+ Log.d(
+ TAG,
+ "play lottie animation $animationRawRes, previous rotation:$animationRotation"
+ + ", new rotation:" + rotation
+ )
animationRotation = rotation
illustrationLottie.setAnimation(animationRawRes)
LottieColorUtils.applyDynamicColors(activity, illustrationLottie)
@@ -247,7 +257,7 @@
@RawRes
private fun getSfpsLottieAnimationRawRes(@Surface.Rotation rotation: Int): Int {
- val isFolded = java.lang.Boolean.FALSE != foldedViewModel.getLiveData().getValue()
+ val isFolded = java.lang.Boolean.FALSE != foldedViewModel.liveData.value
return when (rotation) {
Surface.ROTATION_90 ->
if (isFolded)
@@ -278,6 +288,7 @@
_progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
_rotationViewModel = provider[DeviceRotationViewModel::class.java]
_foldedViewModel = provider[DeviceFoldedViewModel::class.java]
+ _errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
}
super.onAttach(context)
}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt
index fd76198..12aac6a 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt
@@ -32,8 +32,11 @@
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
import com.android.settings.R
@@ -53,15 +56,12 @@
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator
import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintErrorDialogAction
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP
@@ -78,8 +78,11 @@
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FingerprintEnrollIntroAction
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.google.android.setupdesign.util.ThemeHelper
+import kotlinx.coroutines.launch
/**
* Fingerprint enrollment activity implementation
@@ -103,6 +106,30 @@
viewModelProvider[AutoCredentialViewModel::class.java]
}
+ private val introViewModel: FingerprintEnrollIntroViewModel by lazy {
+ viewModelProvider[FingerprintEnrollIntroViewModel::class.java]
+ }
+
+ private val findSensorViewModel: FingerprintEnrollFindSensorViewModel by lazy {
+ viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
+ }
+
+ private val progressViewModel: FingerprintEnrollProgressViewModel by lazy {
+ viewModelProvider[FingerprintEnrollProgressViewModel::class.java]
+ }
+
+ private val enrollingViewModel: FingerprintEnrollEnrollingViewModel by lazy {
+ viewModelProvider[FingerprintEnrollEnrollingViewModel::class.java]
+ }
+
+ private val finishViewModel: FingerprintEnrollFinishViewModel by lazy {
+ viewModelProvider[FingerprintEnrollFinishViewModel::class.java]
+ }
+
+ private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel by lazy {
+ viewModelProvider[FingerprintEnrollErrorDialogViewModel::class.java]
+ }
+
private val introActionObserver: Observer<Int> = Observer<Int> { action ->
if (DEBUG) {
Log.d(TAG, "introActionObserver($action)")
@@ -124,26 +151,6 @@
action?.let { onEnrollingAction(it) }
}
- private val enrollingErrorDialogObserver: Observer<ErrorDialogData> =
- Observer<ErrorDialogData> { data ->
- if (DEBUG) {
- Log.d(TAG, "enrollingErrorDialogObserver($data)")
- }
- data?.let {
- FingerprintEnrollEnrollingErrorDialog().show(
- supportFragmentManager,
- ENROLLING_ERROR_DIALOG_TAG
- )
- }
- }
-
- private val enrollingErrorDialogActionObserver: Observer<Int> = Observer<Int> { action ->
- if (DEBUG) {
- Log.d(TAG, "enrollingErrorDialogActionObserver($action)")
- }
- action?.let { onEnrollingErrorDialogAction(it) }
- }
-
private val finishActionObserver: Observer<Int> = Observer<Int> { action ->
if (DEBUG) {
Log.d(TAG, "finishActionObserver($action)")
@@ -218,6 +225,33 @@
autoCredentialViewModel.generateChallengeFailedLiveData.observe(this) {
_: Boolean -> onGenerateChallengeFailed()
}
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ errorDialogViewModel.newDialogFlow.collect {
+ Log.d(TAG, "newErrorDialogFlow($it)")
+ FingerprintEnrollErrorDialog.newInstance(it).show(
+ supportFragmentManager,
+ ERROR_DIALOG_TAG
+ )
+ }
+ }
+ }
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ errorDialogViewModel.setResultFlow.collect {
+ Log.d(TAG, "errorDialogSetResultFlow($it)")
+ when (it) {
+ FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH -> onSetActivityResult(
+ ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null)
+ )
+
+ FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT -> onSetActivityResult(
+ ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null)
+ )
+ }
+ }
+ }
+ }
}
private fun startFragment(fragmentClass: Class<out Fragment>, tag: String) {
@@ -252,7 +286,7 @@
if (request.isSkipIntro || request.isSkipFindSensor) {
return
}
- viewModelProvider[FingerprintEnrollIntroViewModel::class.java].let {
+ introViewModel.let {
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
// recreate, like press 'Agree' then press 'back' in FingerprintEnrollFindSensor
// activity.
@@ -264,8 +298,7 @@
// We need to make sure token is valid before entering find sensor page
private fun startFindSensorFragment() {
// Always setToken into progressViewModel even it is not necessary action for UDFPS
- viewModelProvider[FingerprintEnrollProgressViewModel::class.java]
- .setToken(autoCredentialViewModel.token)
+ progressViewModel.setToken(autoCredentialViewModel.token)
attachFindSensorViewModel()
val fragmentClass: Class<out Fragment> = if (viewModel.canAssumeUdfps()) {
FingerprintEnrollFindUdfpsFragment::class.java
@@ -281,7 +314,7 @@
if (viewModel.request.isSkipFindSensor) {
return
}
- viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java].let {
+ findSensorViewModel.let {
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
// recreate, like press 'Start' then press 'back' in FingerprintEnrollEnrolling
// activity.
@@ -292,8 +325,7 @@
private fun startEnrollingFragment() {
// Always setToken into progressViewModel even it is not necessary action for SFPS or RFPS
- viewModelProvider[FingerprintEnrollProgressViewModel::class.java]
- .setToken(autoCredentialViewModel.token)
+ progressViewModel.setToken(autoCredentialViewModel.token)
attachEnrollingViewModel()
val fragmentClass: Class<out Fragment> = if (viewModel.canAssumeUdfps()) {
FingerprintEnrollEnrollingUdfpsFragment::class.java
@@ -306,14 +338,9 @@
}
private fun attachEnrollingViewModel() {
- viewModelProvider[FingerprintEnrollEnrollingViewModel::class.java].let {
+ enrollingViewModel.let {
it.clearActionLiveData()
it.actionLiveData.observe(this, enrollingActionObserver)
- it.errorDialogLiveData.observe(this, enrollingErrorDialogObserver)
- it.errorDialogActionLiveData.observe(
- this,
- enrollingErrorDialogActionObserver
- )
}
}
@@ -374,7 +401,7 @@
}
private fun attachFinishViewModel() {
- viewModelProvider[FingerprintEnrollFinishViewModel::class.java].let {
+ finishViewModel.let {
it.clearActionLiveData()
it.actionLiveData.observe(this, finishActionObserver)
}
@@ -520,18 +547,6 @@
}
}
- private fun onEnrollingErrorDialogAction(@FingerprintErrorDialogAction action: Int) {
- when (action) {
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH -> onSetActivityResult(
- ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null)
- )
-
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT -> onSetActivityResult(
- ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null)
- )
- }
- }
-
private fun onFinishAction(@FingerprintEnrollFinishAction action: Int) {
when (action) {
FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK -> {
@@ -623,12 +638,13 @@
companion object {
private const val DEBUG = false
private const val TAG = "FingerprintEnrollmentActivity"
+ protected const val LAUNCH_CONFIRM_LOCK_ACTIVITY = 1
+
private const val INTRO_TAG = "intro"
private const val FIND_SENSOR_TAG = "find-sensor"
private const val ENROLLING_TAG = "enrolling"
private const val FINISH_TAG = "finish"
private const val SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog"
- private const val ENROLLING_ERROR_DIALOG_TAG = "enrolling-error-dialog"
- protected const val LAUNCH_CONFIRM_LOCK_ACTIVITY = 1
+ private const val ERROR_DIALOG_TAG = "error-dialog"
}
}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/DeviceRotationViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/DeviceRotationViewModel.java
index 3bed9fb..07fe275 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/DeviceRotationViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/DeviceRotationViewModel.java
@@ -59,9 +59,7 @@
@Override
public void onDisplayChanged(int displayId) {
final int rotation = getRotation();
- if (DEBUG) {
- Log.d(TAG, "onDisplayChanged(" + displayId + "), rotation:" + rotation);
- }
+ Log.d(TAG, "onDisplayChanged(" + displayId + "), rotation:" + rotation);
mLiveData.postValue(rotation);
}
};
@@ -98,10 +96,11 @@
* Returns RotationLiveData
*/
public LiveData<Integer> getLiveData() {
- if (mLiveData.getValue() == null) {
- // Init data here because if we set it through getDisplay().getRotation() or through
- // getDisplay().getDisplayInfo() in constructor(), we always get incorrect value.
- mLiveData.setValue(getRotation());
+ final Integer lastRotation = mLiveData.getValue();
+ @Surface.Rotation int newRotation = getRotation();
+ if (lastRotation == null || lastRotation != newRotation) {
+ Log.d(TAG, "getLiveData, update rotation from " + lastRotation + " to " + newRotation);
+ mLiveData.setValue(newRotation);
}
return mLiveData;
}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
index e2b2ee2..eba6a15 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
@@ -73,29 +73,11 @@
@IntDef(prefix = { "FINGERPRINT_ENROLL_ENROLLING_ACTION_" }, value = {
FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE,
FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG,
- FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP,
- FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
+ FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP
})
@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;
-
- @IntDef(prefix = { "FINGERPRINT_ERROR_DIALOG_ACTION_" }, value = {
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH,
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface FingerprintErrorDialogAction {}
-
private final int mUserId;
private boolean mOnBackPressed;
private boolean mOnSkipPressed;
@@ -104,11 +86,12 @@
private final Vibrator mVibrator;
private final MutableLiveData<Integer> mActionLiveData = new MutableLiveData<>();
- private final MutableLiveData<ErrorDialogData> mErrorDialogLiveData = new MutableLiveData<>();
- private final MutableLiveData<Integer> mErrorDialogActionLiveData = new MutableLiveData<>();
- public FingerprintEnrollEnrollingViewModel(@NonNull Application application,
- int userId, @NonNull FingerprintRepository fingerprintRepository) {
+ public FingerprintEnrollEnrollingViewModel(
+ @NonNull Application application,
+ int userId,
+ @NonNull FingerprintRepository fingerprintRepository
+ ) {
super(application);
mUserId = userId;
mFingerprintRepository = fingerprintRepository;
@@ -116,21 +99,6 @@
mVibrator = application.getSystemService(Vibrator.class);
}
- /**
- * Notifies activity to show error dialog
- */
- public void showErrorDialog(@NonNull ErrorDialogData errorDialogData) {
- mErrorDialogLiveData.postValue(errorDialogData);
- }
-
- public LiveData<ErrorDialogData> getErrorDialogLiveData() {
- return mErrorDialogLiveData;
- }
-
- public LiveData<Integer> getErrorDialogActionLiveData() {
- return mErrorDialogActionLiveData;
- }
-
public LiveData<Integer> getActionLiveData() {
return mActionLiveData;
}
@@ -142,16 +110,6 @@
mActionLiveData.setValue(null);
}
- /**
- * Saves new user dialog action to mErrorDialogActionLiveData
- */
- public void onErrorDialogAction(@FingerprintErrorDialogAction int action) {
- if (DEBUG) {
- Log.d(TAG, "onErrorDialogAction(" + action + ")");
- }
- mErrorDialogActionLiveData.postValue(action);
- }
-
public boolean getOnSkipPressed() {
return mOnSkipPressed;
}
@@ -164,7 +122,7 @@
}
/**
- * Enrolling is cacelled because user clicks skip
+ * Enrolling is cancelled because user clicks skip
*/
public void onCancelledDueToOnSkipPressed() {
final int action = FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
@@ -287,38 +245,4 @@
public FingerprintSensorPropertiesInternal getFirstFingerprintSensorPropertiesInternal() {
return mFingerprintRepository.getFirstFingerprintSensorPropertiesInternal();
}
-
- /**
- * 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 getClass().getSimpleName() + "@" + Integer.toHexString(hashCode())
- + "{id:" + mErrMsgId + "}";
- }
- }
}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModel.kt b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModel.kt
new file mode 100644
index 0000000..b154fe7
--- /dev/null
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModel.kt
@@ -0,0 +1,51 @@
+package com.android.settings.biometrics2.ui.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import kotlinx.atomicfu.AtomicBoolean
+import kotlinx.atomicfu.atomic
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+
+class FingerprintEnrollErrorDialogViewModel(
+ application: Application,
+ val isSuw: Boolean
+): AndroidViewModel(application) {
+
+ private val _isDialogShown: AtomicBoolean = atomic(false)
+ val isDialogShown: Boolean
+ get() = _isDialogShown.value
+
+ private val _newDialogFlow = MutableSharedFlow<Int>()
+ val newDialogFlow: SharedFlow<Int>
+ get() = _newDialogFlow.asSharedFlow()
+
+ private val _triggerRetryFlow = MutableSharedFlow<Any>()
+ val triggerRetryFlow: SharedFlow<Any>
+ get() = _triggerRetryFlow.asSharedFlow()
+
+ private val _setResultFlow = MutableSharedFlow<FingerprintErrorDialogSetResultAction>()
+ val setResultFlow: SharedFlow<FingerprintErrorDialogSetResultAction>
+ get() = _setResultFlow.asSharedFlow()
+
+ suspend fun newDialog(errorMsgId: Int) {
+ _isDialogShown.compareAndSet(expect = false, update = true)
+ _newDialogFlow.emit(errorMsgId)
+ }
+
+ suspend fun triggerRetry() {
+ _isDialogShown.compareAndSet(expect = true, update = false)
+ _triggerRetryFlow.emit(Any())
+ }
+
+ suspend fun setResultAndFinish(action: FingerprintErrorDialogSetResultAction) {
+ _isDialogShown.compareAndSet(expect = true, update = false)
+ _setResultFlow.emit(action)
+ }
+}
+
+enum class FingerprintErrorDialogSetResultAction {
+ FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH,
+ FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
+}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
index 7074288..9b25ee8 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
@@ -16,6 +16,7 @@
package com.android.settings.biometrics2.ui.viewmodel;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_CANCELED;
import static android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL;
import static com.android.settings.biometrics2.ui.model.EnrollmentProgress.INITIAL_REMAINING;
@@ -41,6 +42,8 @@
import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
+import java.util.LinkedList;
+
/**
* Progress ViewModel handles the state around biometric enrollment. It manages the state of
* enrollment throughout the activity lifecycle so the app can continue after an event like
@@ -57,6 +60,7 @@
new MutableLiveData<>();
private final MutableLiveData<EnrollmentStatusMessage> mErrorMessageLiveData =
new MutableLiveData<>();
+ private final MutableLiveData<Object> mCanceledSignalLiveData = new MutableLiveData<>();
private final MutableLiveData<Boolean> mAcquireLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mPointerDownLiveData = new MutableLiveData<>();
private final MutableLiveData<Integer> mPointerUpLiveData = new MutableLiveData<>();
@@ -66,6 +70,8 @@
private final FingerprintUpdater mFingerprintUpdater;
@Nullable private CancellationSignal mCancellationSignal = null;
+ @NonNull private final LinkedList<CancellationSignal> mCancelingSignalQueue =
+ new LinkedList<>();
private final EnrollmentCallback mEnrollmentCallback = new EnrollmentCallback() {
@Override
@@ -91,10 +97,13 @@
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
- if (DEBUG) {
- Log.d(TAG, "onEnrollmentError(" + errMsgId + ", " + errString + ")");
+ Log.d(TAG, "onEnrollmentError(" + errMsgId + ", " + errString
+ + "), cancelingQueueSize:" + mCancelingSignalQueue.size());
+ if (FINGERPRINT_ERROR_CANCELED == errMsgId && mCancelingSignalQueue.size() > 0) {
+ mCanceledSignalLiveData.postValue(mCancelingSignalQueue.poll());
+ } else {
+ mErrorMessageLiveData.postValue(new EnrollmentStatusMessage(errMsgId, errString));
}
- mErrorMessageLiveData.postValue(new EnrollmentStatusMessage(errMsgId, errString));
}
@Override
@@ -152,6 +161,10 @@
return mErrorMessageLiveData;
}
+ public LiveData<Object> getCanceledSignalLiveData() {
+ return mCanceledSignalLiveData;
+ }
+
public LiveData<Boolean> getAcquireLiveData() {
return mAcquireLiveData;
}
@@ -167,14 +180,14 @@
/**
* Starts enrollment and return latest isEnrolling() result
*/
- public boolean startEnrollment(@EnrollReason int reason) {
+ public Object startEnrollment(@EnrollReason int reason) {
if (mToken == null) {
Log.e(TAG, "Null hardware auth token for enroll");
- return false;
+ return null;
}
if (mCancellationSignal != null) {
- Log.w(TAG, "Enrolling has started, shall not start again");
- return true;
+ Log.w(TAG, "Enrolling is running, shall not start again");
+ return mCancellationSignal;
}
if (DEBUG) {
Log.e(TAG, "startEnrollment(" + reason + ")");
@@ -204,7 +217,7 @@
mFingerprintUpdater.enroll(mToken, mCancellationSignal, mUserId, mEnrollmentCallback,
reason);
}
- return true;
+ return mCancellationSignal;
}
/**
@@ -212,13 +225,17 @@
*/
public boolean cancelEnrollment() {
final CancellationSignal cancellationSignal = mCancellationSignal;
+ mCancellationSignal = null;
+
if (cancellationSignal == null) {
Log.e(TAG, "Fail to cancel enrollment, has cancelled or not start");
return false;
+ } else {
+ Log.d(TAG, "enrollment cancelled");
}
-
- mCancellationSignal = null;
+ mCancelingSignalQueue.add(cancellationSignal);
cancellationSignal.cancel();
+
return true;
}
diff --git a/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollView.java b/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollView.java
index 518397a..55a78b8 100644
--- a/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollView.java
+++ b/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollView.java
@@ -23,6 +23,7 @@
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.RotationUtils;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -130,18 +131,26 @@
onFingerUp();
}
+ private final ViewTreeObserver.OnDrawListener mOnDrawListener = this::updateOverlayParams;
+
/**
* setup SensorProperties
*/
public void setSensorProperties(FingerprintSensorPropertiesInternal properties) {
mSensorProperties = properties;
- ((ViewGroup) getParent()).getViewTreeObserver().addOnDrawListener(
- new ViewTreeObserver.OnDrawListener() {
- @Override
- public void onDraw() {
- updateOverlayParams();
- }
- });
+ ((ViewGroup) getParent()).getViewTreeObserver().addOnDrawListener(mOnDrawListener);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ final ViewGroup parent = (ViewGroup) getParent();
+ if (parent != null) {
+ final ViewTreeObserver observer = parent.getViewTreeObserver();
+ if (observer != null) {
+ observer.removeOnDrawListener(mOnDrawListener);
+ }
+ }
+ super.onDetachedFromWindow();
}
private void onSensorRectUpdated() {
@@ -168,6 +177,10 @@
}
RelativeLayout parent = ((RelativeLayout) getParent());
+ if (parent == null) {
+ Log.e(TAG, "Fail to updateDimensions for " + this + ", parent null");
+ return;
+ }
final int[] coords = parent.getLocationOnScreen();
final int parentLeft = coords[0];
final int parentTop = coords[1];
diff --git a/tests/uitests/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivityTest.kt b/tests/uitests/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivityTest.kt
index 33c8d3d..44eae91 100644
--- a/tests/uitests/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivityTest.kt
+++ b/tests/uitests/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivityTest.kt
@@ -130,7 +130,7 @@
}
@Test
- fun testIntroChooseLock_landscape() {
+ fun testIntroChooseLock_runAslandscape() {
runAsLandscape = true
testIntroChooseLock()
}
@@ -193,7 +193,7 @@
}
@Test
- fun testIntroWithGkPwHandle_withUdfps_clickStart_landscape() {
+ fun testIntroWithGkPwHandle_withUdfps_clickStart_runAslandscape() {
runAsLandscape = true
testIntroWithGkPwHandle_withUdfps_clickStart()
}
@@ -226,7 +226,7 @@
}
@Test
- fun testIntroWithGkPwHandle_withUdfps_clickLottie_landscape() {
+ fun testIntroWithGkPwHandle_withUdfps_clickLottie_runAslandscape() {
runAsLandscape = true
testIntroWithGkPwHandle_withUdfps_clickLottie()
}
@@ -256,7 +256,7 @@
}
@Test
- fun testIntroWithGkPwHandle_withSfps_landscape() {
+ fun testIntroWithGkPwHandle_withSfps_runAslandscape() {
runAsLandscape = true
testIntroWithGkPwHandle_withSfps()
}
@@ -291,7 +291,7 @@
}
@Test
- fun testIntroWithGkPwHandle_withRfps_landscape() {
+ fun testIntroWithGkPwHandle_withRfps_runAslandscape() {
runAsLandscape = true
testIntroWithGkPwHandle_withRfps()
}
@@ -314,7 +314,7 @@
}
@Test
- fun testIntroWithGkPwHandle_clickNoThanksInIntroPage_landscape() {
+ fun testIntroWithGkPwHandle_clickNoThanksInIntroPage_runAslandscape() {
runAsLandscape = true
testIntroWithGkPwHandle_clickNoThanksInIntroPage()
}
@@ -344,7 +344,7 @@
}
@Test
- fun testIntroWithGkPwHandle_clickSkipInFindSensor_landscape() {
+ fun testIntroWithGkPwHandle_clickSkipInFindSensor_runAslandscape() {
runAsLandscape = true
testIntroWithGkPwHandle_clickSkipInFindSensor()
}
@@ -382,7 +382,7 @@
}
@Test
- fun testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw_landscape() {
+ fun testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw_runAslandscape() {
runAsLandscape = true
testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw()
}
@@ -418,7 +418,7 @@
}
@Test
- fun testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw_landscape() {
+ fun testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw_runAslandscape() {
runAsLandscape = true
testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw()
}
@@ -449,7 +449,7 @@
}
@Test
- fun testEnrollingWithGkPwHandle_landscape() {
+ fun testEnrollingWithGkPwHandle_runAslandscape() {
runAsLandscape = true
testEnrollingWithGkPwHandle()
}
@@ -492,7 +492,7 @@
}
@Test
- fun testEnrollingIconTouchDialog_withSfps_landscape() {
+ fun testEnrollingIconTouchDialog_withSfps_runAslandscape() {
runAsLandscape = true
testEnrollingIconTouchDialog_withSfps()
}
@@ -534,7 +534,7 @@
}
@Test
- fun testEnrollingIconTouchDialog_withRfps_landscape() {
+ fun testEnrollingIconTouchDialog_withRfps_runAslandscape() {
runAsLandscape = true
testEnrollingIconTouchDialog_withRfps()
}
@@ -563,7 +563,7 @@
}
@Test
- fun testFindUdfpsWithGkPwHandle_clickStart_landscape() {
+ fun testFindUdfpsWithGkPwHandle_clickStart_runAslandscape() {
runAsLandscape = true
testFindUdfpsWithGkPwHandle_clickStart()
}
@@ -580,7 +580,11 @@
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
// rotate device
- device.setOrientationLandscape()
+ if (runAsLandscape) {
+ device.setOrientationPortrait()
+ } else {
+ device.setOrientationLandscape()
+ }
device.waitForIdle()
// FindUdfps page (landscape)
@@ -606,6 +610,12 @@
}
@Test
+ fun testFindUdfpsLandscapeWithGkPwHandle_clickStartThenBack_runAslandscape() {
+ runAsLandscape = true
+ testFindUdfpsLandscapeWithGkPwHandle_clickStartThenBack()
+ }
+
+ @Test
fun testFindUdfpsWithGkPwHandle_clickLottie() {
Assume.assumeTrue(canAssumeUdfps)
@@ -629,7 +639,7 @@
}
@Test
- fun testFindUdfpsWithGkPwHandle_clickLottie_landscape() {
+ fun testFindUdfpsWithGkPwHandle_clickLottie_runAslandscape() {
runAsLandscape = true
testFindUdfpsWithGkPwHandle_clickLottie()
}
@@ -653,7 +663,7 @@
}
@Test
- fun testFindSfpsWithGkPwHandle_landscape() {
+ fun testFindSfpsWithGkPwHandle_runAslandscape() {
runAsLandscape = true
testFindSfpsWithGkPwHandle()
}
@@ -688,7 +698,7 @@
}
@Test
- fun testFindRfpsWithGkPwHandle_landscape() {
+ fun testFindRfpsWithGkPwHandle_runAslandscape() {
runAsLandscape = true
testFindRfpsWithGkPwHandle()
}
@@ -712,7 +722,7 @@
}
@Test
- fun testFindSensorWithGkPwHandle_clickSkipInFindSensor_landscape() {
+ fun testFindSensorWithGkPwHandle_clickSkipInFindSensor_runAslandscape() {
runAsLandscape = true
testFindSensorWithGkPwHandle_clickSkipInFindSensor()
}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
index a038747..d4fae60 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
@@ -18,13 +18,9 @@
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
-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_CANCELED_BECAUSE_BACK_PRESSED;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintErrorDialogAction;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
import static com.google.common.truth.Truth.assertThat;
@@ -78,20 +74,11 @@
mViewModel = new FingerprintEnrollEnrollingViewModel(
mApplication,
TEST_USER_ID,
- newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5)
+ newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5)
);
}
@Test
- public void testShowErrorDialogLiveData() {
- assertThat(mViewModel.getErrorDialogLiveData().getValue()).isEqualTo(null);
-
- final ErrorDialogData data = new ErrorDialogData("errMsg", "errTitle", 0);
- mViewModel.showErrorDialog(data);
- assertThat(mViewModel.getErrorDialogLiveData().getValue()).isEqualTo(data);
- }
-
- @Test
public void testIconTouchDialog() {
final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
assertThat(actionLiveData.getValue()).isEqualTo(null);
@@ -102,20 +89,6 @@
}
@Test
- public void testErrorDialogActionLiveData() {
- assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(null);
-
- @FingerprintErrorDialogAction int action =
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
- mViewModel.onErrorDialogAction(action);
- assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(action);
-
- action = FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
- mViewModel.onErrorDialogAction(action);
- assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(action);
- }
-
- @Test
public void tesBackPressedScenario() {
final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
assertThat(actionLiveData.getValue()).isEqualTo(null);
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModelTest.kt b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModelTest.kt
new file mode 100644
index 0000000..ae829b9
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModelTest.kt
@@ -0,0 +1,134 @@
+/*
+ * 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.biometrics2.ui.viewmodel
+
+import android.app.Application
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
+import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class FingerprintEnrollErrorDialogViewModelTest {
+
+ private val application = ApplicationProvider.getApplicationContext<Application>()
+ private var viewModel: FingerprintEnrollErrorDialogViewModel =
+ FingerprintEnrollErrorDialogViewModel(application, false)
+
+ @Before
+ fun setUp() {
+ // Make sure viewModel is new for each test
+ viewModel = FingerprintEnrollErrorDialogViewModel(application, false)
+ }
+
+ @Test
+ fun testIsDialogNotShownDefaultFalse() {
+ assertThat(viewModel.isDialogShown).isFalse()
+ }
+
+ @Test
+ fun testIsSuw() {
+ assertThat(FingerprintEnrollErrorDialogViewModel(application, false).isSuw).isFalse()
+ assertThat(FingerprintEnrollErrorDialogViewModel(application, true).isSuw).isTrue()
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun testNewDialog() = runTest {
+ backgroundScope.launch {
+ mutableListOf<Any>().let { list ->
+ viewModel.newDialogFlow.toList(list)
+ assertThat(list.size).isEqualTo(0)
+ }
+
+ mutableListOf<FingerprintErrorDialogSetResultAction>().let { list ->
+ val testErrorMsgId = 3456
+ viewModel.newDialog(testErrorMsgId)
+
+ assertThat(viewModel.isDialogShown).isTrue()
+ viewModel.setResultFlow.toList(list)
+ assertThat(list.size).isEqualTo(1)
+ assertThat(list[0]).isEqualTo(testErrorMsgId)
+ }
+ }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun testTriggerRetry() = runTest {
+ backgroundScope.launch {
+ // triggerRetryFlow shall be empty on begin
+ mutableListOf<Any>().let { list ->
+ viewModel.triggerRetryFlow.toList(list)
+ assertThat(list.size).isEqualTo(0)
+ }
+
+ // emit newDialog
+ mutableListOf<FingerprintErrorDialogSetResultAction>().let { list ->
+ viewModel.newDialog(0)
+ viewModel.triggerRetry()
+
+ assertThat(viewModel.isDialogShown).isFalse()
+ viewModel.setResultFlow.toList(list)
+ assertThat(list.size).isEqualTo(1)
+ }
+ }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun testSetResultFinish() = runTest {
+ backgroundScope.launch {
+ // setResultFlow shall be empty on begin
+ mutableListOf<FingerprintErrorDialogSetResultAction>().let { list ->
+ viewModel.setResultFlow.toList(list)
+ assertThat(list.size).isEqualTo(0)
+ }
+
+ // emit FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
+ viewModel = FingerprintEnrollErrorDialogViewModel(application, false)
+ mutableListOf<FingerprintErrorDialogSetResultAction>().let { list ->
+ viewModel.newDialog(0)
+ viewModel.setResultAndFinish(FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH)
+
+ assertThat(viewModel.isDialogShown).isFalse()
+ viewModel.setResultFlow.toList(list)
+ assertThat(list.size).isEqualTo(1)
+ assertThat(list[0]).isEqualTo(FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH)
+ }
+
+ // emit FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
+ viewModel = FingerprintEnrollErrorDialogViewModel(application, false)
+ mutableListOf<FingerprintErrorDialogSetResultAction>().let { list ->
+ viewModel.newDialog(0)
+ viewModel.setResultAndFinish(FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT)
+
+ assertThat(viewModel.isDialogShown).isFalse()
+ viewModel.setResultFlow.toList(list)
+ assertThat(list.size).isEqualTo(1)
+ assertThat(list[0]).isEqualTo(FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH)
+ }
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
index 2c830ad..418db04 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
@@ -108,9 +108,9 @@
mViewModel.setToken(token);
// Start enrollment
- final boolean ret = mViewModel.startEnrollment(enrollReason);
+ final Object ret = mViewModel.startEnrollment(enrollReason);
- assertThat(ret).isTrue();
+ assertThat(ret).isNotNull();
verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class),
eq(TEST_USER_ID), any(EnrollmentCallback.class), eq(enrollReason));
assertThat(mCallbackWrapper.mValue instanceof MessageDisplayController).isFalse();
@@ -123,9 +123,9 @@
mViewModel.setToken(token);
// Start enrollment
- final boolean ret = mViewModel.startEnrollment(enrollReason);
+ final Object ret = mViewModel.startEnrollment(enrollReason);
- assertThat(ret).isTrue();
+ assertThat(ret).isNotNull();
verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class),
eq(TEST_USER_ID), any(EnrollmentCallback.class), eq(enrollReason));
assertThat(mCallbackWrapper.mValue instanceof MessageDisplayController).isFalse();
@@ -142,9 +142,9 @@
mViewModel.setToken(token);
// Start enrollment
- final boolean ret = mViewModel.startEnrollment(enrollReason);
+ final Object ret = mViewModel.startEnrollment(enrollReason);
- assertThat(ret).isTrue();
+ assertThat(ret).isNotNull();
verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class),
eq(TEST_USER_ID), any(MessageDisplayController.class), eq(enrollReason));
assertThat(mCallbackWrapper.mValue).isNotNull();
@@ -166,9 +166,9 @@
@Test
public void testStartEnrollmentFailBecauseOfNoToken() {
// Start enrollment
- final boolean ret = mViewModel.startEnrollment(ENROLL_FIND_SENSOR);
+ final Object ret = mViewModel.startEnrollment(ENROLL_FIND_SENSOR);
- assertThat(ret).isFalse();
+ assertThat(ret).isNull();
verify(mFingerprintUpdater, never()).enroll(any(byte[].class),
any(CancellationSignal.class), anyInt(), any(EnrollmentCallback.class), anyInt());
}
@@ -177,8 +177,8 @@
public void testCancelEnrollment() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCancellationSignalWrapper.mValue).isNotNull();
// Cancel enrollment
@@ -191,8 +191,8 @@
public void testProgressUpdate() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Test default value
@@ -228,8 +228,8 @@
public void testProgressUpdateClearHelpMessage() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
final LiveData<EnrollmentProgress> progressLiveData = mViewModel.getProgressLiveData();
final LiveData<EnrollmentStatusMessage> helpMsgLiveData =
@@ -271,8 +271,8 @@
mViewModel.setToken(new byte[] { 1, 2, 3 });
// Start enrollment
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Test default value
@@ -308,8 +308,8 @@
public void testGetErrorMessageLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
@@ -330,8 +330,8 @@
public void testGetHelpMessageLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
@@ -352,8 +352,8 @@
public void testGetAcquireLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
@@ -369,8 +369,8 @@
public void testGetPointerDownLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
@@ -387,8 +387,8 @@
public void testGetPointerUpLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
- final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
- assertThat(ret).isTrue();
+ final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+ assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value