1 /* 2 * 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 com.android.settings.biometrics.fingerprint2.lib.model.FastEnroll 20 import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow 21 import com.android.systemui.biometrics.shared.model.FingerprintSensor 22 23 /** 24 * A [FingerprintAction] event notifies the current [FingerprintNavigationStep] that an event 25 * occurred. Depending on the type of [FingerprintAction] and the current 26 * [FingerprintNavigationStep], the navstep will potentially produce a new 27 * [FingerprintNavigationStep] indicating either 1). Control flow has changed 2). The activity has 28 * finished 3). A transition is required 29 */ 30 enum class FingerprintAction { 31 NEXT, 32 PREV, 33 CONFIRM_DEVICE_SUCCESS, 34 CONFIRM_DEVICE_FAIL, 35 TRANSITION_FINISHED, 36 DID_GO_TO_BACKGROUND, 37 ACTIVITY_CREATED, 38 NEGATIVE_BUTTON_PRESSED, 39 USER_CLICKED_FINISH, 40 ADD_ANOTHER, 41 } 42 43 /** State that can be used to help a [FingerprintNavigationStep] determine the next step to take. */ 44 data class NavigationState( 45 val flowType: FingerprintFlow, 46 val hasConfirmedDeviceCredential: Boolean, 47 val fingerprintSensor: FingerprintSensor?, 48 ) 49 50 /** 51 * A generic interface for operating on (state, action) -> state? which will produce either another 52 * FingerprintNavStep if something is required, or nothing. 53 * 54 * Note during the lifetime of the Activity, their should only be one [FingerprintNavigationStep] at 55 * a time. 56 */ 57 sealed interface FingerprintNavigationStep { updatenull58 fun update(state: NavigationState, action: FingerprintAction): FingerprintNavigationStep? 59 60 /** 61 * This indicates that a transition should occur from one screen to another. This class should 62 * contain all necessary info about the transition. 63 * 64 * A transition step will cause a screen to change ownership from the current screen to the 65 * [nextUiStep], after the transition has been completed and a 66 * [FingerprintAction.TRANSITION_FINISHED] has been sent, the [nextUiStep] will be given control. 67 */ 68 class TransitionStep(val nextUiStep: UiStep) : FingerprintNavigationStep { 69 override fun update( 70 state: NavigationState, 71 action: FingerprintAction, 72 ): FingerprintNavigationStep? { 73 return when (action) { 74 FingerprintAction.TRANSITION_FINISHED -> nextUiStep 75 else -> null 76 } 77 } 78 79 override fun toString(): String = "TransitionStep(nextUiStep=$nextUiStep)" 80 } 81 82 /** Indicates we should finish the enrolling activity */ 83 data class Finish(val result: Int?) : FingerprintNavigationStep { updatenull84 override fun update( 85 state: NavigationState, 86 action: FingerprintAction, 87 ): FingerprintNavigationStep? = null 88 } 89 90 /** UiSteps should have a 1 to 1 mapping between each screen of FingerprintEnrollment */ 91 sealed class UiStep( 92 val enterTransition: Transition = Transition.EnterFromRight, 93 val exitTransition: Transition = Transition.ExitToLeft, 94 ) : FingerprintNavigationStep 95 96 /** This is the landing page for enrollment, where no content is shown. */ 97 data object Init : UiStep() { 98 override fun update( 99 state: NavigationState, 100 action: FingerprintAction, 101 ): FingerprintNavigationStep? { 102 return when (action) { 103 FingerprintAction.ACTIVITY_CREATED -> { 104 if (!state.hasConfirmedDeviceCredential) { 105 TransitionStep(ConfirmDeviceCredential) 106 } else if (state.flowType is FastEnroll) { 107 TransitionStep(Enrollment(state.fingerprintSensor!!)) 108 } else { 109 TransitionStep(Introduction()) 110 } 111 } 112 else -> null 113 } 114 } 115 } 116 117 /** Indicates the ConfirmDeviceCredential activity is being presented to the user */ 118 data object ConfirmDeviceCredential : UiStep() { updatenull119 override fun update( 120 state: NavigationState, 121 action: FingerprintAction, 122 ): FingerprintNavigationStep? { 123 return when (action) { 124 FingerprintAction.CONFIRM_DEVICE_SUCCESS -> TransitionStep(Introduction()) 125 FingerprintAction.CONFIRM_DEVICE_FAIL -> Finish(null) 126 else -> null 127 } 128 } 129 } 130 131 /** Indicates the FingerprintIntroduction screen is being presented to the user */ 132 class Introduction( 133 enterTransition: Transition = Transition.EnterFromRight, 134 exitTransition: Transition = Transition.ExitToLeft, 135 ) : UiStep(enterTransition, exitTransition) { updatenull136 override fun update( 137 state: NavigationState, 138 action: FingerprintAction, 139 ): FingerprintNavigationStep? { 140 return when (action) { 141 FingerprintAction.NEXT -> TransitionStep(Education(state.fingerprintSensor!!)) 142 FingerprintAction.NEGATIVE_BUTTON_PRESSED, 143 FingerprintAction.PREV -> Finish(null) 144 else -> null 145 } 146 } 147 } 148 149 /** Indicates the FingerprintEducation screen is being presented to the user */ 150 class Education( 151 val sensor: FingerprintSensor, 152 enterTransition: Transition = Transition.EnterFromRight, 153 exitTransition: Transition = Transition.ExitToLeft, 154 ) : UiStep(enterTransition, exitTransition) { updatenull155 override fun update( 156 state: NavigationState, 157 action: FingerprintAction, 158 ): FingerprintNavigationStep? { 159 return when (action) { 160 FingerprintAction.NEXT -> TransitionStep(Enrollment(state.fingerprintSensor!!)) 161 FingerprintAction.NEGATIVE_BUTTON_PRESSED, 162 FingerprintAction.PREV -> 163 TransitionStep(Introduction(Transition.EnterFromLeft, Transition.ExitToRight)) 164 else -> null 165 } 166 } 167 } 168 169 /** Indicates the Enrollment screen is being presented to the user */ 170 data class Enrollment(val sensor: FingerprintSensor) : UiStep() { updatenull171 override fun update( 172 state: NavigationState, 173 action: FingerprintAction, 174 ): FingerprintNavigationStep? { 175 return when (action) { 176 FingerprintAction.NEXT -> TransitionStep(Confirmation) 177 FingerprintAction.NEGATIVE_BUTTON_PRESSED, 178 FingerprintAction.USER_CLICKED_FINISH, 179 FingerprintAction.DID_GO_TO_BACKGROUND -> Finish(null) 180 else -> null 181 } 182 } 183 } 184 185 /** Indicates the Confirmation screen is being presented to the user */ 186 data object Confirmation : UiStep() { updatenull187 override fun update( 188 state: NavigationState, 189 action: FingerprintAction, 190 ): FingerprintNavigationStep? { 191 return when (action) { 192 FingerprintAction.NEXT -> Finish(null) 193 FingerprintAction.PREV -> 194 TransitionStep( 195 Education(state.fingerprintSensor!!, Transition.EnterFromLeft, Transition.ExitToRight) 196 ) 197 FingerprintAction.ADD_ANOTHER -> TransitionStep(Enrollment(state.fingerprintSensor!!)) 198 else -> null 199 } 200 } 201 } 202 } 203