[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
This commit is contained in:
@@ -77,6 +77,7 @@ android_library {
|
||||
"setupcompat",
|
||||
"setupdesign",
|
||||
"androidx.lifecycle_lifecycle-runtime",
|
||||
"androidx.lifecycle_lifecycle-runtime-ktx",
|
||||
"androidx.lifecycle_lifecycle-viewmodel",
|
||||
"guava",
|
||||
"jsr305",
|
||||
|
@@ -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"
|
||||
|
36
res/layout/udfps_enroll_enrolling_v2_udfps_view.xml
Normal file
36
res/layout/udfps_enroll_enrolling_v2_udfps_view.xml
Normal file
@@ -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>
|
@@ -34,6 +34,7 @@ import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.Cha
|
||||
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 @@ import com.android.systemui.unfold.compat.ScreenSizeFoldProvider;
|
||||
*/
|
||||
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 @@ public class BiometricsViewModelFactory implements ViewModelProvider.Factory {
|
||||
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 @@ public class BiometricsViewModelFactory implements ViewModelProvider.Factory {
|
||||
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);
|
||||
}
|
||||
|
@@ -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) }
|
@@ -23,13 +23,14 @@ import android.graphics.drawable.Animatable2
|
||||
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 android.widget.TextView
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
)
|
||||
.setDuration(100)
|
||||
.setInterpolator(fastOutLinearInInterpolator)
|
||||
.withEndAction { errorText!!.visibility = View.INVISIBLE }
|
||||
.withEndAction { errorText.visibility = View.INVISIBLE }
|
||||
.start()
|
||||
}
|
||||
}
|
||||
@@ -385,8 +425,8 @@ class FingerprintEnrollEnrollingRfpsFragment : Fragment() {
|
||||
|
||||
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
|
||||
|
@@ -21,10 +21,11 @@ import android.annotation.RawRes
|
||||
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 android.widget.RelativeLayout
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
}
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun onEnrollmentHelp(helpMessage: EnrollmentStatusMessage) {
|
||||
Log.d(TAG, "onEnrollmentHelp($helpMessage)")
|
||||
val helpStr: CharSequence = helpMessage.str
|
||||
if (helpStr.isNotEmpty()) {
|
||||
showError(helpStr)
|
||||
@@ -297,25 +343,26 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingSfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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 @@ private fun ProgressBar.applyProgressBarDynamicColor(context: Context, isError:
|
||||
}
|
||||
|
||||
fun LottieAnimationView.applyLottieDynamicColor(context: Context, isError: Boolean) {
|
||||
addValueCallback<ColorFilter>(
|
||||
addValueCallback(
|
||||
KeyPath(".blue100", "**"),
|
||||
LottieProperty.COLOR_FILTER
|
||||
) {
|
||||
|
@@ -17,8 +17,8 @@ package com.android.settings.biometrics2.ui.view
|
||||
|
||||
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 android.widget.TextView
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
override fun handleOnBackPressed() {
|
||||
isEnabled = false
|
||||
enrollingViewModel.setOnBackPressed()
|
||||
cancelEnrollment()
|
||||
cancelEnrollment(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +174,7 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
_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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
): 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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
illustrationLottie = null
|
||||
} else if (shouldShowLottie) {
|
||||
illustrationLottie =
|
||||
enrollingUdfpsView!!.findViewById<LottieAnimationView>(R.id.illustration_lottie)
|
||||
enrollingView!!.findViewById(R.id.illustration_lottie)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,6 +554,7 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun onEnrollmentHelp(helpMessage: EnrollmentStatusMessage) {
|
||||
Log.d(TAG, "onEnrollmentHelp($helpMessage)")
|
||||
val helpStr: CharSequence = helpMessage.str
|
||||
if (helpStr.isNotEmpty()) {
|
||||
showError(helpStr)
|
||||
@@ -476,25 +563,26 @@ class FingerprintEnrollEnrollingUdfpsFragment : Fragment() {
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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) }
|
@@ -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.View
|
||||
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 @@ class FingerprintEnrollFindRfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollFindRfpsFragment : Fragment() {
|
||||
|
||||
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 @@ class FingerprintEnrollFindRfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollFindRfpsFragment : Fragment() {
|
||||
|
||||
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 @@ class FingerprintEnrollFindRfpsFragment : Fragment() {
|
||||
_viewModel = provider[FingerprintEnrollFindSensorViewModel::class.java]
|
||||
_progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
|
||||
_rotationViewModel = provider[DeviceRotationViewModel::class.java]
|
||||
_errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
|
||||
}
|
||||
super.onAttach(context)
|
||||
}
|
||||
|
@@ -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 android.view.ViewGroup
|
||||
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 @@ class FingerprintEnrollFindSfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollFindSfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollFindSfpsFragment : Fragment() {
|
||||
|
||||
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 @@ class FingerprintEnrollFindSfpsFragment : Fragment() {
|
||||
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 @@ class FingerprintEnrollFindSfpsFragment : Fragment() {
|
||||
|
||||
@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 @@ class FingerprintEnrollFindSfpsFragment : Fragment() {
|
||||
_progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
|
||||
_rotationViewModel = provider[DeviceRotationViewModel::class.java]
|
||||
_foldedViewModel = provider[DeviceFoldedViewModel::class.java]
|
||||
_errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
|
||||
}
|
||||
super.onAttach(context)
|
||||
}
|
||||
|
@@ -32,8 +32,11 @@ import androidx.annotation.ColorInt
|
||||
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.CRE
|
||||
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.FingerprintEnrollIntroViewM
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
// 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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
}
|
||||
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
}
|
||||
|
||||
private fun attachFinishViewModel() {
|
||||
viewModelProvider[FingerprintEnrollFinishViewModel::class.java].let {
|
||||
finishViewModel.let {
|
||||
it.clearActionLiveData()
|
||||
it.actionLiveData.observe(this, finishActionObserver)
|
||||
}
|
||||
@@ -520,18 +547,6 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
@@ -59,9 +59,7 @@ public class DeviceRotationViewModel extends AndroidViewModel {
|
||||
@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 @@ public class DeviceRotationViewModel extends AndroidViewModel {
|
||||
* 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;
|
||||
}
|
||||
|
@@ -73,29 +73,11 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
|
||||
@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 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
|
||||
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 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
|
||||
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 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
|
||||
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 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
|
||||
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 + "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
@@ -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.biometrics.fingerprint.MessageDisplayController;
|
||||
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 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
|
||||
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 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
|
||||
|
||||
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 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
|
||||
|
||||
@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 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
|
||||
return mErrorMessageLiveData;
|
||||
}
|
||||
|
||||
public LiveData<Object> getCanceledSignalLiveData() {
|
||||
return mCanceledSignalLiveData;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getAcquireLiveData() {
|
||||
return mAcquireLiveData;
|
||||
}
|
||||
@@ -167,14 +180,14 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
|
||||
/**
|
||||
* 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 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
|
||||
mFingerprintUpdater.enroll(mToken, mCancellationSignal, mUserId, mEnrollmentCallback,
|
||||
reason);
|
||||
}
|
||||
return true;
|
||||
return mCancellationSignal;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,13 +225,17 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
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 @@ public class UdfpsEnrollView extends FrameLayout {
|
||||
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 @@ public class UdfpsEnrollView extends FrameLayout {
|
||||
}
|
||||
|
||||
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];
|
||||
|
@@ -130,7 +130,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroChooseLock_landscape() {
|
||||
fun testIntroChooseLock_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroChooseLock()
|
||||
}
|
||||
@@ -193,7 +193,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroWithGkPwHandle_withUdfps_clickStart_landscape() {
|
||||
fun testIntroWithGkPwHandle_withUdfps_clickStart_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroWithGkPwHandle_withUdfps_clickStart()
|
||||
}
|
||||
@@ -226,7 +226,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroWithGkPwHandle_withUdfps_clickLottie_landscape() {
|
||||
fun testIntroWithGkPwHandle_withUdfps_clickLottie_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroWithGkPwHandle_withUdfps_clickLottie()
|
||||
}
|
||||
@@ -256,7 +256,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroWithGkPwHandle_withSfps_landscape() {
|
||||
fun testIntroWithGkPwHandle_withSfps_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroWithGkPwHandle_withSfps()
|
||||
}
|
||||
@@ -291,7 +291,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroWithGkPwHandle_withRfps_landscape() {
|
||||
fun testIntroWithGkPwHandle_withRfps_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroWithGkPwHandle_withRfps()
|
||||
}
|
||||
@@ -314,7 +314,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroWithGkPwHandle_clickNoThanksInIntroPage_landscape() {
|
||||
fun testIntroWithGkPwHandle_clickNoThanksInIntroPage_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroWithGkPwHandle_clickNoThanksInIntroPage()
|
||||
}
|
||||
@@ -344,7 +344,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroWithGkPwHandle_clickSkipInFindSensor_landscape() {
|
||||
fun testIntroWithGkPwHandle_clickSkipInFindSensor_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroWithGkPwHandle_clickSkipInFindSensor()
|
||||
}
|
||||
@@ -382,7 +382,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw_landscape() {
|
||||
fun testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw()
|
||||
}
|
||||
@@ -418,7 +418,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw_landscape() {
|
||||
fun testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw()
|
||||
}
|
||||
@@ -449,7 +449,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEnrollingWithGkPwHandle_landscape() {
|
||||
fun testEnrollingWithGkPwHandle_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testEnrollingWithGkPwHandle()
|
||||
}
|
||||
@@ -492,7 +492,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEnrollingIconTouchDialog_withSfps_landscape() {
|
||||
fun testEnrollingIconTouchDialog_withSfps_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testEnrollingIconTouchDialog_withSfps()
|
||||
}
|
||||
@@ -534,7 +534,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEnrollingIconTouchDialog_withRfps_landscape() {
|
||||
fun testEnrollingIconTouchDialog_withRfps_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testEnrollingIconTouchDialog_withRfps()
|
||||
}
|
||||
@@ -563,7 +563,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFindUdfpsWithGkPwHandle_clickStart_landscape() {
|
||||
fun testFindUdfpsWithGkPwHandle_clickStart_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testFindUdfpsWithGkPwHandle_clickStart()
|
||||
}
|
||||
@@ -580,7 +580,11 @@ class FingerprintEnrollmentActivityTest {
|
||||
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)
|
||||
@@ -605,6 +609,12 @@ class FingerprintEnrollmentActivityTest {
|
||||
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFindUdfpsLandscapeWithGkPwHandle_clickStartThenBack_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testFindUdfpsLandscapeWithGkPwHandle_clickStartThenBack()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFindUdfpsWithGkPwHandle_clickLottie() {
|
||||
Assume.assumeTrue(canAssumeUdfps)
|
||||
@@ -629,7 +639,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFindUdfpsWithGkPwHandle_clickLottie_landscape() {
|
||||
fun testFindUdfpsWithGkPwHandle_clickLottie_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testFindUdfpsWithGkPwHandle_clickLottie()
|
||||
}
|
||||
@@ -653,7 +663,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFindSfpsWithGkPwHandle_landscape() {
|
||||
fun testFindSfpsWithGkPwHandle_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testFindSfpsWithGkPwHandle()
|
||||
}
|
||||
@@ -688,7 +698,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFindRfpsWithGkPwHandle_landscape() {
|
||||
fun testFindRfpsWithGkPwHandle_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testFindRfpsWithGkPwHandle()
|
||||
}
|
||||
@@ -712,7 +722,7 @@ class FingerprintEnrollmentActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFindSensorWithGkPwHandle_clickSkipInFindSensor_landscape() {
|
||||
fun testFindSensorWithGkPwHandle_clickSkipInFindSensor_runAslandscape() {
|
||||
runAsLandscape = true
|
||||
testFindSensorWithGkPwHandle_clickSkipInFindSensor()
|
||||
}
|
||||
|
@@ -18,13 +18,9 @@ package com.android.settings.biometrics2.ui.viewmodel;
|
||||
|
||||
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,19 +74,10 @@ public class FingerprintEnrollEnrollingViewModelTest {
|
||||
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();
|
||||
@@ -101,20 +88,6 @@ public class FingerprintEnrollEnrollingViewModelTest {
|
||||
FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG);
|
||||
}
|
||||
|
||||
@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();
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -108,9 +108,9 @@ public class FingerprintEnrollProgressViewModelTest {
|
||||
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 @@ public class FingerprintEnrollProgressViewModelTest {
|
||||
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 @@ public class FingerprintEnrollProgressViewModelTest {
|
||||
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 @@ public class FingerprintEnrollProgressViewModelTest {
|
||||
@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 class FingerprintEnrollProgressViewModelTest {
|
||||
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 class FingerprintEnrollProgressViewModelTest {
|
||||
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 class FingerprintEnrollProgressViewModelTest {
|
||||
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 @@ public class FingerprintEnrollProgressViewModelTest {
|
||||
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 class FingerprintEnrollProgressViewModelTest {
|
||||
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 class FingerprintEnrollProgressViewModelTest {
|
||||
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 class FingerprintEnrollProgressViewModelTest {
|
||||
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 class FingerprintEnrollProgressViewModelTest {
|
||||
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 class FingerprintEnrollProgressViewModelTest {
|
||||
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
|
||||
|
Reference in New Issue
Block a user