1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel 18 19 import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY 20 import androidx.lifecycle.ViewModel 21 import androidx.lifecycle.ViewModelProvider 22 import androidx.lifecycle.viewModelScope 23 import androidx.lifecycle.viewmodel.initializer 24 import androidx.lifecycle.viewmodel.viewModelFactory 25 import com.android.settings.SettingsApplication 26 import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintVibrationEffects 27 import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor 28 import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState 29 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel 30 import kotlinx.coroutines.flow.MutableStateFlow 31 import kotlinx.coroutines.flow.distinctUntilChanged 32 import kotlinx.coroutines.flow.filter 33 import kotlinx.coroutines.flow.filterIsInstance 34 import kotlinx.coroutines.flow.filterNotNull 35 import kotlinx.coroutines.flow.take 36 import kotlinx.coroutines.flow.toList 37 import kotlinx.coroutines.flow.transform 38 import kotlinx.coroutines.flow.update 39 import kotlinx.coroutines.launch 40 41 /** 42 * This class is responsible for determining if we should animate the last step of an enrollment. It 43 * seems to be due to poor hardware implementation that the last step of a UDFPS enrollment takes 44 * much longer then normal (likely due to to saving the whole enrollment/or some kind of 45 * verification) 46 * 47 * Because of this, we will use the information of if a fingerprint was acquired(good) + enrollment 48 * has reached the last step 49 */ 50 class UdfpsLastStepViewModel( 51 private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel, 52 private val vibrationInteractor: VibrationInteractor, 53 ) : ViewModel() { 54 55 private val lastStep: MutableStateFlow<FingerEnrollState.EnrollProgress?> = MutableStateFlow(null) 56 private val stepSize: MutableStateFlow<Int?> = MutableStateFlow(null) 57 58 init { 59 viewModelScope.launch { 60 val steps = 61 fingerprintEnrollEnrollingViewModel.enrollFlow 62 .filterIsInstance<FingerEnrollState.EnrollProgress>() 63 .distinctUntilChanged() 64 .take(2) 65 .toList() 66 stepSize.update { steps[0].remainingSteps - steps[1].remainingSteps } 67 lastStep.update { FingerEnrollState.EnrollProgress(0, steps[0].totalStepsRequired) } 68 } 69 } 70 71 private val enrollProgress = 72 fingerprintEnrollEnrollingViewModel.enrollFlow.filterIsInstance< 73 FingerEnrollState.EnrollProgress 74 >() 75 76 /** Indicates if we should animate the completion of udfps enrollment. */ 77 val shouldAnimateCompletion = 78 enrollProgress 79 .transform { it -> 80 if (it.remainingSteps == stepSize.value) { 81 fingerprintEnrollEnrollingViewModel.enrollFlow 82 .filterIsInstance<FingerEnrollState.Acquired>() 83 .filter { acquired -> acquired.acquiredGood } 84 .collect { 85 vibrationInteractor.vibrate( 86 FingerprintVibrationEffects.UdfpsSuccess, 87 "UdfpsLastStepViewModel", 88 ) 89 90 emit(lastStep.value) 91 } 92 } 93 } 94 .filterNotNull() 95 96 companion object { 97 val Factory: ViewModelProvider.Factory = viewModelFactory { 98 initializer { 99 val settingsApplication = 100 this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication 101 val biometricEnvironment = settingsApplication.biometricEnvironment 102 val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!) 103 UdfpsLastStepViewModel( 104 provider[FingerprintEnrollEnrollingViewModel::class], 105 biometricEnvironment!!.vibrationInteractor, 106 ) 107 } 108 } 109 } 110 } 111