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