Merge "UDFPS Enrollment Refactor (5/N)" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
890eecf2e4
@@ -14,38 +14,38 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.lib.model
|
||||
package com.android.settings.biometrics.fingerprint2.data.model
|
||||
|
||||
/**
|
||||
* A view model that describes the various stages of UDFPS Enrollment. This stages typically update
|
||||
* the enrollment UI in a major way, such as changing the lottie animation or changing the location
|
||||
* of the where the user should press their fingerprint
|
||||
*/
|
||||
sealed class StageViewModel {
|
||||
sealed class EnrollStageModel {
|
||||
/** Unknown stage */
|
||||
data object Unknown : StageViewModel()
|
||||
data object Unknown : EnrollStageModel()
|
||||
|
||||
/** This is the stage that moves the fingerprint icon around during enrollment. */
|
||||
data object Guided : StageViewModel()
|
||||
data object Guided : EnrollStageModel()
|
||||
|
||||
/** The center stage is the initial stage of enrollment. */
|
||||
data object Center : StageViewModel()
|
||||
data object Center : EnrollStageModel()
|
||||
|
||||
/**
|
||||
* Fingerprint stage of enrollment. Typically there is some sort of indication that a user should
|
||||
* be using their finger tip to enroll.
|
||||
*/
|
||||
data object Fingertip : StageViewModel()
|
||||
data object Fingertip : EnrollStageModel()
|
||||
|
||||
/**
|
||||
* Left edge stage of enrollment. Typically there is an indication that a user should be using the
|
||||
* left edge of their fingerprint.
|
||||
*/
|
||||
data object LeftEdge : StageViewModel()
|
||||
data object LeftEdge : EnrollStageModel()
|
||||
|
||||
/**
|
||||
* Right edge stage of enrollment. Typically there is an indication that a user should be using
|
||||
* the right edge of their fingerprint.
|
||||
*/
|
||||
data object RightEdge : StageViewModel()
|
||||
data object RightEdge : EnrollStageModel()
|
||||
}
|
@@ -16,11 +16,11 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.domain.interactor
|
||||
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
typealias EnrollStageThresholds = Map<Float, StageViewModel>
|
||||
typealias EnrollStageThresholds = Map<Float, EnrollStageModel>
|
||||
|
||||
/** Interactor that provides enroll stages for enrollment. */
|
||||
interface EnrollStageInteractor {
|
||||
@@ -33,11 +33,11 @@ class EnrollStageInteractorImpl() : EnrollStageInteractor {
|
||||
override val enrollStageThresholds: Flow<EnrollStageThresholds> =
|
||||
flowOf(
|
||||
mapOf(
|
||||
0.0f to StageViewModel.Center,
|
||||
0.25f to StageViewModel.Guided,
|
||||
0.5f to StageViewModel.Fingertip,
|
||||
0.75f to StageViewModel.LeftEdge,
|
||||
0.875f to StageViewModel.RightEdge,
|
||||
0.0f to EnrollStageModel.Center,
|
||||
0.25f to EnrollStageModel.Guided,
|
||||
0.5f to EnrollStageModel.Fingertip,
|
||||
0.75f to EnrollStageModel.LeftEdge,
|
||||
0.875f to EnrollStageModel.RightEdge,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ interface OrientationInteractor {
|
||||
* A flow that contains the rotation info matched against the def [config_reverseDefaultRotation]
|
||||
*/
|
||||
val rotationFromDefault: Flow<Int>
|
||||
|
||||
/**
|
||||
* A Helper function that computes rotation if device is in
|
||||
* [R.bool.config_reverseDefaultConfigRotation]
|
||||
|
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.biometrics.fingerprint2.domain.interactor
|
||||
|
||||
import android.graphics.PointF
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
/**
|
||||
* This interactor provides information about the current offset of the sensor for guided enrollment
|
||||
* on UDFPS devices.
|
||||
*/
|
||||
interface UdfpsEnrollInteractor {
|
||||
/** Indicates at which step a UDFPS enrollment is in. */
|
||||
fun onEnrollmentStep(stepsRemaining: Int, totalStep: Int)
|
||||
|
||||
/** Indicates if guided enrollment should be enabled or not. */
|
||||
fun updateGuidedEnrollment(enabled: Boolean)
|
||||
|
||||
/**
|
||||
* A flow indicating how much the sensor image drawable should be offset for guided enrollment. A
|
||||
* null point indicates that the icon should be in its default position.
|
||||
*/
|
||||
val guidedEnrollmentOffset: Flow<PointF>
|
||||
}
|
||||
|
||||
/** Keeps track of which guided enrollment point we should be using */
|
||||
class UdfpsEnrollInteractorImpl(
|
||||
pixelsPerMillimeter: Float,
|
||||
accessibilityInteractor: AccessibilityInteractor,
|
||||
) : UdfpsEnrollInteractor {
|
||||
|
||||
private var isGuidedEnrollment = MutableStateFlow(false)
|
||||
// Number of pixels per mm
|
||||
val px = pixelsPerMillimeter
|
||||
private val guidedEnrollmentPoints: MutableList<PointF> =
|
||||
mutableListOf(
|
||||
PointF(2.00f * px, 0.00f * px),
|
||||
PointF(0.87f * px, -2.70f * px),
|
||||
PointF(-1.80f * px, -1.31f * px),
|
||||
PointF(-1.80f * px, 1.31f * px),
|
||||
PointF(0.88f * px, 2.70f * px),
|
||||
PointF(3.94f * px, -1.06f * px),
|
||||
PointF(2.90f * px, -4.14f * px),
|
||||
PointF(-0.52f * px, -5.95f * px),
|
||||
PointF(-3.33f * px, -3.33f * px),
|
||||
PointF(-3.99f * px, -0.35f * px),
|
||||
PointF(-3.62f * px, 2.54f * px),
|
||||
PointF(-1.49f * px, 5.57f * px),
|
||||
PointF(2.29f * px, 4.92f * px),
|
||||
PointF(3.82f * px, 1.78f * px),
|
||||
)
|
||||
|
||||
override fun onEnrollmentStep(stepsRemaining: Int, totalStep: Int) {
|
||||
val index = (totalStep - stepsRemaining) % guidedEnrollmentPoints.size
|
||||
_guidedEnrollment.update { guidedEnrollmentPoints[index] }
|
||||
}
|
||||
|
||||
override fun updateGuidedEnrollment(enabled: Boolean) {
|
||||
isGuidedEnrollment.update { enabled }
|
||||
}
|
||||
|
||||
private val _guidedEnrollment = MutableStateFlow(PointF(0f, 0f))
|
||||
override val guidedEnrollmentOffset: Flow<PointF> =
|
||||
combine(
|
||||
_guidedEnrollment,
|
||||
accessibilityInteractor.isAccessibilityEnabled,
|
||||
isGuidedEnrollment,
|
||||
) { point, accessibilityEnabled, guidedEnrollmentEnabled ->
|
||||
if (accessibilityEnabled || !guidedEnrollmentEnabled) {
|
||||
return@combine PointF(0f, 0f)
|
||||
} else {
|
||||
return@combine PointF(point.x * SCALE, point.y * SCALE)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SCALE = 0.5f
|
||||
}
|
||||
}
|
@@ -24,6 +24,7 @@ import android.hardware.fingerprint.FingerprintManager
|
||||
import android.os.Bundle
|
||||
import android.os.Vibrator
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.fragment.app.Fragment
|
||||
@@ -54,6 +55,8 @@ import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateI
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||
@@ -89,6 +92,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Transition
|
||||
import com.android.settings.flags.Flags
|
||||
import com.android.settings.password.ChooseLockGeneric
|
||||
import com.android.settings.password.ChooseLockSettingsHelper
|
||||
@@ -116,6 +120,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
private lateinit var foldStateInteractor: FoldStateInteractor
|
||||
private lateinit var orientationInteractor: OrientationInteractor
|
||||
private lateinit var displayDensityInteractor: DisplayDensityInteractor
|
||||
private lateinit var udfpsEnrollInteractor: UdfpsEnrollInteractor
|
||||
private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
|
||||
private lateinit var backgroundViewModel: BackgroundViewModel
|
||||
private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
|
||||
@@ -256,6 +261,15 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
fingerprintManager,
|
||||
Settings,
|
||||
)
|
||||
val accessibilityInteractor =
|
||||
AccessibilityInteractorImpl(
|
||||
getSystemService(AccessibilityManager::class.java)!!,
|
||||
lifecycleScope,
|
||||
)
|
||||
|
||||
val pixelsPerMillimeter =
|
||||
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, context.resources.displayMetrics)
|
||||
udfpsEnrollInteractor = UdfpsEnrollInteractorImpl(pixelsPerMillimeter, accessibilityInteractor)
|
||||
|
||||
val fingerprintManagerInteractor =
|
||||
FingerprintManagerInteractorImpl(
|
||||
@@ -273,12 +287,6 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
|
||||
val hasConfirmedDeviceCredential = gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo
|
||||
|
||||
val accessibilityInteractor =
|
||||
AccessibilityInteractorImpl(
|
||||
getSystemService(AccessibilityManager::class.java)!!,
|
||||
lifecycleScope,
|
||||
)
|
||||
|
||||
navigationViewModel =
|
||||
ViewModelProvider(
|
||||
this,
|
||||
@@ -384,6 +392,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
orientationInteractor,
|
||||
backgroundViewModel,
|
||||
fingerprintSensorRepo,
|
||||
udfpsEnrollInteractor,
|
||||
),
|
||||
)[UdfpsViewModel::class.java]
|
||||
|
||||
@@ -435,17 +444,17 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
else -> FingerprintEnrollEnrollingV2Fragment()
|
||||
}
|
||||
}
|
||||
Introduction -> FingerprintEnrollIntroV2Fragment()
|
||||
is Introduction -> FingerprintEnrollIntroV2Fragment()
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (theClass != null) {
|
||||
supportFragmentManager.fragments.onEach { fragment ->
|
||||
supportFragmentManager.beginTransaction().remove(fragment).commit()
|
||||
}
|
||||
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.setCustomAnimations(
|
||||
step.enterTransition.toAnimation(),
|
||||
step.exitTransition.toAnimation(),
|
||||
)
|
||||
.setReorderingAllowed(true)
|
||||
.add(R.id.fragment_container_view, theClass::class.java, null)
|
||||
.commit()
|
||||
@@ -512,3 +521,12 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Transition.toAnimation(): Int {
|
||||
return when (this) {
|
||||
Transition.EnterFromLeft -> com.google.android.setupdesign.R.anim.sud_slide_back_in
|
||||
Transition.EnterFromRight -> com.google.android.setupdesign.R.anim.sud_slide_next_in
|
||||
Transition.ExitToLeft -> com.google.android.setupdesign.R.anim.sud_slide_next_out
|
||||
Transition.ExitToRight -> com.google.android.setupdesign.R.anim.sud_slide_back_out
|
||||
}
|
||||
}
|
||||
|
@@ -32,12 +32,12 @@ import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.airbnb.lottie.LottieCompositionFactory
|
||||
import com.android.settings.R
|
||||
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.widget.FingerprintErrorDialog
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.DescriptionText
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.DescriptionText
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.HeaderText
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.EducationAnimationModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.HeaderText
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.UdfpsViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.widget.UdfpsEnrollViewV2
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
|
||||
@@ -83,6 +83,8 @@ class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enro
|
||||
window.statusBarColor = color
|
||||
view.setBackgroundColor(color)
|
||||
|
||||
udfpsEnrollView.setFinishAnimationCompleted { viewModel.finishedSuccessfully() }
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
launch {
|
||||
@@ -159,7 +161,14 @@ class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enro
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.enrollStage.collect { udfpsEnrollView.updateStage(it) }
|
||||
viewModel.guidedEnrollment.collect {
|
||||
glifLayout.post { udfpsEnrollView.updateGuidedEnrollment(it) }
|
||||
}
|
||||
}
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.guidedEnrollmentSaved.collect {
|
||||
glifLayout.post { udfpsEnrollView.onGuidedPointSaved(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,35 +184,35 @@ class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enro
|
||||
}
|
||||
|
||||
private fun HeaderText.toResource(): Int {
|
||||
return when (this.stageViewModel) {
|
||||
StageViewModel.Center,
|
||||
StageViewModel.Guided,
|
||||
StageViewModel.Fingertip,
|
||||
StageViewModel.Unknown -> R.string.security_settings_udfps_enroll_fingertip_title
|
||||
StageViewModel.LeftEdge -> R.string.security_settings_udfps_enroll_left_edge_title
|
||||
StageViewModel.RightEdge -> R.string.security_settings_udfps_enroll_right_edge_title
|
||||
return when (this.enrollStageModel) {
|
||||
EnrollStageModel.Center,
|
||||
EnrollStageModel.Guided,
|
||||
EnrollStageModel.Fingertip,
|
||||
EnrollStageModel.Unknown -> R.string.security_settings_udfps_enroll_fingertip_title
|
||||
EnrollStageModel.LeftEdge -> R.string.security_settings_udfps_enroll_left_edge_title
|
||||
EnrollStageModel.RightEdge -> R.string.security_settings_udfps_enroll_right_edge_title
|
||||
}
|
||||
}
|
||||
|
||||
private fun DescriptionText.toResource(): Int? {
|
||||
return when (this.stageViewModel) {
|
||||
StageViewModel.Center,
|
||||
StageViewModel.Guided,
|
||||
StageViewModel.Fingertip,
|
||||
StageViewModel.LeftEdge,
|
||||
StageViewModel.RightEdge -> null
|
||||
StageViewModel.Unknown -> R.string.security_settings_udfps_enroll_start_message
|
||||
return when (this.enrollStageModel) {
|
||||
EnrollStageModel.Center,
|
||||
EnrollStageModel.Guided,
|
||||
EnrollStageModel.Fingertip,
|
||||
EnrollStageModel.LeftEdge,
|
||||
EnrollStageModel.RightEdge -> null
|
||||
EnrollStageModel.Unknown -> R.string.security_settings_udfps_enroll_start_message
|
||||
}
|
||||
}
|
||||
|
||||
private fun EducationAnimationModel.toResource(): Int? {
|
||||
return when (this.stageViewModel) {
|
||||
StageViewModel.Center,
|
||||
StageViewModel.Guided -> R.raw.udfps_center_hint_lottie
|
||||
StageViewModel.Fingertip -> R.raw.udfps_tip_hint_lottie
|
||||
StageViewModel.LeftEdge -> R.raw.udfps_left_edge_hint_lottie
|
||||
StageViewModel.RightEdge -> R.raw.udfps_right_edge_hint_lottie
|
||||
StageViewModel.Unknown -> null
|
||||
return when (this.enrollStageModel) {
|
||||
EnrollStageModel.Center,
|
||||
EnrollStageModel.Guided -> R.raw.udfps_center_hint_lottie
|
||||
EnrollStageModel.Fingertip -> R.raw.udfps_tip_hint_lottie
|
||||
EnrollStageModel.LeftEdge -> R.raw.udfps_left_edge_hint_lottie
|
||||
EnrollStageModel.RightEdge -> R.raw.udfps_right_edge_hint_lottie
|
||||
EnrollStageModel.Unknown -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model
|
||||
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
|
||||
|
||||
/** Represents the description text for UDFPS enrollment */
|
||||
data class DescriptionText(
|
||||
val isSuw: Boolean,
|
||||
val isAccessibility: Boolean,
|
||||
val stageViewModel: StageViewModel,
|
||||
val enrollStageModel: EnrollStageModel,
|
||||
)
|
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model
|
||||
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
|
||||
|
||||
/** Represents the header text for UDFPS enrollment */
|
||||
data class HeaderText(
|
||||
val isSuw: Boolean,
|
||||
val isAccessibility: Boolean,
|
||||
val stageViewModel: StageViewModel,
|
||||
val enrollStageModel: EnrollStageModel,
|
||||
)
|
@@ -16,11 +16,11 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
|
||||
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
|
||||
|
||||
/** Represents the lottie for UDFPS enrollment */
|
||||
data class EducationAnimationModel(
|
||||
val isSuw: Boolean,
|
||||
val isAccessibility: Boolean,
|
||||
val stageViewModel: StageViewModel,
|
||||
val enrollStageModel: EnrollStageModel,
|
||||
)
|
||||
|
@@ -17,20 +17,24 @@
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
|
||||
|
||||
import android.graphics.Point
|
||||
import android.graphics.PointF
|
||||
import android.view.Surface
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
|
||||
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.SimulatedTouchEventsRepository
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintVibrationEffects
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.DescriptionText
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.HeaderText
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
|
||||
@@ -61,9 +65,11 @@ class UdfpsViewModel(
|
||||
orientationInteractor: OrientationInteractor,
|
||||
backgroundViewModel: BackgroundViewModel,
|
||||
sensorRepository: FingerprintSensorRepository,
|
||||
udfpsEnrollInteractor: UdfpsEnrollInteractor,
|
||||
) : ViewModel() {
|
||||
|
||||
private val isSetupWizard = flowOf(false)
|
||||
private var shouldResetErollment = false
|
||||
|
||||
private var _enrollState: Flow<FingerEnrollState?> =
|
||||
fingerprintEnrollEnrollingViewModel.enrollFlow
|
||||
@@ -112,6 +118,17 @@ class UdfpsViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This indicates at which point the UI should offset the fingerprint sensor icon for guided
|
||||
* enrollment.
|
||||
*/
|
||||
val guidedEnrollment: Flow<PointF> =
|
||||
udfpsEnrollInteractor.guidedEnrollmentOffset.distinctUntilChanged()
|
||||
|
||||
/** The saved version of [guidedEnrollment] */
|
||||
val guidedEnrollmentSaved: Flow<PointF> =
|
||||
guidedEnrollment.shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
|
||||
|
||||
/**
|
||||
* This is the saved progress, this is for when views are recreated and need saved state for the
|
||||
* first time.
|
||||
@@ -132,13 +149,13 @@ class UdfpsViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
/** Determines the current [StageViewModel] enrollment is in */
|
||||
val enrollStage: Flow<StageViewModel> =
|
||||
/** Determines the current [EnrollStageModel] enrollment is in */
|
||||
private val enrollStage: Flow<EnrollStageModel> =
|
||||
combine(enrollStageInteractor.enrollStageThresholds, enrollState) { thresholds, event ->
|
||||
if (event is FingerEnrollState.EnrollProgress) {
|
||||
val progress =
|
||||
(event.totalStepsRequired - event.remainingSteps).toFloat() / event.totalStepsRequired
|
||||
var stageToReturn: StageViewModel = StageViewModel.Center
|
||||
var stageToReturn: EnrollStageModel = EnrollStageModel.Center
|
||||
thresholds.forEach { (threshold, stage) ->
|
||||
if (progress < threshold) {
|
||||
return@forEach
|
||||
@@ -153,6 +170,40 @@ class UdfpsViewModel(
|
||||
.filterNotNull()
|
||||
.shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
enrollState
|
||||
.combine(accessibilityEnabled) { event, isEnabled -> Pair(event, isEnabled) }
|
||||
.collect {
|
||||
if (
|
||||
when (it.first) {
|
||||
is FingerEnrollState.EnrollError -> true
|
||||
is FingerEnrollState.EnrollHelp -> it.second
|
||||
is FingerEnrollState.EnrollProgress -> true
|
||||
else -> false
|
||||
}
|
||||
) {
|
||||
vibrate(it.first)
|
||||
}
|
||||
}
|
||||
}
|
||||
viewModelScope.launch {
|
||||
enrollStage.collect {
|
||||
udfpsEnrollInteractor.updateGuidedEnrollment(it is EnrollStageModel.Guided)
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
enrollState.filterIsInstance<FingerEnrollState.EnrollProgress>().collect {
|
||||
udfpsEnrollInteractor.onEnrollmentStep(it.remainingSteps, it.totalStepsRequired)
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
backgroundViewModel.background.filter { true }.collect { didGoToBackground() }
|
||||
}
|
||||
}
|
||||
|
||||
/** Indicates if we should show the lottie. */
|
||||
val shouldShowLottie: Flow<Boolean> =
|
||||
combine(
|
||||
@@ -183,7 +234,7 @@ class UdfpsViewModel(
|
||||
}
|
||||
.shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
|
||||
|
||||
private val shouldClearDescriptionText = enrollStage.map { it is StageViewModel.Unknown }
|
||||
private val shouldClearDescriptionText = enrollStage.map { it is EnrollStageModel.Unknown }
|
||||
|
||||
/** The description text for UDFPS enrollment */
|
||||
val descriptionText: Flow<DescriptionText?> =
|
||||
@@ -202,6 +253,10 @@ class UdfpsViewModel(
|
||||
|
||||
/** Indicates if the consumer is ready for enrollment */
|
||||
fun readyForEnrollment() {
|
||||
if (shouldResetErollment) {
|
||||
shouldResetErollment = false
|
||||
_enrollState = fingerprintEnrollEnrollingViewModel.enrollFlow
|
||||
}
|
||||
fingerprintEnrollEnrollingViewModel.canEnroll()
|
||||
}
|
||||
|
||||
@@ -237,8 +292,12 @@ class UdfpsViewModel(
|
||||
}
|
||||
|
||||
private fun doReset() {
|
||||
/** Indicates if the icon should be animating or not */
|
||||
_enrollState = fingerprintEnrollEnrollingViewModel.enrollFlow
|
||||
progressSaved =
|
||||
enrollState
|
||||
.filterIsInstance<FingerEnrollState.EnrollProgress>()
|
||||
.filterNotNull()
|
||||
.shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
|
||||
}
|
||||
|
||||
/** The lottie that should be shown for UDFPS Enrollment */
|
||||
@@ -272,6 +331,7 @@ class UdfpsViewModel(
|
||||
private val orientationInteractor: OrientationInteractor,
|
||||
private val backgroundViewModel: BackgroundViewModel,
|
||||
private val sensorRepository: FingerprintSensorRepository,
|
||||
private val udfpsEnrollInteractor: UdfpsEnrollInteractor,
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -287,6 +347,7 @@ class UdfpsViewModel(
|
||||
orientationInteractor,
|
||||
backgroundViewModel,
|
||||
sensorRepository,
|
||||
udfpsEnrollInteractor,
|
||||
)
|
||||
as T
|
||||
}
|
||||
|
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PointF
|
||||
import android.util.TypedValue
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
|
||||
/** Keeps track of which guided enrollment point we should be using */
|
||||
class UdfpsEnrollHelperV2(private val mContext: Context) {
|
||||
|
||||
private var isGuidedEnrollment: Boolean = false
|
||||
private val accessibilityEnabled: Boolean
|
||||
private val guidedEnrollmentPoints: MutableList<PointF>
|
||||
/** The current index of [guidedEnrollmentPoints] for the guided enrollment. */
|
||||
private var index = 0
|
||||
|
||||
init {
|
||||
val am = mContext.getSystemService(AccessibilityManager::class.java)
|
||||
accessibilityEnabled = am!!.isEnabled
|
||||
guidedEnrollmentPoints = ArrayList()
|
||||
|
||||
// Number of pixels per mm
|
||||
val px =
|
||||
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, mContext.resources.displayMetrics)
|
||||
guidedEnrollmentPoints.add(PointF(2.00f * px, 0.00f * px))
|
||||
guidedEnrollmentPoints.add(PointF(0.87f * px, -2.70f * px))
|
||||
guidedEnrollmentPoints.add(PointF(-1.80f * px, -1.31f * px))
|
||||
guidedEnrollmentPoints.add(PointF(-1.80f * px, 1.31f * px))
|
||||
guidedEnrollmentPoints.add(PointF(0.88f * px, 2.70f * px))
|
||||
guidedEnrollmentPoints.add(PointF(3.94f * px, -1.06f * px))
|
||||
guidedEnrollmentPoints.add(PointF(2.90f * px, -4.14f * px))
|
||||
guidedEnrollmentPoints.add(PointF(-0.52f * px, -5.95f * px))
|
||||
guidedEnrollmentPoints.add(PointF(-3.33f * px, -3.33f * px))
|
||||
guidedEnrollmentPoints.add(PointF(-3.99f * px, -0.35f * px))
|
||||
guidedEnrollmentPoints.add(PointF(-3.62f * px, 2.54f * px))
|
||||
guidedEnrollmentPoints.add(PointF(-1.49f * px, 5.57f * px))
|
||||
guidedEnrollmentPoints.add(PointF(2.29f * px, 4.92f * px))
|
||||
guidedEnrollmentPoints.add(PointF(3.82f * px, 1.78f * px))
|
||||
}
|
||||
|
||||
/**
|
||||
* This indicates whether we should be offsetting the enrollment icon based on
|
||||
* [guidedEnrollmentPoints]
|
||||
*/
|
||||
fun onUpdateStage(stage: StageViewModel) {
|
||||
this.isGuidedEnrollment = stage is StageViewModel.Guided
|
||||
}
|
||||
|
||||
/** Updates [index] to be used by [guidedEnrollmentPoints] */
|
||||
fun onEnrollmentProgress(remaining: Int, totalSteps: Int) {
|
||||
index = totalSteps - remaining
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current guided enrollment point, or (0,0) if we are not in guided enrollment or are
|
||||
* in accessibility.
|
||||
*/
|
||||
val guidedEnrollmentLocation: PointF?
|
||||
get() {
|
||||
if (accessibilityEnabled || !isGuidedEnrollment) {
|
||||
return null
|
||||
}
|
||||
val scale = SCALE
|
||||
val originalPoint = guidedEnrollmentPoints[index % guidedEnrollmentPoints.size]
|
||||
return PointF(originalPoint.x * scale, originalPoint.y * scale)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "UdfpsEnrollHelperV2"
|
||||
private const val SCALE = 0.5f
|
||||
}
|
||||
}
|
@@ -24,6 +24,7 @@ import android.graphics.Canvas
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.PointF
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import android.graphics.drawable.Drawable
|
||||
@@ -37,7 +38,6 @@ import androidx.core.animation.addListener
|
||||
import androidx.core.graphics.toRect
|
||||
import androidx.core.graphics.toRectF
|
||||
import com.android.settings.R
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
import kotlin.math.sin
|
||||
|
||||
/**
|
||||
@@ -51,11 +51,11 @@ class UdfpsEnrollIconV2 internal constructor(context: Context, attrs: AttributeS
|
||||
private val fingerprintDrawable: ShapeDrawable
|
||||
private val sensorOutlinePaint: Paint
|
||||
private val blueFill: Paint
|
||||
private val helper = UdfpsEnrollHelperV2(context)
|
||||
@ColorInt private var enrollIconColor = 0
|
||||
@ColorInt private var movingTargetFill = 0
|
||||
private var currentScale = 1.0f
|
||||
private var alpha = 0
|
||||
private var guidedEnrollmentOffset: PointF? = null
|
||||
|
||||
/**
|
||||
* This is the physical location of the sensor. This rect will be updated by [drawSensorRectAt]
|
||||
@@ -143,45 +143,6 @@ class UdfpsEnrollIconV2 internal constructor(context: Context, attrs: AttributeS
|
||||
invalidateSelf()
|
||||
}
|
||||
|
||||
/** Update the progress of the icon */
|
||||
fun onEnrollmentProgress(remaining: Int, totalSteps: Int, isRecreating: Boolean = false) {
|
||||
restoreAnimationTime()
|
||||
// If we are restoring this view from a saved state, set animation duration to 0 to avoid
|
||||
// animating progress that has already occurred.
|
||||
if (isRecreating) {
|
||||
setAnimationTimeToZero()
|
||||
} else {
|
||||
restoreAnimationTime()
|
||||
}
|
||||
|
||||
helper.onEnrollmentProgress(remaining, totalSteps)
|
||||
val offset = helper.guidedEnrollmentLocation
|
||||
val currentBounds = getCurrLocation().toRect()
|
||||
if (offset != null) {
|
||||
// This is the desired location of the sensor rect, the [EnrollHelper]
|
||||
// offsets the initial sensor rect by a bit to get the user to move their finger a bit more.
|
||||
val targetRect = Rect(sensorRectBounds).toRectF()
|
||||
targetRect.offset(offset.x, offset.y)
|
||||
val shouldAnimateMovement =
|
||||
!currentBounds.equals(targetRect) && offset.x != 0f && offset.y != 0f
|
||||
if (shouldAnimateMovement) {
|
||||
targetAnimatorSet?.cancel()
|
||||
animateMovement(currentBounds, targetRect, true)
|
||||
}
|
||||
} else {
|
||||
// If we are not offsetting the sensor, move it back to its original place
|
||||
animateMovement(currentBounds, sensorRectBounds.toRectF(), false)
|
||||
}
|
||||
|
||||
invalidateSelf()
|
||||
}
|
||||
|
||||
/** Update the stage of the icon */
|
||||
fun updateStage(it: StageViewModel) {
|
||||
helper.onUpdateStage(it)
|
||||
invalidateSelf()
|
||||
}
|
||||
|
||||
/** Stop drawing the fingerprint icon. */
|
||||
fun stopDrawing() {
|
||||
alpha = 0
|
||||
@@ -211,6 +172,7 @@ class UdfpsEnrollIconV2 internal constructor(context: Context, attrs: AttributeS
|
||||
if (currentBounds.equals(offsetRect)) {
|
||||
return
|
||||
}
|
||||
|
||||
val xAnimator = ValueAnimator.ofFloat(currentBounds.left.toFloat(), offsetRect.left)
|
||||
xAnimator.addUpdateListener {
|
||||
currX = it.animatedValue as Float
|
||||
@@ -260,6 +222,40 @@ class UdfpsEnrollIconV2 internal constructor(context: Context, attrs: AttributeS
|
||||
targetAnimationDuration = TARGET_ANIM_DURATION_LONG
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates a change to guided enrollment has occurred. Also indicates if we are recreating the
|
||||
* view, in which case their is no need to animate the icon to whatever position it was in.
|
||||
*/
|
||||
fun updateGuidedEnrollment(point: PointF, isRecreating: Boolean) {
|
||||
guidedEnrollmentOffset = point
|
||||
if (isRecreating) {
|
||||
setAnimationTimeToZero()
|
||||
} else {
|
||||
restoreAnimationTime()
|
||||
}
|
||||
|
||||
val currentBounds = getCurrLocation().toRect()
|
||||
val offset = guidedEnrollmentOffset
|
||||
if (offset?.x != 0f && offset?.y != 0f) {
|
||||
val targetRect = Rect(sensorRectBounds).toRectF()
|
||||
// This is the desired location of the sensor rect, the [EnrollHelper]
|
||||
// offsets the initial sensor rect by a bit to get the user to move their finger a bit more.
|
||||
targetRect.offset(offset!!.x, offset!!.y)
|
||||
val shouldAnimateMovement = !currentBounds.equals(targetRect)
|
||||
if (shouldAnimateMovement) {
|
||||
targetAnimatorSet?.cancel()
|
||||
animateMovement(currentBounds, targetRect, true)
|
||||
} else {
|
||||
// If we are not offsetting the sensor, move it back to its original place
|
||||
animateMovement(currentBounds, sensorRectBounds.toRectF(), false)
|
||||
}
|
||||
} else {
|
||||
// If we are not offsetting the sensor, move it back to its original place
|
||||
animateMovement(currentBounds, sensorRectBounds.toRectF(), false)
|
||||
}
|
||||
invalidateSelf()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "UdfpsEnrollDrawableV2"
|
||||
private const val DEFAULT_STROKE_WIDTH = 3f
|
||||
|
@@ -27,10 +27,12 @@ import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.view.animation.Interpolator
|
||||
import android.view.animation.OvershootInterpolator
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.core.animation.addListener
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.graphics.toRectF
|
||||
import com.android.internal.annotations.VisibleForTesting
|
||||
@@ -46,6 +48,7 @@ import kotlin.math.sin
|
||||
class UdfpsEnrollProgressBarDrawableV2(private val context: Context, attrs: AttributeSet?) :
|
||||
Drawable() {
|
||||
private val sensorRect: Rect = Rect()
|
||||
private var onFinishedCompletionAnimation: (() -> Unit)? = null
|
||||
private var rotation: Int = 0
|
||||
private val strokeWidthPx: Float
|
||||
|
||||
@@ -287,6 +290,12 @@ class UdfpsEnrollProgressBarDrawableV2(private val context: Context, attrs: Attr
|
||||
checkMarkDrawable.bounds = newBounds
|
||||
checkMarkDrawable.setVisible(true, false)
|
||||
}
|
||||
doOnEnd {
|
||||
onFinishedCompletionAnimation?.let{
|
||||
it()
|
||||
}
|
||||
|
||||
}
|
||||
start()
|
||||
}
|
||||
}
|
||||
@@ -380,6 +389,13 @@ class UdfpsEnrollProgressBarDrawableV2(private val context: Context, attrs: Attr
|
||||
checkmarkAnimationDuration = CHECKMARK_ANIMATION_DURATION_MS
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the finish animation has completed, and enrollment can proceed to the next stage
|
||||
*/
|
||||
fun setFinishAnimationCompleted(onFinishedAnimation: () -> Unit) {
|
||||
this.onFinishedCompletionAnimation = onFinishedAnimation
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "UdfpsProgressBar"
|
||||
private const val FILL_COLOR_ANIMATION_DURATION_MS = 350L
|
||||
|
@@ -18,6 +18,7 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrol
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Point
|
||||
import android.graphics.PointF
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
@@ -31,7 +32,6 @@ import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import com.android.settings.R
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
|
||||
import com.android.systemui.biometrics.UdfpsUtils
|
||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
|
||||
@@ -53,6 +53,13 @@ class UdfpsEnrollViewV2(context: Context, attrs: AttributeSet?) : FrameLayout(co
|
||||
private val udfpsUtils: UdfpsUtils = UdfpsUtils()
|
||||
private lateinit var touchExplorationAnnouncer: TouchExplorationAnnouncer
|
||||
private var isRecreating = false
|
||||
private var onFinishedCompletionAnimation: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
fingerprintProgressDrawable.setFinishAnimationCompleted {
|
||||
onFinishedCompletionAnimation?.let { it() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function computes the center (x,y) location with respect to the parent [FrameLayout] for
|
||||
@@ -112,11 +119,6 @@ class UdfpsEnrollViewV2(context: Context, attrs: AttributeSet?) : FrameLayout(co
|
||||
touchExplorationAnnouncer = TouchExplorationAnnouncer(context, this, overlayParams, udfpsUtils)
|
||||
}
|
||||
|
||||
/** Updates the current enrollment stage. */
|
||||
fun updateStage(it: StageViewModel) {
|
||||
fingerprintIcon.updateStage(it)
|
||||
}
|
||||
|
||||
/** Receive enroll progress event */
|
||||
fun onUdfpsEvent(event: FingerEnrollState) {
|
||||
when (event) {
|
||||
@@ -174,7 +176,6 @@ class UdfpsEnrollViewV2(context: Context, attrs: AttributeSet?) : FrameLayout(co
|
||||
|
||||
/** Receive enroll progress event */
|
||||
private fun onEnrollmentProgress(remaining: Int, totalSteps: Int) {
|
||||
fingerprintIcon.onEnrollmentProgress(remaining, totalSteps)
|
||||
fingerprintProgressDrawable.onEnrollmentProgress(remaining, totalSteps)
|
||||
}
|
||||
|
||||
@@ -241,10 +242,25 @@ class UdfpsEnrollViewV2(context: Context, attrs: AttributeSet?) : FrameLayout(co
|
||||
|
||||
/** Indicates we should should restore the views saved state. */
|
||||
fun onEnrollProgressSaved(it: FingerEnrollState.EnrollProgress) {
|
||||
fingerprintIcon.onEnrollmentProgress(it.remainingSteps, it.totalStepsRequired, true)
|
||||
fingerprintProgressDrawable.onEnrollmentProgress(it.remainingSteps, it.totalStepsRequired, true)
|
||||
}
|
||||
|
||||
/** Indicates we are recreating the UI from a saved state. */
|
||||
fun onGuidedPointSaved(it: PointF) {
|
||||
fingerprintIcon.updateGuidedEnrollment(it, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the finish animation has completed, and enrollment can proceed to the next stage
|
||||
*/
|
||||
fun setFinishAnimationCompleted(onFinishedAnimation: () -> Unit) {
|
||||
this.onFinishedCompletionAnimation = onFinishedAnimation
|
||||
}
|
||||
|
||||
fun updateGuidedEnrollment(point: PointF) {
|
||||
fingerprintIcon.updateGuidedEnrollment(point, false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "UdfpsEnrollView"
|
||||
}
|
||||
|
@@ -88,7 +88,10 @@ sealed interface FingerprintNavigationStep {
|
||||
}
|
||||
|
||||
/** UiSteps should have a 1 to 1 mapping between each screen of FingerprintEnrollment */
|
||||
sealed class UiStep : FingerprintNavigationStep
|
||||
sealed class UiStep(
|
||||
val enterTransition: Transition = Transition.EnterFromRight,
|
||||
val exitTransition: Transition = Transition.ExitToLeft,
|
||||
) : FingerprintNavigationStep
|
||||
|
||||
/** This is the landing page for enrollment, where no content is shown. */
|
||||
data object Init : UiStep() {
|
||||
@@ -103,7 +106,7 @@ sealed interface FingerprintNavigationStep {
|
||||
} else if (state.flowType is FastEnroll) {
|
||||
TransitionStep(Enrollment(state.fingerprintSensor!!))
|
||||
} else {
|
||||
TransitionStep(Introduction)
|
||||
TransitionStep(Introduction())
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
@@ -118,7 +121,7 @@ sealed interface FingerprintNavigationStep {
|
||||
action: FingerprintAction,
|
||||
): FingerprintNavigationStep? {
|
||||
return when (action) {
|
||||
FingerprintAction.CONFIRM_DEVICE_SUCCESS -> TransitionStep(Introduction)
|
||||
FingerprintAction.CONFIRM_DEVICE_SUCCESS -> TransitionStep(Introduction())
|
||||
FingerprintAction.CONFIRM_DEVICE_FAIL -> Finish(null)
|
||||
else -> null
|
||||
}
|
||||
@@ -126,7 +129,10 @@ sealed interface FingerprintNavigationStep {
|
||||
}
|
||||
|
||||
/** Indicates the FingerprintIntroduction screen is being presented to the user */
|
||||
data object Introduction : UiStep() {
|
||||
class Introduction(
|
||||
enterTransition: Transition = Transition.EnterFromRight,
|
||||
exitTransition: Transition = Transition.ExitToLeft,
|
||||
) : UiStep(enterTransition, exitTransition) {
|
||||
override fun update(
|
||||
state: NavigationState,
|
||||
action: FingerprintAction,
|
||||
@@ -141,7 +147,11 @@ sealed interface FingerprintNavigationStep {
|
||||
}
|
||||
|
||||
/** Indicates the FingerprintEducation screen is being presented to the user */
|
||||
data class Education(val sensor: FingerprintSensor) : UiStep() {
|
||||
class Education(
|
||||
val sensor: FingerprintSensor,
|
||||
enterTransition: Transition = Transition.EnterFromRight,
|
||||
exitTransition: Transition = Transition.ExitToLeft,
|
||||
) : UiStep(enterTransition, exitTransition) {
|
||||
override fun update(
|
||||
state: NavigationState,
|
||||
action: FingerprintAction,
|
||||
@@ -149,7 +159,8 @@ sealed interface FingerprintNavigationStep {
|
||||
return when (action) {
|
||||
FingerprintAction.NEXT -> TransitionStep(Enrollment(state.fingerprintSensor!!))
|
||||
FingerprintAction.NEGATIVE_BUTTON_PRESSED,
|
||||
FingerprintAction.PREV -> TransitionStep(Introduction)
|
||||
FingerprintAction.PREV ->
|
||||
TransitionStep(Introduction(Transition.EnterFromLeft, Transition.ExitToRight))
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -179,7 +190,10 @@ sealed interface FingerprintNavigationStep {
|
||||
): FingerprintNavigationStep? {
|
||||
return when (action) {
|
||||
FingerprintAction.NEXT -> Finish(null)
|
||||
FingerprintAction.PREV -> TransitionStep(Education(state.fingerprintSensor!!))
|
||||
FingerprintAction.PREV ->
|
||||
TransitionStep(
|
||||
Education(state.fingerprintSensor!!, Transition.EnterFromLeft, Transition.ExitToRight)
|
||||
)
|
||||
FingerprintAction.ADD_ANOTHER -> TransitionStep(Enrollment(state.fingerprintSensor!!))
|
||||
else -> null
|
||||
}
|
||||
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
/** Indicates the type of transitions that can occur between fragments */
|
||||
sealed class Transition {
|
||||
/**
|
||||
* Indicates the new fragment should slide in from the left side
|
||||
*/
|
||||
data object EnterFromLeft : Transition()
|
||||
|
||||
/**
|
||||
* Indicates the new fragment should slide in from the right side
|
||||
*/
|
||||
data object EnterFromRight : Transition()
|
||||
|
||||
/**
|
||||
* Indicates the old fragment should slide out to the left side
|
||||
*/
|
||||
data object ExitToLeft : Transition()
|
||||
|
||||
/**
|
||||
* Indicates the old fragment should slide out to the right side
|
||||
*/
|
||||
data object ExitToRight : Transition()
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ class FingerprintEnrollIntroFragmentTest {
|
||||
|
||||
private val navigationViewModel =
|
||||
FingerprintNavigationViewModel(
|
||||
Introduction,
|
||||
Introduction(),
|
||||
false,
|
||||
flowViewModel,
|
||||
interactor
|
||||
|
@@ -28,7 +28,7 @@ import platform.test.screenshot.ViewScreenshotTestRule.Mode
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class FingerprintEnrollIntroScreenshotTest {
|
||||
private val injector: Injector = Injector(FingerprintNavigationStep.Introduction)
|
||||
private val injector: Injector = Injector(FingerprintNavigationStep.Introduction())
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
|
Reference in New Issue
Block a user