Add failure listener logging to BP icons

Adding failure listener logging on lotties for BiometricPrompt

Flag: NONE adding logs
Bug: 331920634
Test: N/A
Change-Id: I5ad7dd33b46085f83f3a746b0ab2824eecae563e
Merged-In: I5ad7dd33b46085f83f3a746b0ab2824eecae563e
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
index e457601..f5d09ad 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
@@ -21,17 +21,20 @@
 import android.graphics.drawable.Animatable2
 import android.graphics.drawable.AnimatedVectorDrawable
 import android.graphics.drawable.Drawable
+import android.util.Log
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.airbnb.lottie.LottieAnimationView
+import com.airbnb.lottie.LottieListener
 import com.android.settingslib.widget.LottieColorUtils
 import com.android.systemui.Flags.constraintBp
 import com.android.systemui.biometrics.ui.viewmodel.PromptIconViewModel
 import com.android.systemui.biometrics.ui.viewmodel.PromptIconViewModel.AuthType
 import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
 import com.android.systemui.util.kotlin.Utils.Companion.toQuad
 import com.android.systemui.util.kotlin.Utils.Companion.toQuint
 import com.android.systemui.util.kotlin.Utils.Companion.toTriple
@@ -40,6 +43,8 @@
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
 
+private const val TAG = "PromptIconViewBinder"
+
 /** Sub-binder for [BiometricPromptLayout.iconView]. */
 object PromptIconViewBinder {
     /**
@@ -172,6 +177,7 @@
                                 when (activeAuthType) {
                                     AuthType.Fingerprint,
                                     AuthType.Coex -> {
+                                        iconView.setIconFailureListener(iconAsset, activeAuthType)
                                         iconView.setAnimation(iconAsset)
                                         iconView.frame = 0
 
@@ -188,6 +194,10 @@
                                             iconView.context.getDrawable(iconAsset)
                                                 as AnimatedVectorDrawable
                                         faceIcon?.apply {
+                                            iconView.setIconFailureListener(
+                                                iconAsset,
+                                                activeAuthType
+                                            )
                                             iconView.setImageDrawable(this)
                                             if (shouldAnimateIconView) {
                                                 forceAnimationOnUI()
@@ -217,6 +227,7 @@
                         )
                         .collect { (iconOverlayAsset, shouldAnimateIconOverlay, showingError) ->
                             if (iconOverlayAsset != -1) {
+                                iconOverlayView.setIconOverlayFailureListener(iconOverlayAsset)
                                 iconOverlayView.setAnimation(iconOverlayAsset)
                                 iconOverlayView.frame = 0
                                 LottieColorUtils.applyDynamicColors(
@@ -251,3 +262,96 @@
         }
     }
 }
+
+private val assetIdToString: Map<Int, String> =
+    mapOf(
+        // UDFPS assets
+        R.raw.fingerprint_dialogue_error_to_fingerprint_lottie to
+            "fingerprint_dialogue_error_to_fingerprint_lottie",
+        R.raw.fingerprint_dialogue_error_to_success_lottie to
+            "fingerprint_dialogue_error_to_success_lottie",
+        R.raw.fingerprint_dialogue_fingerprint_to_error_lottie to
+            "fingerprint_dialogue_fingerprint_to_error_lottie",
+        R.raw.fingerprint_dialogue_fingerprint_to_success_lottie to
+            "fingerprint_dialogue_fingerprint_to_success_lottie",
+        // SFPS assets
+        R.raw.biometricprompt_fingerprint_to_error_landscape to
+            "biometricprompt_fingerprint_to_error_landscape",
+        R.raw.biometricprompt_folded_base_bottomright to "biometricprompt_folded_base_bottomright",
+        R.raw.biometricprompt_folded_base_default to "biometricprompt_folded_base_default",
+        R.raw.biometricprompt_folded_base_topleft to "biometricprompt_folded_base_topleft",
+        R.raw.biometricprompt_landscape_base to "biometricprompt_landscape_base",
+        R.raw.biometricprompt_portrait_base_bottomright to
+            "biometricprompt_portrait_base_bottomright",
+        R.raw.biometricprompt_portrait_base_topleft to "biometricprompt_portrait_base_topleft",
+        R.raw.biometricprompt_symbol_error_to_fingerprint_landscape to
+            "biometricprompt_symbol_error_to_fingerprint_landscape",
+        R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_bottomright to
+            "biometricprompt_symbol_error_to_fingerprint_portrait_bottomright",
+        R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_topleft to
+            "biometricprompt_symbol_error_to_fingerprint_portrait_topleft",
+        R.raw.biometricprompt_symbol_error_to_success_landscape to
+            "biometricprompt_symbol_error_to_success_landscape",
+        R.raw.biometricprompt_symbol_error_to_success_portrait_bottomright to
+            "biometricprompt_symbol_error_to_success_portrait_bottomright",
+        R.raw.biometricprompt_symbol_error_to_success_portrait_topleft to
+            "biometricprompt_symbol_error_to_success_portrait_topleft",
+        R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright to
+            "biometricprompt_symbol_fingerprint_to_error_portrait_bottomright",
+        R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_topleft to
+            "biometricprompt_symbol_fingerprint_to_error_portrait_topleft",
+        R.raw.biometricprompt_symbol_fingerprint_to_success_landscape to
+            "biometricprompt_symbol_fingerprint_to_success_landscape",
+        R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_bottomright to
+            "biometricprompt_symbol_fingerprint_to_success_portrait_bottomright",
+        R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_topleft to
+            "biometricprompt_symbol_fingerprint_to_success_portrait_topleft",
+        // Face assets
+        R.drawable.face_dialog_wink_from_dark to "face_dialog_wink_from_dark",
+        R.drawable.face_dialog_dark_to_checkmark to "face_dialog_dark_to_checkmark",
+        R.drawable.face_dialog_pulse_light_to_dark to "face_dialog_pulse_light_to_dark",
+        R.drawable.face_dialog_pulse_dark_to_light to "face_dialog_pulse_dark_to_light",
+        R.drawable.face_dialog_dark_to_error to "face_dialog_dark_to_error",
+        R.drawable.face_dialog_error_to_idle to "face_dialog_error_to_idle",
+        R.drawable.face_dialog_idle_static to "face_dialog_idle_static",
+        // Co-ex assets
+        R.raw.fingerprint_dialogue_unlocked_to_checkmark_success_lottie to
+            "fingerprint_dialogue_unlocked_to_checkmark_success_lottie",
+        R.raw.fingerprint_dialogue_error_to_unlock_lottie to
+            "fingerprint_dialogue_error_to_unlock_lottie",
+        R.raw.fingerprint_dialogue_fingerprint_to_unlock_lottie to
+            "fingerprint_dialogue_fingerprint_to_unlock_lottie",
+    )
+
+private fun getAssetNameFromId(id: Int): String {
+    return assetIdToString.getOrDefault(id, "Asset $id not found")
+}
+
+private fun LottieAnimationView.setIconFailureListener(iconAsset: Int, activeAuthType: AuthType) {
+    setFailureListener(
+        LottieListener<Throwable> { result: Throwable? ->
+            Log.d(
+                TAG,
+                "Collecting iconAsset | " +
+                    "activeAuthType = $activeAuthType | " +
+                    "Invalid resource id: $iconAsset, " +
+                    "name ${getAssetNameFromId(iconAsset)}",
+                result
+            )
+        }
+    )
+}
+
+private fun LottieAnimationView.setIconOverlayFailureListener(iconOverlayAsset: Int) {
+    setFailureListener(
+        LottieListener<Throwable> { result: Throwable? ->
+            Log.d(
+                TAG,
+                "Collecting iconOverlayAsset | " +
+                    "Invalid resource id: $iconOverlayAsset, " +
+                    "name ${getAssetNameFromId(iconOverlayAsset)}",
+                result
+            )
+        }
+    )
+}