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 18 package com.android.systemui.biometrics.ui.viewmodel 19 20 import android.annotation.RawRes 21 import android.content.res.Configuration 22 import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor 23 import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor 24 import com.android.systemui.biometrics.shared.model.DisplayRotation 25 import com.android.systemui.biometrics.shared.model.FingerprintSensorType 26 import com.android.systemui.res.R 27 import com.android.systemui.util.kotlin.combine 28 import kotlinx.coroutines.flow.Flow 29 import kotlinx.coroutines.flow.MutableStateFlow 30 import kotlinx.coroutines.flow.combine 31 import kotlinx.coroutines.flow.distinctUntilChanged 32 import kotlinx.coroutines.flow.flatMapLatest 33 import kotlinx.coroutines.flow.flowOf 34 35 /** Models UI of [BiometricPromptLayout.iconView] */ 36 class PromptIconViewModel( 37 promptViewModel: PromptViewModel, 38 private val displayStateInteractor: DisplayStateInteractor, 39 promptSelectorInteractor: PromptSelectorInteractor, 40 ) { 41 42 /** Auth types for the UI to display. */ 43 enum class AuthType { 44 Fingerprint, 45 Face, 46 Coex, 47 } 48 49 /** 50 * Indicates what auth type the UI currently displays. Fingerprint-only auth -> Fingerprint 51 * Face-only auth -> Face Co-ex auth, implicit flow -> Face Co-ex auth, explicit flow -> Coex 52 */ 53 val activeAuthType: Flow<AuthType> = 54 combine( 55 promptViewModel.modalities.distinctUntilChanged(), 56 promptViewModel.faceMode.distinctUntilChanged(), 57 ) { modalities, faceMode -> 58 if (modalities.hasFaceAndFingerprint && !faceMode) { 59 AuthType.Coex 60 } else if (modalities.hasFaceOnly || faceMode) { 61 AuthType.Face 62 } else if (modalities.hasFingerprintOnly) { 63 AuthType.Fingerprint 64 } else { 65 // TODO(b/288175072): Remove, currently needed for transition to credential view 66 AuthType.Fingerprint 67 } 68 } 69 70 /** Whether an error message is currently being shown. */ 71 val showingError = promptViewModel.showingError 72 73 /** Whether the previous icon shown displayed an error. */ 74 private val _previousIconWasError: MutableStateFlow<Boolean> = MutableStateFlow(false) 75 76 fun setPreviousIconWasError(previousIconWasError: Boolean) { 77 _previousIconWasError.value = previousIconWasError 78 } 79 80 val iconSize: Flow<Pair<Int, Int>> = 81 combine( 82 promptViewModel.position, 83 activeAuthType, 84 promptViewModel.legacyFingerprintSensorWidth, 85 promptViewModel.legacyFingerprintSensorHeight, 86 ) { _, activeAuthType, fingerprintSensorWidth, fingerprintSensorHeight -> 87 if (activeAuthType == AuthType.Face) { 88 Pair(promptViewModel.faceIconWidth, promptViewModel.faceIconHeight) 89 } else { 90 Pair(fingerprintSensorWidth, fingerprintSensorHeight) 91 } 92 } 93 94 /** Current BiometricPromptLayout.iconView asset. */ 95 val iconAsset: Flow<Int> = 96 activeAuthType.flatMapLatest { activeAuthType: AuthType -> 97 when (activeAuthType) { 98 AuthType.Fingerprint -> 99 combine( 100 displayStateInteractor.currentRotation, 101 displayStateInteractor.isInRearDisplayMode, 102 promptSelectorInteractor.fingerprintSensorType, 103 promptViewModel.isAuthenticated, 104 promptViewModel.isAuthenticating, 105 promptViewModel.showingError, 106 ) { 107 rotation: DisplayRotation, 108 isInRearDisplayMode: Boolean, 109 sensorType: FingerprintSensorType, 110 authState: PromptAuthState, 111 isAuthenticating: Boolean, 112 showingError: Boolean -> 113 when (sensorType) { 114 FingerprintSensorType.POWER_BUTTON -> 115 getSfpsIconViewAsset( 116 rotation, 117 isInRearDisplayMode, 118 authState.isAuthenticated, 119 isAuthenticating, 120 showingError, 121 ) 122 else -> 123 getFingerprintIconViewAsset( 124 authState.isAuthenticated, 125 isAuthenticating, 126 showingError, 127 ) 128 } 129 } 130 AuthType.Face -> 131 combine( 132 promptViewModel.isAuthenticated.distinctUntilChanged(), 133 promptViewModel.isAuthenticating.distinctUntilChanged(), 134 promptViewModel.isPendingConfirmation.distinctUntilChanged(), 135 promptViewModel.showingError.distinctUntilChanged(), 136 ) { 137 authState: PromptAuthState, 138 isAuthenticating: Boolean, 139 isPendingConfirmation: Boolean, 140 showingError: Boolean -> 141 getFaceIconViewAsset( 142 authState, 143 isAuthenticating, 144 isPendingConfirmation, 145 showingError, 146 ) 147 } 148 AuthType.Coex -> 149 combine( 150 displayStateInteractor.currentRotation, 151 displayStateInteractor.isInRearDisplayMode, 152 promptSelectorInteractor.fingerprintSensorType, 153 promptViewModel.isAuthenticated, 154 promptViewModel.isAuthenticating, 155 promptViewModel.isPendingConfirmation, 156 promptViewModel.showingError, 157 ) { 158 rotation: DisplayRotation, 159 isInRearDisplayMode: Boolean, 160 sensorType: FingerprintSensorType, 161 authState: PromptAuthState, 162 isAuthenticating: Boolean, 163 isPendingConfirmation: Boolean, 164 showingError: Boolean -> 165 when (sensorType) { 166 FingerprintSensorType.POWER_BUTTON -> 167 getCoexSfpsIconViewAsset( 168 rotation, 169 isInRearDisplayMode, 170 authState, 171 isAuthenticating, 172 isPendingConfirmation, 173 showingError, 174 ) 175 else -> 176 getCoexIconViewAsset( 177 authState, 178 isAuthenticating, 179 isPendingConfirmation, 180 showingError, 181 ) 182 } 183 } 184 } 185 } 186 187 private fun getFingerprintIconViewAsset( 188 isAuthenticated: Boolean, 189 isAuthenticating: Boolean, 190 showingError: Boolean, 191 ): Int { 192 return if (isAuthenticated) { 193 if (_previousIconWasError.value) { 194 R.raw.fingerprint_dialogue_error_to_success_lottie 195 } else { 196 R.raw.fingerprint_dialogue_fingerprint_to_success_lottie 197 } 198 } else if (isAuthenticating) { 199 if (_previousIconWasError.value) { 200 R.raw.fingerprint_dialogue_error_to_fingerprint_lottie 201 } else { 202 R.raw.fingerprint_dialogue_fingerprint_to_error_lottie 203 } 204 } else if (showingError) { 205 R.raw.fingerprint_dialogue_fingerprint_to_error_lottie 206 } else { 207 -1 208 } 209 } 210 211 @RawRes 212 private fun getSfpsIconViewAsset( 213 rotation: DisplayRotation, 214 isInRearDisplayMode: Boolean, 215 isAuthenticated: Boolean, 216 isAuthenticating: Boolean, 217 showingError: Boolean, 218 ): Int { 219 return if (isAuthenticated) { 220 if (_previousIconWasError.value) { 221 R.raw.biometricprompt_sfps_error_to_success 222 } else { 223 getSfpsAsset_fingerprintToSuccess(rotation, isInRearDisplayMode) 224 } 225 } else if (isAuthenticating) { 226 if (_previousIconWasError.value) { 227 getSfpsAsset_errorToFingerprint(rotation, isInRearDisplayMode) 228 } else { 229 getSfpsAsset_fingerprintAuthenticating(isInRearDisplayMode) 230 } 231 } else if (showingError) { 232 getSfpsAsset_fingerprintToError(rotation, isInRearDisplayMode) 233 } else { 234 -1 235 } 236 } 237 238 @RawRes 239 private fun getFaceIconViewAsset( 240 authState: PromptAuthState, 241 isAuthenticating: Boolean, 242 isPendingConfirmation: Boolean, 243 showingError: Boolean, 244 ): Int { 245 return if (authState.isAuthenticated && isPendingConfirmation) { 246 R.raw.face_dialog_wink_from_dark 247 } else if (authState.isAuthenticated) { 248 R.raw.face_dialog_dark_to_checkmark 249 } else if (isAuthenticating) { 250 R.raw.face_dialog_authenticating 251 } else if (showingError) { 252 R.raw.face_dialog_dark_to_error 253 } else if (_previousIconWasError.value) { 254 R.raw.face_dialog_error_to_idle 255 } else { 256 R.raw.face_dialog_idle_static 257 } 258 } 259 260 @RawRes 261 private fun getCoexIconViewAsset( 262 authState: PromptAuthState, 263 isAuthenticating: Boolean, 264 isPendingConfirmation: Boolean, 265 showingError: Boolean, 266 ): Int { 267 return if (authState.isAuthenticatedAndExplicitlyConfirmed) { 268 R.raw.fingerprint_dialogue_unlocked_to_checkmark_success_lottie 269 } else if (isPendingConfirmation) { 270 if (_previousIconWasError.value) { 271 R.raw.fingerprint_dialogue_error_to_unlock_lottie 272 } else { 273 R.raw.fingerprint_dialogue_fingerprint_to_unlock_lottie 274 } 275 } else if (authState.isAuthenticated) { 276 if (_previousIconWasError.value) { 277 R.raw.fingerprint_dialogue_error_to_success_lottie 278 } else { 279 R.raw.fingerprint_dialogue_fingerprint_to_success_lottie 280 } 281 } else if (isAuthenticating) { 282 if (_previousIconWasError.value) { 283 R.raw.fingerprint_dialogue_error_to_fingerprint_lottie 284 } else { 285 R.raw.fingerprint_dialogue_fingerprint_to_error_lottie 286 } 287 } else if (showingError) { 288 R.raw.fingerprint_dialogue_fingerprint_to_error_lottie 289 } else { 290 -1 291 } 292 } 293 294 @RawRes 295 private fun getCoexSfpsIconViewAsset( 296 rotation: DisplayRotation, 297 isInRearDisplayMode: Boolean, 298 authState: PromptAuthState, 299 isAuthenticating: Boolean, 300 isPendingConfirmation: Boolean, 301 showingError: Boolean, 302 ): Int { 303 return if (authState.isAuthenticatedAndExplicitlyConfirmed) { 304 R.raw.biometricprompt_sfps_unlock_to_success 305 } else if (isPendingConfirmation) { 306 if (_previousIconWasError.value) { 307 R.raw.biometricprompt_sfps_error_to_unlock 308 } else { 309 getSfpsAsset_fingerprintToUnlock(rotation, isInRearDisplayMode) 310 } 311 } else if (authState.isAuthenticated) { 312 if (_previousIconWasError.value) { 313 R.raw.biometricprompt_sfps_error_to_success 314 } else { 315 getSfpsAsset_fingerprintToSuccess(rotation, isInRearDisplayMode) 316 } 317 } else if (isAuthenticating) { 318 if (_previousIconWasError.value) { 319 getSfpsAsset_errorToFingerprint(rotation, isInRearDisplayMode) 320 } else { 321 getSfpsAsset_fingerprintAuthenticating(isInRearDisplayMode) 322 } 323 } else if (showingError) { 324 getSfpsAsset_fingerprintToError(rotation, isInRearDisplayMode) 325 } else { 326 -1 327 } 328 } 329 330 /** Content description for iconView */ 331 val contentDescriptionId: Flow<Int> = 332 activeAuthType.flatMapLatest { activeAuthType: AuthType -> 333 when (activeAuthType) { 334 AuthType.Fingerprint, 335 AuthType.Coex -> 336 combine( 337 promptSelectorInteractor.fingerprintSensorType, 338 promptViewModel.isAuthenticated, 339 promptViewModel.isAuthenticating, 340 promptViewModel.isPendingConfirmation, 341 promptViewModel.showingError, 342 ) { 343 sensorType: FingerprintSensorType, 344 authState: PromptAuthState, 345 isAuthenticating: Boolean, 346 isPendingConfirmation: Boolean, 347 showingError: Boolean -> 348 getFingerprintIconContentDescriptionId( 349 sensorType, 350 authState.isAuthenticated, 351 isAuthenticating, 352 isPendingConfirmation, 353 showingError, 354 ) 355 } 356 AuthType.Face -> 357 combine( 358 promptViewModel.isAuthenticated, 359 promptViewModel.isAuthenticating, 360 promptViewModel.showingError, 361 ) { authState: PromptAuthState, isAuthenticating: Boolean, showingError: Boolean 362 -> 363 getFaceIconContentDescriptionId(authState, isAuthenticating, showingError) 364 } 365 } 366 } 367 368 private fun getFingerprintIconContentDescriptionId( 369 sensorType: FingerprintSensorType, 370 isAuthenticated: Boolean, 371 isAuthenticating: Boolean, 372 isPendingConfirmation: Boolean, 373 showingError: Boolean, 374 ): Int = 375 if (isPendingConfirmation) { 376 when (sensorType) { 377 FingerprintSensorType.POWER_BUTTON -> -1 378 else -> R.string.biometric_dialog_confirm 379 } 380 } else if (isAuthenticating || isAuthenticated) { 381 when (sensorType) { 382 FingerprintSensorType.POWER_BUTTON -> 383 R.string.security_settings_sfps_enroll_find_sensor_message 384 else -> R.string.accessibility_fingerprint_label 385 } 386 } else if (showingError) { 387 R.string.biometric_dialog_try_again 388 } else { 389 -1 390 } 391 392 private fun getFaceIconContentDescriptionId( 393 authState: PromptAuthState, 394 isAuthenticating: Boolean, 395 showingError: Boolean, 396 ): Int = 397 if (authState.isAuthenticatedAndExplicitlyConfirmed) { 398 R.string.biometric_dialog_face_icon_description_confirmed 399 } else if (authState.isAuthenticated) { 400 R.string.biometric_dialog_face_icon_description_authenticated 401 } else if (isAuthenticating) { 402 R.string.biometric_dialog_face_icon_description_authenticating 403 } else if (showingError) { 404 R.string.keyguard_face_failed 405 } else { 406 R.string.biometric_dialog_face_icon_description_idle 407 } 408 409 /** Whether the current BiometricPromptLayout.iconView asset animation should be playing. */ 410 val shouldAnimateIconView: Flow<Boolean> = 411 activeAuthType.flatMapLatest { activeAuthType: AuthType -> 412 when (activeAuthType) { 413 AuthType.Fingerprint -> 414 combine( 415 promptSelectorInteractor.fingerprintSensorType, 416 promptViewModel.isAuthenticated, 417 promptViewModel.isAuthenticating, 418 promptViewModel.showingError, 419 ) { 420 sensorType: FingerprintSensorType, 421 authState: PromptAuthState, 422 isAuthenticating: Boolean, 423 showingError: Boolean -> 424 when (sensorType) { 425 FingerprintSensorType.POWER_BUTTON -> true 426 else -> 427 shouldAnimateFingerprintIconView( 428 authState.isAuthenticated, 429 isAuthenticating, 430 showingError, 431 ) 432 } 433 } 434 AuthType.Face -> 435 combine( 436 promptViewModel.isAuthenticated, 437 promptViewModel.isAuthenticating, 438 promptViewModel.showingError, 439 ) { authState: PromptAuthState, isAuthenticating: Boolean, showingError: Boolean 440 -> 441 isAuthenticating || 442 authState.isAuthenticated || 443 showingError || 444 _previousIconWasError.value 445 } 446 AuthType.Coex -> 447 combine( 448 promptSelectorInteractor.fingerprintSensorType, 449 promptViewModel.isAuthenticated, 450 promptViewModel.isAuthenticating, 451 promptViewModel.isPendingConfirmation, 452 promptViewModel.showingError, 453 ) { 454 sensorType: FingerprintSensorType, 455 authState: PromptAuthState, 456 isAuthenticating: Boolean, 457 isPendingConfirmation: Boolean, 458 showingError: Boolean -> 459 when (sensorType) { 460 FingerprintSensorType.POWER_BUTTON -> true 461 else -> 462 shouldAnimateCoexIconView( 463 authState.isAuthenticated, 464 isAuthenticating, 465 isPendingConfirmation, 466 showingError, 467 ) 468 } 469 } 470 } 471 } 472 473 /** Whether the current BiometricPromptLayout.iconView asset animation should be looping. */ 474 val shouldLoopIconView: Flow<Boolean> = 475 activeAuthType.flatMapLatest { activeAuthType: AuthType -> 476 when (activeAuthType) { 477 AuthType.Fingerprint, 478 AuthType.Coex -> flowOf(false) 479 AuthType.Face -> promptViewModel.isAuthenticating 480 } 481 } 482 483 private fun shouldAnimateFingerprintIconView( 484 isAuthenticated: Boolean, 485 isAuthenticating: Boolean, 486 showingError: Boolean, 487 ) = (isAuthenticating && _previousIconWasError.value) || isAuthenticated || showingError 488 489 private fun shouldAnimateCoexIconView( 490 isAuthenticated: Boolean, 491 isAuthenticating: Boolean, 492 isPendingConfirmation: Boolean, 493 showingError: Boolean, 494 ) = 495 (isAuthenticating && _previousIconWasError.value) || 496 isPendingConfirmation || 497 isAuthenticated || 498 showingError 499 500 /* Used to rotate the iconView for assets reused across rotations. */ 501 val iconViewRotation: Flow<Float> = 502 combine(iconAsset, displayStateInteractor.currentRotation) { 503 icon: Int, 504 rotation: DisplayRotation -> 505 if (assetReusedAcrossRotations(icon)) { 506 when (rotation) { 507 DisplayRotation.ROTATION_0 -> 0f 508 DisplayRotation.ROTATION_90 -> 270f 509 DisplayRotation.ROTATION_180 -> 180f 510 DisplayRotation.ROTATION_270 -> 90f 511 } 512 } else { 513 0f 514 } 515 } 516 517 private fun assetReusedAcrossRotations(asset: Int): Boolean { 518 return asset in assetsReusedAcrossRotations 519 } 520 521 private val assetsReusedAcrossRotations: List<Int> = 522 listOf( 523 R.raw.biometricprompt_sfps_fingerprint_authenticating, 524 R.raw.biometricprompt_sfps_rear_display_fingerprint_authenticating, 525 R.raw.biometricprompt_sfps_rear_display_fingerprint_authenticating, 526 ) 527 528 /** Called on configuration changes */ 529 fun onConfigurationChanged(newConfig: Configuration) { 530 displayStateInteractor.onConfigurationChanged(newConfig) 531 } 532 533 /** Coex iconView assets for caching */ 534 fun getCoexAssetsList(hasSfps: Boolean): List<Int> = 535 if (hasSfps) { 536 listOf( 537 R.raw.biometricprompt_sfps_fingerprint_authenticating, 538 R.raw.biometricprompt_sfps_rear_display_fingerprint_authenticating, 539 R.raw.biometricprompt_sfps_error_to_unlock, 540 R.raw.biometricprompt_sfps_error_to_success, 541 R.raw.biometricprompt_sfps_fingerprint_to_error, 542 R.raw.biometricprompt_sfps_fingerprint_to_error_90, 543 R.raw.biometricprompt_sfps_fingerprint_to_error_180, 544 R.raw.biometricprompt_sfps_fingerprint_to_error_270, 545 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error, 546 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_90, 547 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_180, 548 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_270, 549 R.raw.biometricprompt_sfps_error_to_fingerprint, 550 R.raw.biometricprompt_sfps_error_to_fingerprint_90, 551 R.raw.biometricprompt_sfps_error_to_fingerprint_180, 552 R.raw.biometricprompt_sfps_error_to_fingerprint_270, 553 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint, 554 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_90, 555 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_180, 556 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_270, 557 R.raw.biometricprompt_sfps_fingerprint_to_unlock, 558 R.raw.biometricprompt_sfps_fingerprint_to_unlock_90, 559 R.raw.biometricprompt_sfps_fingerprint_to_unlock_180, 560 R.raw.biometricprompt_sfps_fingerprint_to_unlock_270, 561 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_unlock, 562 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_unlock_90, 563 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_unlock_180, 564 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_unlock_270, 565 R.raw.biometricprompt_sfps_fingerprint_to_success, 566 R.raw.biometricprompt_sfps_fingerprint_to_success_90, 567 R.raw.biometricprompt_sfps_fingerprint_to_success_180, 568 R.raw.biometricprompt_sfps_fingerprint_to_success_270, 569 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success, 570 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_90, 571 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_180, 572 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_270, 573 ) 574 } else { 575 listOf( 576 R.raw.fingerprint_dialogue_unlocked_to_checkmark_success_lottie, 577 R.raw.fingerprint_dialogue_error_to_unlock_lottie, 578 R.raw.fingerprint_dialogue_fingerprint_to_unlock_lottie, 579 R.raw.fingerprint_dialogue_error_to_success_lottie, 580 R.raw.fingerprint_dialogue_fingerprint_to_success_lottie, 581 R.raw.fingerprint_dialogue_error_to_fingerprint_lottie, 582 R.raw.fingerprint_dialogue_fingerprint_to_error_lottie, 583 ) 584 } 585 586 /** Fingerprint iconView assets for caching */ 587 fun getFingerprintAssetsList(hasSfps: Boolean): List<Int> = 588 if (hasSfps) { 589 listOf( 590 R.raw.biometricprompt_sfps_fingerprint_authenticating, 591 R.raw.biometricprompt_sfps_rear_display_fingerprint_authenticating, 592 R.raw.biometricprompt_sfps_error_to_success, 593 R.raw.biometricprompt_sfps_fingerprint_to_error, 594 R.raw.biometricprompt_sfps_fingerprint_to_error_90, 595 R.raw.biometricprompt_sfps_fingerprint_to_error_180, 596 R.raw.biometricprompt_sfps_fingerprint_to_error_270, 597 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error, 598 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_90, 599 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_180, 600 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_270, 601 R.raw.biometricprompt_sfps_error_to_fingerprint, 602 R.raw.biometricprompt_sfps_error_to_fingerprint_90, 603 R.raw.biometricprompt_sfps_error_to_fingerprint_180, 604 R.raw.biometricprompt_sfps_error_to_fingerprint_270, 605 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint, 606 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_90, 607 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_180, 608 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_270, 609 R.raw.biometricprompt_sfps_fingerprint_to_success, 610 R.raw.biometricprompt_sfps_fingerprint_to_success_90, 611 R.raw.biometricprompt_sfps_fingerprint_to_success_180, 612 R.raw.biometricprompt_sfps_fingerprint_to_success_270, 613 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success, 614 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_90, 615 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_180, 616 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_270, 617 ) 618 } else { 619 listOf( 620 R.raw.fingerprint_dialogue_error_to_fingerprint_lottie, 621 R.raw.fingerprint_dialogue_error_to_success_lottie, 622 R.raw.fingerprint_dialogue_fingerprint_to_error_lottie, 623 R.raw.fingerprint_dialogue_fingerprint_to_success_lottie, 624 ) 625 } 626 627 /** Face iconView assets for caching */ 628 fun getFaceAssetsList(): List<Int> = 629 listOf( 630 R.raw.face_dialog_wink_from_dark, 631 R.raw.face_dialog_dark_to_checkmark, 632 R.raw.face_dialog_dark_to_error, 633 R.raw.face_dialog_error_to_idle, 634 R.raw.face_dialog_idle_static, 635 R.raw.face_dialog_authenticating, 636 ) 637 638 private fun getSfpsAsset_fingerprintAuthenticating(isInRearDisplayMode: Boolean): Int = 639 if (isInRearDisplayMode) { 640 R.raw.biometricprompt_sfps_rear_display_fingerprint_authenticating 641 } else { 642 R.raw.biometricprompt_sfps_fingerprint_authenticating 643 } 644 645 private fun getSfpsAsset_fingerprintToError( 646 rotation: DisplayRotation, 647 isInRearDisplayMode: Boolean, 648 ): Int = 649 if (isInRearDisplayMode) { 650 when (rotation) { 651 DisplayRotation.ROTATION_0 -> 652 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error 653 DisplayRotation.ROTATION_90 -> 654 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_90 655 DisplayRotation.ROTATION_180 -> 656 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_180 657 DisplayRotation.ROTATION_270 -> 658 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_error_270 659 } 660 } else { 661 when (rotation) { 662 DisplayRotation.ROTATION_0 -> R.raw.biometricprompt_sfps_fingerprint_to_error 663 DisplayRotation.ROTATION_90 -> R.raw.biometricprompt_sfps_fingerprint_to_error_90 664 DisplayRotation.ROTATION_180 -> R.raw.biometricprompt_sfps_fingerprint_to_error_180 665 DisplayRotation.ROTATION_270 -> R.raw.biometricprompt_sfps_fingerprint_to_error_270 666 } 667 } 668 669 private fun getSfpsAsset_errorToFingerprint( 670 rotation: DisplayRotation, 671 isInRearDisplayMode: Boolean, 672 ): Int = 673 if (isInRearDisplayMode) { 674 when (rotation) { 675 DisplayRotation.ROTATION_0 -> 676 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint 677 DisplayRotation.ROTATION_90 -> 678 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_90 679 DisplayRotation.ROTATION_180 -> 680 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_180 681 DisplayRotation.ROTATION_270 -> 682 R.raw.biometricprompt_sfps_rear_display_error_to_fingerprint_270 683 } 684 } else { 685 when (rotation) { 686 DisplayRotation.ROTATION_0 -> R.raw.biometricprompt_sfps_error_to_fingerprint 687 DisplayRotation.ROTATION_90 -> R.raw.biometricprompt_sfps_error_to_fingerprint_90 688 DisplayRotation.ROTATION_180 -> R.raw.biometricprompt_sfps_error_to_fingerprint_180 689 DisplayRotation.ROTATION_270 -> R.raw.biometricprompt_sfps_error_to_fingerprint_270 690 } 691 } 692 693 private fun getSfpsAsset_fingerprintToUnlock( 694 rotation: DisplayRotation, 695 isInRearDisplayMode: Boolean, 696 ): Int = 697 if (isInRearDisplayMode) { 698 when (rotation) { 699 DisplayRotation.ROTATION_0 -> 700 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_unlock 701 DisplayRotation.ROTATION_90 -> 702 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_unlock_90 703 DisplayRotation.ROTATION_180 -> 704 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_unlock_180 705 DisplayRotation.ROTATION_270 -> 706 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_unlock_270 707 } 708 } else { 709 when (rotation) { 710 DisplayRotation.ROTATION_0 -> R.raw.biometricprompt_sfps_fingerprint_to_unlock 711 DisplayRotation.ROTATION_90 -> R.raw.biometricprompt_sfps_fingerprint_to_unlock_90 712 DisplayRotation.ROTATION_180 -> R.raw.biometricprompt_sfps_fingerprint_to_unlock_180 713 DisplayRotation.ROTATION_270 -> R.raw.biometricprompt_sfps_fingerprint_to_unlock_270 714 } 715 } 716 717 private fun getSfpsAsset_fingerprintToSuccess( 718 rotation: DisplayRotation, 719 isInRearDisplayMode: Boolean, 720 ): Int = 721 if (isInRearDisplayMode) { 722 when (rotation) { 723 DisplayRotation.ROTATION_0 -> 724 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success 725 DisplayRotation.ROTATION_90 -> 726 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_90 727 DisplayRotation.ROTATION_180 -> 728 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_180 729 DisplayRotation.ROTATION_270 -> 730 R.raw.biometricprompt_sfps_rear_display_fingerprint_to_success_270 731 } 732 } else { 733 when (rotation) { 734 DisplayRotation.ROTATION_0 -> R.raw.biometricprompt_sfps_fingerprint_to_success 735 DisplayRotation.ROTATION_90 -> R.raw.biometricprompt_sfps_fingerprint_to_success_90 736 DisplayRotation.ROTATION_180 -> 737 R.raw.biometricprompt_sfps_fingerprint_to_success_180 738 DisplayRotation.ROTATION_270 -> 739 R.raw.biometricprompt_sfps_fingerprint_to_success_270 740 } 741 } 742 } 743