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 package com.android.settings.biometrics2.ui.view
17 
18 import android.annotation.StyleRes
19 import android.content.Intent
20 import android.content.res.ColorStateList
21 import android.content.res.Configuration
22 import android.content.res.Resources.Theme
23 import android.graphics.Color
24 import android.os.Bundle
25 import android.os.SystemClock
26 import android.util.Log
27 import androidx.activity.result.ActivityResult
28 import androidx.activity.result.ActivityResultCallback
29 import androidx.activity.result.ActivityResultLauncher
30 import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
31 import androidx.annotation.ColorInt
32 import androidx.fragment.app.Fragment
33 import androidx.fragment.app.FragmentActivity
34 import androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE
35 import androidx.lifecycle.Lifecycle
36 import androidx.lifecycle.Observer
37 import androidx.lifecycle.ViewModelProvider
38 import androidx.lifecycle.lifecycleScope
39 import androidx.lifecycle.repeatOnLifecycle
40 import androidx.lifecycle.viewmodel.CreationExtras
41 import androidx.lifecycle.viewmodel.MutableCreationExtras
42 import com.android.settings.R
43 import com.android.settings.Utils
44 import com.android.settings.biometrics.BiometricEnrollBase
45 import com.android.settings.biometrics2.factory.BiometricsViewModelFactory
46 import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR_KEY
47 import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CREDENTIAL_MODEL_KEY
48 import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.ENROLLMENT_REQUEST_KEY
49 import com.android.settings.biometrics2.ui.model.CredentialModel
50 import com.android.settings.biometrics2.ui.model.EnrollmentRequest
51 import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel
52 import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator
53 import com.android.settings.biometrics2.ui.viewmodel.CredentialAction
54 import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel
55 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel
56 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE
57 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG
58 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
59 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP
60 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction
61 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
62 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
63 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG
64 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP
65 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START
66 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorAction
67 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel
68 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK
69 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK
70 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FingerprintEnrollFinishAction
71 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction
72 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel
73 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
74 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel
75 import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
76 import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
77 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
78 import com.google.android.setupdesign.util.ThemeHelper
79 import kotlinx.coroutines.launch
80 
81 /**
82  * Fingerprint enrollment activity implementation
83  */
84 open class FingerprintEnrollmentActivity : FragmentActivity() {
85     /** SetupWizard activity*/
86     class SetupActivity : FingerprintEnrollmentActivity()
87 
88     /** Internal activity for FingerprintSettings */
89     class InternalActivity : FingerprintEnrollmentActivity()
90 
91     private val viewModelProvider: ViewModelProvider by lazy {
92         ViewModelProvider(this)
93     }
94 
95     private val viewModel: FingerprintEnrollmentViewModel by lazy {
96         viewModelProvider[FingerprintEnrollmentViewModel::class.java]
97     }
98 
99     private val autoCredentialViewModel: AutoCredentialViewModel by lazy {
100         viewModelProvider[AutoCredentialViewModel::class.java]
101     }
102 
103     private val introViewModel: FingerprintEnrollIntroViewModel by lazy {
104         viewModelProvider[FingerprintEnrollIntroViewModel::class.java]
105     }
106 
107     private val findSensorViewModel: FingerprintEnrollFindSensorViewModel by lazy {
108         viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
109     }
110 
111     private val progressViewModel: FingerprintEnrollProgressViewModel by lazy {
112         viewModelProvider[FingerprintEnrollProgressViewModel::class.java]
113     }
114 
115     private val enrollingViewModel: FingerprintEnrollEnrollingViewModel by lazy {
116         viewModelProvider[FingerprintEnrollEnrollingViewModel::class.java]
117     }
118 
119     private val finishViewModel: FingerprintEnrollFinishViewModel by lazy {
120         viewModelProvider[FingerprintEnrollFinishViewModel::class.java]
121     }
122 
123     private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel by lazy {
124         viewModelProvider[FingerprintEnrollErrorDialogViewModel::class.java]
125     }
126 
127     private var isFirstFragmentAdded = false
128 
129     private val findSensorActionObserver = Observer<Int?> { action ->
130         if (DEBUG) {
131             Log.d(TAG, "findSensorActionObserver($action)")
132         }
133         action?.let { onFindSensorAction(it) }
134     }
135 
136     private val enrollingActionObserver = Observer<Int?> { action ->
137         if (DEBUG) {
138             Log.d(TAG, "enrollingActionObserver($action)")
139         }
140         action?.let { onEnrollingAction(it) }
141     }
142 
143     private val finishActionObserver = Observer<Int?> { action ->
144         if (DEBUG) {
145             Log.d(TAG, "finishActionObserver($action)")
146         }
147         action?.let { onFinishAction(it) }
148     }
149 
150     private val chooseLockResultCallback: ActivityResultCallback<ActivityResult> =
151         ActivityResultCallback { result ->
152             onChooseOrConfirmLockResult(true /* isChooseLock */, result)
153         }
154 
155     private val chooseLockLauncher: ActivityResultLauncher<Intent> =
156         registerForActivityResult(StartActivityForResult(), chooseLockResultCallback)
157 
158     override fun onCreate(savedInstanceState: Bundle?) {
159         super.onCreate(savedInstanceState)
160 
161         // Theme
162         setTheme(viewModel.request.theme)
163         ThemeHelper.trySetDynamicColor(this)
164         window.statusBarColor = Color.TRANSPARENT
165 
166         // fragment
167         setContentView(R.layout.biometric_enrollment_container)
168         val fragment: Fragment? = supportFragmentManager.findFragmentById(
169             R.id.fragment_container_view
170         )
171         Log.d(
172             TAG,
173             "onCreate() has savedInstance:$(savedInstanceState != null), fragment:$fragment"
174         )
175 
176         isFirstFragmentAdded = (savedInstanceState != null)
177         if (fragment == null) {
178             checkCredential()
179             if (viewModel.request.isSkipFindSensor) {
180                 startEnrollingFragment()
181             } else if (viewModel.request.isSkipIntro) {
182                 startFindSensorFragment()
183             } else {
184                 startIntroFragment()
185             }
186         } else {
187             val tag: String? = fragment.tag
188             if (INTRO_TAG == tag) {
189                 attachIntroViewModel()
190             } else if (FIND_SENSOR_TAG == tag) {
191                 attachFindSensorViewModel()
192                 attachIntroViewModel()
193             } else if (ENROLLING_TAG == tag) {
194                 attachEnrollingViewModel()
195                 attachFindSensorViewModel()
196                 attachIntroViewModel()
197             } else if (FINISH_TAG == tag) {
198                 attachFinishViewModel()
199                 attachFindSensorViewModel()
200                 attachIntroViewModel()
201             } else {
202                 Log.e(TAG, "fragment tag $tag not found")
203                 finish()
204                 return
205             }
206         }
207 
208         collectFlows()
209     }
210 
211     private fun collectFlows() {
212         lifecycleScope.launch {
213             repeatOnLifecycle(Lifecycle.State.STARTED) {
214                 viewModel.setResultFlow.collect {
215                     Log.d(TAG, "setResultLiveData($it)")
216                     onSetActivityResult(it)
217                 }
218             }
219             repeatOnLifecycle(Lifecycle.State.STARTED) {
220                 autoCredentialViewModel.generateChallengeFailedFlow.collect {
221                     Log.d(TAG, "generateChallengeFailedFlow($it)")
222                     onSetActivityResult(ActivityResult(RESULT_CANCELED, null))
223                 }
224             }
225             repeatOnLifecycle(Lifecycle.State.STARTED) {
226                 errorDialogViewModel.newDialogFlow.collect {
227                     Log.d(TAG, "newErrorDialogFlow($it)")
228                     FingerprintEnrollErrorDialog.newInstance(it).show(
229                         supportFragmentManager,
230                         ERROR_DIALOG_TAG
231                     )
232                 }
233             }
234             repeatOnLifecycle(Lifecycle.State.STARTED) {
235                 errorDialogViewModel.setResultFlow.collect {
236                     Log.d(TAG, "errorDialogSetResultFlow($it)")
237                     when (it) {
238                         FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH -> onSetActivityResult(
239                             ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null)
240                         )
241 
242                         FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT -> onSetActivityResult(
243                             ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null)
244                         )
245                     }
246                 }
247             }
248         }
249     }
250 
251     private fun startFragment(fragmentClass: Class<out Fragment>, tag: String) {
252         if (!isFirstFragmentAdded) {
253             supportFragmentManager.beginTransaction()
254                 .setReorderingAllowed(true)
255                 .replace(R.id.fragment_container_view, fragmentClass, null, tag)
256                 .commit()
257             isFirstFragmentAdded = true
258         } else {
259             supportFragmentManager.beginTransaction()
260                 .setReorderingAllowed(true)
261                 .setCustomAnimations(
262                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_enter_dynamic_color,
263                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_exit,
264                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_enter_dynamic_color,
265                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_exit
266                 )
267                 .replace(R.id.fragment_container_view, fragmentClass, null, tag)
268                 .addToBackStack(tag)
269                 .commit()
270         }
271     }
272 
273     private fun startIntroFragment() {
274         attachIntroViewModel()
275         startFragment(FingerprintEnrollIntroFragment::class.java, INTRO_TAG)
276     }
277 
278     private fun attachIntroViewModel() {
279         val request: EnrollmentRequest = viewModel.request
280         if (request.isSkipIntro || request.isSkipFindSensor) {
281             return
282         }
283         lifecycleScope.launch {
284             repeatOnLifecycle(Lifecycle.State.STARTED) {
285                 introViewModel.actionFlow.collect(this@FingerprintEnrollmentActivity::onIntroAction)
286             }
287         }
288     }
289 
290     // We need to make sure token is valid before entering find sensor page
291     private fun startFindSensorFragment() {
292         // Always setToken into progressViewModel even it is not necessary action for UDFPS
293         progressViewModel.setToken(autoCredentialViewModel.token)
294         attachFindSensorViewModel()
295         val fragmentClass: Class<out Fragment> = if (viewModel.canAssumeUdfps) {
296             FingerprintEnrollFindUdfpsFragment::class.java
297         } else if (viewModel.canAssumeSfps) {
298             FingerprintEnrollFindSfpsFragment::class.java
299         } else {
300             FingerprintEnrollFindRfpsFragment::class.java
301         }
302         startFragment(fragmentClass, FIND_SENSOR_TAG)
303     }
304 
305     private fun attachFindSensorViewModel() {
306         if (viewModel.request.isSkipFindSensor) {
307             return
308         }
309         findSensorViewModel.let {
310             // Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
311             // recreate, like press 'Start' then press 'back' in FingerprintEnrollEnrolling
312             // activity.
313             it.clearActionLiveData()
314             it.actionLiveData.observe(this, findSensorActionObserver)
315         }
316     }
317 
318     private fun startEnrollingFragment() {
319         // Always setToken into progressViewModel even it is not necessary action for SFPS or RFPS
320         progressViewModel.setToken(autoCredentialViewModel.token)
321         attachEnrollingViewModel()
322         val fragmentClass: Class<out Fragment> = if (viewModel.canAssumeUdfps) {
323             FingerprintEnrollEnrollingUdfpsFragment::class.java
324         } else if (viewModel.canAssumeSfps) {
325             FingerprintEnrollEnrollingSfpsFragment::class.java
326         } else {
327             FingerprintEnrollEnrollingRfpsFragment::class.java
328         }
329         startFragment(fragmentClass, ENROLLING_TAG)
330     }
331 
332     private fun attachEnrollingViewModel() {
333         enrollingViewModel.let {
334             it.clearActionLiveData()
335             it.actionLiveData.observe(this, enrollingActionObserver)
336         }
337     }
338 
339     private fun startFinishFragment() {
340         viewModel.isNewFingerprintAdded = true
341         attachFinishViewModel()
342         if (viewModel.request.isSkipFindSensor) {
343             // Set page to Finish
344             supportFragmentManager.beginTransaction()
345                 .setReorderingAllowed(true)
346                 .setCustomAnimations(
347                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_enter_dynamic_color,
348                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_exit,
349                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_enter_dynamic_color,
350                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_exit
351                 )
352                 .replace(
353                     R.id.fragment_container_view,
354                     FingerprintEnrollFinishFragment::class.java,
355                     null,
356                     FINISH_TAG
357                 )
358                 .commit()
359         } else {
360             // Remove Enrolling page
361             supportFragmentManager.popBackStack()
362 
363             // Remove old Finish page if any
364             if (supportFragmentManager.findFragmentByTag(FINISH_TAG) != null) {
365                 supportFragmentManager.popBackStack(FINISH_TAG, POP_BACK_STACK_INCLUSIVE)
366             }
367 
368             // Remove FindSensor page if maxEnrolled
369             if (viewModel.isMaxEnrolledReached(autoCredentialViewModel.userId)
370                 && supportFragmentManager.findFragmentByTag(FIND_SENSOR_TAG) != null
371             ) {
372                 supportFragmentManager.popBackStack(FIND_SENSOR_TAG, POP_BACK_STACK_INCLUSIVE)
373             }
374 
375             // Add Finish page
376             supportFragmentManager.beginTransaction()
377                 .setReorderingAllowed(true)
378                 .setCustomAnimations(
379                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_enter_dynamic_color,
380                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_exit,
381                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_enter_dynamic_color,
382                     com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_exit
383                 )
384                 .replace(
385                     R.id.fragment_container_view,
386                     FingerprintEnrollFinishFragment::class.java,
387                     null,
388                     FINISH_TAG
389                 )
390                 .addToBackStack(FINISH_TAG)
391                 .commit()
392         }
393     }
394 
395     private fun attachFinishViewModel() {
396         finishViewModel.let {
397             it.clearActionLiveData()
398             it.actionLiveData.observe(this, finishActionObserver)
399         }
400     }
401 
402     private fun onSetActivityResult(result: ActivityResult) {
403         val challengeExtras: Bundle? = autoCredentialViewModel.createGeneratingChallengeExtras()
404         val overrideResult: ActivityResult = viewModel.getOverrideActivityResult(
405             result, challengeExtras
406         )
407         if (DEBUG) {
408             Log.d(
409                 TAG, "onSetActivityResult(" + result + "), override:" + overrideResult
410                         + ") challengeExtras:" + challengeExtras
411             )
412         }
413         setResult(overrideResult.resultCode, overrideResult.data)
414         finish()
415     }
416 
417     private fun checkCredential() {
418         when (autoCredentialViewModel.checkCredential(lifecycleScope)) {
419             CredentialAction.FAIL_NEED_TO_CHOOSE_LOCK -> {
420                 val intent: Intent = autoCredentialViewModel.createChooseLockIntent(
421                     this,
422                     viewModel.request.isSuw,
423                     viewModel.request.suwExtras
424                 )
425                 if (!viewModel.isWaitingActivityResult.compareAndSet(false, true)) {
426                     Log.w(TAG, "chooseLock, fail to set isWaiting flag to true")
427                 }
428                 chooseLockLauncher.launch(intent)
429                 return
430             }
431 
432             CredentialAction.FAIL_NEED_TO_CONFIRM_LOCK -> {
433                 val launched: Boolean = autoCredentialViewModel.createConfirmLockLauncher(
434                     this,
435                     LAUNCH_CONFIRM_LOCK_ACTIVITY,
436                     getString(R.string.security_settings_fingerprint_preference_title)
437                 ).launch()
438                 if (!launched) {
439                     // This shouldn't happen, as we should only end up at this step if a lock thingy
440                     // is already set.
441                     Log.e(TAG, "confirmLock, launched is true")
442                     finish()
443                 } else if (!viewModel.isWaitingActivityResult.compareAndSet(false, true)) {
444                     Log.w(TAG, "confirmLock, fail to set isWaiting flag to true")
445                 }
446                 return
447             }
448 
449             CredentialAction.CREDENTIAL_VALID,
450             CredentialAction.IS_GENERATING_CHALLENGE -> {}
451         }
452     }
453 
454     private fun onChooseOrConfirmLockResult(
455         isChooseLock: Boolean,
456         activityResult: ActivityResult
457     ) {
458         if (!viewModel.isWaitingActivityResult.compareAndSet(true, false)) {
459             Log.w(TAG, "isChooseLock:$isChooseLock, fail to unset waiting flag")
460         }
461         if (!autoCredentialViewModel.generateChallengeAsCredentialActivityResult(
462                 isChooseLock,
463                 activityResult,
464                 lifecycleScope
465             )
466         ) {
467             onSetActivityResult(activityResult)
468         }
469     }
470 
471     private fun onIntroAction(action: FingerprintEnrollIntroAction) {
472         Log.d(TAG, "onIntroAction($action)")
473         when (action) {
474             FingerprintEnrollIntroAction.DONE_AND_FINISH -> {
475                 onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null))
476                 return
477             }
478 
479             FingerprintEnrollIntroAction.SKIP_OR_CANCEL -> {
480                 onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_SKIP, null))
481                 return
482             }
483 
484             FingerprintEnrollIntroAction.CONTINUE_ENROLL -> {
485                 startFindSensorFragment()
486             }
487         }
488     }
489 
490     private fun onFindSensorAction(@FingerprintEnrollFindSensorAction action: Int) {
491         when (action) {
492             FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP -> {
493                 onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_SKIP, null))
494                 return
495             }
496 
497             FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG -> {
498                 SkipSetupFindFpsDialog().show(
499                     supportFragmentManager,
500                     SKIP_SETUP_FIND_FPS_DIALOG_TAG
501                 )
502                 return
503             }
504 
505             FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START -> {
506                 startEnrollingFragment()
507             }
508         }
509     }
510 
511     private fun onEnrollingAction(@FingerprintEnrollEnrollingAction action: Int) {
512         when (action) {
513             FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE -> {
514                 startFinishFragment()
515             }
516 
517             FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP -> {
518                 onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_SKIP, null))
519             }
520 
521             FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG -> {
522                 FingerprintEnrollEnrollingIconTouchDialog().show(
523                     supportFragmentManager,
524                     SKIP_SETUP_FIND_FPS_DIALOG_TAG
525                 )
526             }
527 
528             FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED -> {
529                 if (supportFragmentManager.backStackEntryCount > 0) {
530                     supportFragmentManager.popBackStack()
531                 } else {
532                     onSetActivityResult(ActivityResult(RESULT_CANCELED, null))
533                 }
534             }
535         }
536     }
537 
538     private fun onFinishAction(@FingerprintEnrollFinishAction action: Int) {
539         when (action) {
540             FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK -> {
541                 startEnrollingFragment()
542             }
543 
544             FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK -> {
545                 val data: Intent? = if (viewModel.request.isSuw) {
546                     Intent().also {
547                         it.putExtras(
548                             viewModel.getSuwFingerprintCountExtra(
549                                 autoCredentialViewModel.userId
550                             )
551                         )
552                     }
553                 } else {
554                     null
555                 }
556                 onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_FINISHED, data))
557             }
558         }
559     }
560 
561     override fun onPause() {
562         super.onPause()
563         viewModel.checkFinishActivityDuringOnPause(
564             isFinishing,
565             isChangingConfigurations,
566             lifecycleScope
567         )
568     }
569 
570     override fun onDestroy() {
571         viewModel.updateFingerprintSuggestionEnableState(autoCredentialViewModel.userId)
572         super.onDestroy()
573     }
574 
575     override fun onApplyThemeResource(theme: Theme, @StyleRes resid: Int, first: Boolean) {
576         theme.applyStyle(R.style.SetupWizardPartnerResource, true)
577         super.onApplyThemeResource(theme, resid, first)
578     }
579 
580     @Deprecated("Deprecated in Java")
581     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
582         if (requestCode == LAUNCH_CONFIRM_LOCK_ACTIVITY) {
583             onChooseOrConfirmLockResult(false, ActivityResult(resultCode, data))
584             return
585         }
586         super.onActivityResult(requestCode, resultCode, data)
587     }
588 
589     override val defaultViewModelCreationExtras: CreationExtras
590         get() = MutableCreationExtras(super.defaultViewModelCreationExtras).also {
591             it[CHALLENGE_GENERATOR_KEY] = FingerprintChallengeGenerator(
592                 featureFactory.biometricsRepositoryProvider.getFingerprintRepository(application)!!
593             )
594             it[ENROLLMENT_REQUEST_KEY] =
595                 EnrollmentRequest(intent, applicationContext, this is SetupActivity)
596             it[CREDENTIAL_MODEL_KEY] =
597                 CredentialModel(intent.extras, SystemClock.elapsedRealtimeClock())
598         }
599 
600     override val defaultViewModelProviderFactory: ViewModelProvider.Factory
601         get() = BiometricsViewModelFactory()
602 
603     override fun onAttachedToWindow() {
604         super.onAttachedToWindow()
605         window.statusBarColor = backgroundColor
606     }
607 
608     @get:ColorInt
609     private val backgroundColor: Int
610         get() {
611             val stateList: ColorStateList? =
612                 Utils.getColorAttr(this, android.R.attr.windowBackground)
613             return stateList?.defaultColor ?: Color.TRANSPARENT
614         }
615 
616     override fun onConfigurationChanged(newConfig: Configuration) {
617         viewModelProvider[DeviceFoldedViewModel::class.java].onConfigurationChanged(newConfig)
618         super.onConfigurationChanged(newConfig)
619     }
620 
621     companion object {
622         private const val DEBUG = false
623         private const val TAG = "FingerprintEnrollmentActivity"
624         protected const val LAUNCH_CONFIRM_LOCK_ACTIVITY = 1
625 
626         private const val INTRO_TAG = "intro"
627         private const val FIND_SENSOR_TAG = "find-sensor"
628         private const val ENROLLING_TAG = "enrolling"
629         private const val FINISH_TAG = "finish"
630         private const val SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog"
631         private const val ERROR_DIALOG_TAG = "error-dialog"
632     }
633 }
634