1 /*
<lambda>null2  * Copyright (C) 2023 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.viewmodel
18 
19 import android.hardware.fingerprint.FingerprintEnrollOptions
20 import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
21 import androidx.lifecycle.ViewModel
22 import androidx.lifecycle.ViewModelProvider
23 import androidx.lifecycle.viewmodel.initializer
24 import androidx.lifecycle.viewmodel.viewModelFactory
25 import kotlinx.coroutines.flow.Flow
26 import kotlinx.coroutines.flow.MutableStateFlow
27 import kotlinx.coroutines.flow.combine
28 import kotlinx.coroutines.flow.transformLatest
29 import kotlinx.coroutines.flow.update
30 
31 /**
32  * This class is a wrapper around the [FingerprintEnrollViewModel] and decides when the user should
33  * or should not be enrolling.
34  */
35 class FingerprintEnrollEnrollingViewModel(
36   private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
37   backgroundViewModel: BackgroundViewModel,
38 ) : ViewModel() {
39 
40   private val _didTryEnrollment = MutableStateFlow(false)
41   private val _userDidEnroll = MutableStateFlow(false)
42   /** Indicates if the enrollment flow should be running. */
43   val enrollFlowShouldBeRunning: Flow<Boolean> =
44     _userDidEnroll.combine(backgroundViewModel.background) { shouldEnroll, isInBackground ->
45       if (isInBackground) {
46         false
47       } else {
48         shouldEnroll
49       }
50     }
51 
52   /**
53    * Used to indicate the consumer of the view model is ready for an enrollment. Note that this does
54    * not necessarily try an enrollment.
55    */
56   fun canEnroll() {
57     // Update _consumerShouldEnroll after updating the other values.
58     if (!_didTryEnrollment.value) {
59       _didTryEnrollment.update { true }
60       _userDidEnroll.update { true }
61     }
62   }
63 
64   /** Used to indicate to stop the enrollment. */
65   fun stopEnroll() {
66     _userDidEnroll.update { false }
67   }
68 
69   /** Collects the enrollment flow based on [enrollFlowShouldBeRunning] */
70   val enrollFlow =
71     enrollFlowShouldBeRunning.transformLatest {
72       if (it) {
73         fingerprintEnrollViewModel.enrollFlow.collect { event -> emit(event) }
74       }
75     }
76 
77   /** Indicates enrollment to start */
78   fun enroll(enrollOptions: FingerprintEnrollOptions) {
79     fingerprintEnrollViewModel.enroll(enrollOptions)
80   }
81 
82   companion object {
83     val Factory: ViewModelProvider.Factory = viewModelFactory {
84       initializer {
85         val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
86         FingerprintEnrollEnrollingViewModel(
87           provider[FingerprintEnrollViewModel::class],
88           provider[BackgroundViewModel::class],
89         )
90       }
91     }
92   }
93 }
94