Enabling Advanced Injection Attack Detection

Overview

Face Capture provides two workflow options for advanced injection attack detection:

  • LIGHT_TRACE_STRICT_MODE_OPTIMIZATIONS — Strict Mode Optimizations.

  • SPECTRAL_ANALYSIS — Spectral Analysis.

Both options add more advanced injection attack detection to your workflow. Neither is enabled by default, because both introduce additional considerations for end user applications:

  • Enabling either option requires additional time to process data after the subject’s photo is taken. To ensure a smooth end user experience, a POST_CAPTURE_PROCESSING status will be provided. While this is occurring, it is advised to update the UI display, as the SDK will no longer be displaying the camera feed.

The two options differ in which workflows they support, and in some usage advice:

  • Strict Mode Optimizations is intended for the Charlie workflow only. It is also recommended to advise users to avoid taking pictures outside in direct sunlight, as direct sunlight may increase errors for live users.

  • Spectral Analysis is supported on both the Charlie and Foxtrot workflows.

Because both options surface the same POST_CAPTURE_PROCESSING behavior, they share a single post-capture handling implementation. This guide describes how to enable each option and how to handle the extra processing time on the UI by displaying an animation during the POST_CAPTURE_PROCESSING phase.

Enabling Strict Mode Optimizations

Before starting the Face Capture process, set the LIGHT_TRACE_STRICT_MODE_OPTIMIZATIONS workflow property to true. The default value is false.

Enable Strict Mode Optimizations
   workflow?.setPropertyBool(
       WorkflowProperty.LIGHT_TRACE_STRICT_MODE_OPTIMIZATIONS,
       true
   )

Note

Strict Mode Optimizations is intended for the Charlie workflow only. When LIGHT_TRACE_STRICT_MODE_OPTIMIZATIONS is enabled, expect an additional ~1 second delay on the CaptureSessionStatus.POST_CAPTURE_PROCESSING callback before the status transitions to COMPLETED. To improve the user experience during this delay, it is recommended to display an animation (e.g. a progress indicator followed by a checkmark). See Handling Post-Capture Processing.

Enabling Spectral Analysis

Before starting the Face Capture process, set the SPECTRAL_ANALYSIS workflow property to true. The default value is false.

Enable Spectral Analysis
   workflow?.setPropertyBool(
       WorkflowProperty.SPECTRAL_ANALYSIS,
       true
   )

Note

Spectral Analysis is supported on both the Charlie and Foxtrot workflows. When SPECTRAL_ANALYSIS is enabled, expect additional processing time on the CaptureSessionStatus.POST_CAPTURE_PROCESSING callback before the status transitions to COMPLETED. To improve the user experience during this delay, it is recommended to display an animation (e.g. a progress indicator followed by a checkmark). See Handling Post-Capture Processing.

Handling Post-Capture Processing

Both options above use the same post-capture handling. Regardless of which option you enabled, the POST_CAPTURE_PROCESSING status is handled identically, so the implementation below applies to both.

The flow is:

  • While the status is POST_CAPTURE_PROCESSING — show a progress animation.

  • When the status becomes COMPLETED — hide the progress and play a checkmark animation; finalize the capture when the animation ends.

Drawable Resources

res/drawable/ic_check.xml

The static checkmark vector.

res/drawable/ic_check.xml
   <vector xmlns:android="http://schemas.android.com/apk/res/android"
       android:width="96dp"
       android:height="96dp"
       android:viewportWidth="96"
       android:viewportHeight="96">

       <path
           android:name="check"
           android:pathData="M28,50 L42,64 L70,32"
           android:fillColor="@android:color/transparent"
           android:strokeColor="@color/colorGreen"
           android:strokeWidth="6"
           android:strokeLineCap="round"
           android:strokeLineJoin="round"
           android:trimPathEnd="0" />
   </vector>

res/animator/check_animator.xml

Animates trimPathEnd so the check is drawn stroke-by-stroke.

res/animator/check_animator.xml
   <objectAnimator
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:propertyName="trimPathEnd"
       android:duration="1000"
       android:valueFrom="0"
       android:valueTo="1"
       android:valueType="floatType" />

res/drawable/animated_check.xml

Binds the animator to the check path inside the vector.

res/drawable/animated_check.xml
   <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
       android:drawable="@drawable/ic_check">

       <target
           android:name="check"
           android:animation="@animator/check_animator" />
   </animated-vector>

Layout

Place a progress indicator and an ImageView for the checkmark inside your capture layout:

Capture Layout
   <ProgressBar
       android:id="@+id/postProcessingProgress"
       android:layout_width="64dp"
       android:layout_height="64dp"
       android:visibility="gone" />

   <ImageView
       android:id="@+id/imgCheckmark"
       android:layout_width="96dp"
       android:layout_height="96dp"
       android:visibility="gone" />

Activity Logic

Inside your capture activity, react to the polling status callbacks. While in POST_CAPTURE_PROCESSING, show the progress; on COMPLETED, play the checkmark animation and only finalize when it ends.

Handle Polling Status Callbacks
   private var isPostProcessingVisible = false
   private var isCompletedHandled = false

   override fun onPollingStatusListener(
       status: CaptureSessionStatus,
       frame: ByteArray?,
       feedback: AutoCaptureFeedback?
   ) {
       when (status) {
           CaptureSessionStatus.CAPTURING -> processCurrentData(frame, feedback)
           CaptureSessionStatus.POST_CAPTURE_PROCESSING -> showPostProcessing()
           CaptureSessionStatus.COMPLETED -> playCheckmarkThenEnd()
           else -> Unit
       }
   }

   private fun showPostProcessing() {
       if (isCompletedHandled || isPostProcessingVisible) return

       isPostProcessingVisible = true
       binding.imgCheckmark.isVisible = false
       binding.postProcessingProgress.isVisible = true
   }

   private fun playCheckmarkThenEnd() {
       if (isCompletedHandled) return

       isCompletedHandled = true
       isPostProcessingVisible = false

       runOnUiThread {
           binding.postProcessingProgress.isVisible = false
           binding.imgCheckmark.isVisible = true
       }

       val checkDrawable = AnimatedVectorDrawableCompat.create(
           binding.root.context,
           R.drawable.animated_check
       )

       if (checkDrawable == null) {
           onCaptureEnd()
           return
       }

       runOnUiThread {
           binding.imgCheckmark.setImageDrawable(checkDrawable)

           checkDrawable.registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
               override fun onAnimationEnd(drawable: Drawable?) {
                   binding.imgCheckmark.post {
                       checkDrawable.clearAnimationCallbacks()
                       onCaptureEnd()
                   }
               }
           })

           checkDrawable.start()
       }
   }

Required Imports

Required Imports
   import androidx.core.view.isVisible
   import androidx.vectordrawable.graphics.drawable.Animatable2Compat
   import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat

Guard Flags

Two flags prevent double-handling of status callbacks, which can arrive multiple times:

  • isPostProcessingVisible — ensures the progress UI is only shown once per session.

  • isCompletedHandled — ensures the completion animation and onCaptureEnd() run only once, even if COMPLETED is delivered repeatedly.