> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/es/implement-nfc-wallet/make-payment/implement-contactless-payments/5.-perform-cdcvm-verification.md).

# 5. Realizar la verificación CDCVM

## Resumen

Durante una transacción sin contacto, NFC Wallet SDK puede requerir que el **usuario final** se autentique para completar la verificación de CDCVM.

Tu **aplicación de cartera digital** debe realizar esta autenticación usando el método CDCVM que configuraste anteriormente. Ver [Establecer método CDCVM](/nfc-wallet-sdk-android/es/implement-nfc-wallet/tokenize-a-card/set-cdcvm-method.md).

## Integración del SDK

Gestionar la autenticación en `ContactlessPaymentServiceListener.onAuthenticationRequired()`. Consulte [Implementar devoluciones de llamada de pago sin contacto](/nfc-wallet-sdk-android/es/implement-nfc-wallet/make-payment/implement-contactless-payments/2.-implement-contactless-payment-callbacks.md).

Para autenticar al usuario final, usa el `CHVerificationMethod` proporcionado por el SDK. Úsalo para obtener un `DeviceCVMVerifier` instancia, luego inicia la autenticación y escucha el resultado usando `DeviceCVMVerifyListener`.

`cvmResetTimeout` te indica cuánto tiempo sigue siendo válida la verificación. Úsalo para guiar al usuario final en el segundo toque.

### Verificación CDCVM con la pantalla de bloqueo del dispositivo

Cuando la pantalla de bloqueo del dispositivo se usa como método CDCVM:

```java
//Desde una implementación de ContactlessPaymentServiceListener()
//...

@Override
public void onAuthenticationRequired(
  PaymentService activatedPaymentService,
  CHVerificationMethod cvm,
  long cvmResetTimeout) {

    // comprueba el tipo de CDCVM
    if(cvm == CHVerificationMethod.DEVICE_KEYGUARD) {
        // Inicia la Activity implementada para gestionar la pantalla de autenticación de Keyguard
        // En este ejemplo la activity se llama 'KeyguardActivity'
        Intent intent = new Intent(getApplicationContext(), KeyguardActivity.class);
        intent.putExtra(Tags.CVM, cvm);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

//...
```

Implemente `KeyguardActivity` en tu aplicación de cartera digital. Debe extender `DeviceCVMKeyguardActivity`. Esto habilita la verificación CDCVM usando las credenciales del dispositivo.

El siguiente ejemplo muestra la implementación de la `KeyguardActivity` clase:

{% code expandable="true" %}

```java
public class KeyguardActivity extends DeviceCVMKeyguardActivity{

     private static String TAG = KeyguardActivity.class.getName();
     private PaymentBusinessService paymentBusinessService;
     private DeviceCVMVerifier chDeviceCVMVerifier;
     private TextView message;
     private boolean keyguardVerificationStart = false;
     private CharSequence title;
     private CharSequence message1;

     @Override
     protected void onCreate(Bundle savedInstanceState) {

      Log.d(TAG, "KeyguardActivity:onCreate");
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_device_keyguard);
      Log.d(TAG, "KeyguardActivity:unlockAndWake : start");
      unlockAndWake();
      Log.d(TAG, "KeyguardActivity:unlockAndWake : end");

      title=getString(R.string.keyguard_title);
      message1=getString(R.string.keyguard_message);

      Bundle extras = getIntent().getExtras();

      // obtener el objeto cvm del paquete pasado
      CHVerificationMethod cvm = (CHVerificationMethod) extras.getSerializable(Tags.CVM);

      message = (TextView) findViewById(R.id.message);

      paymentBusinessService = PaymentBusinessManager.getPaymentBusinessService();

      PaymentService paymentService = paymentBusinessService.getActivatedPaymentService();

      // gracias al objeto cvm, obtiene una instancia del objeto DeviceCVMVerifier correspondiente
      chDeviceCVMVerifier = (DeviceCVMVerifier) paymentService.getCHVerifier(cvm);

      // luego establece el listener correspondiente para el objeto DeviceCVMVerifier
      chDeviceCVMVerifier.setDeviceCVMVerifyListener(new DeviceCVMVerifyListener() {

      @Override
      public void onVerifySuccess() {
         // ¡La verificación fue correcta!
         message.setText("");
         KeyguardActivity.this.finish();
     }


      @Override
      public void onVerifyError(int errorCode, CharSequence charSequence) {
          // No se espera que se invoque
      }

      @Override
      public void onVerifyFailed() {
        // ¡La verificación no es correcta! Se debe pedir al usuario que lo intente de nuevo
        message.setText("No se pudo autenticar. Por favor, inténtalo de nuevo.");
      }


      @Override
      public void onVerifyHelp(int i, CharSequence charSequence) {
          // No se espera que se invoque
      }

      });

      cbDeviceCVMVerifier.setKeyguardActivity(this);

      // Inicia la autenticación cuando la pantalla está encendida y desbloqueada
      if (DeviceUtil.isDeviceScreenOn(getApplicationContext())) {

             Log.d(TAG, "Iniciando la autenticación de Keyguard del dispositivo");
             keyguardVerificationStart = true;
             DeviceCVMVerifierInput input = new  DeviceCVMVerifierInput(title,message1);
             chDeviceCVMVerifier.startAuthentication(input);
       } else {
             Log.d(TAG, "La pantalla está desactivada, se omite la autenticación de Keyguard");
       }

     }

}
```

{% endcode %}

### Verificación CDCVM con biometría (ejemplo de huella digital)

Usa este método cuando el dispositivo admita autenticación biométrica (la huella digital se muestra en el ejemplo).

El siguiente ejemplo muestra cómo se puede implementar este mecanismo:

```java
//Desde una implementación de ContactlessPaymentServiceListener()
//...

@Override
public void onAuthenticationRequired(
  PaymentService activatedPaymentService,
  CHVerificationMethod cvm,
  long cvmResetTimeout) {

    // comprueba el tipo de CDCVM
    if(cvm == CHVerificationMethod.FINGERPRINT) {
        // Inicia la activity que gestiona la pantalla de autenticación de huella digital
        // En este caso, esta activity se llama 'BioFingerprintActivity'
        Intent intent = new Intent(getApplicationContext(),
        BioFingerprintActivity.class);
        intent.putExtra(Tags.CVM, cvm);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

//...
```

Implementa una `Activity` que extienda `DeviceCVMKeyguardActivity`. Esto permite recurrir a la pantalla de bloqueo del dispositivo cuando falla la verificación biométrica.

{% code expandable="true" %}

```java
public class BioFingerprintActivity extends DeviceCVMKeyguardActivity {

    private static String TAG = BioFingerprintActivity.class.getName();
    private PaymentBusinessService paymentBusinessService;
    private DeviceCVMVerifier deviceCVMVerifier;
    private CancellationSignal cancellationSignal;
    private TextView message;
    private boolean isBioFPVerificationStarted = false;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_bio_fingerprint_2);
      unlockAndWake();
      Bundle extras = getIntent().getExtras();

      // obtener el objeto cvm pasado a través del paquete
      CHVerificationMethod cvm = (CHVerificationMethod) extras.getSerializable(Tags.CVM);

      message = (TextView) findViewById(R.id.message);
      paymentBusinessService = PaymentBusinessManager.getPaymentBusinessService();
      PaymentService paymentService = paymentBusinessService.getActivatedPaymentService();

      // gracias al objeto cvm, obtiene una instancia de 'DeviceCVMVerifier'
      deviceCVMVerifier = (DeviceCVMVerifier) paymentService.getCHVerifier(cvm);

			// establece el listener correspondiente
      deviceCVMVerifier.setDeviceCVMVerifyListener(new DeviceCVMVerifyListener() {

            @Override
            public void onVerifySuccess() {
              // ¡La verificación es correcta!
              message.setText("");
              BioFingerprintActivity.this.finish();
            }

            @Override
            public void onVerifyError(int errorCode, CharSequence charSequence) {

              Log.d(TAG, "BioFingerprintActivity:error :" + errorCode);

              // Caso especial cuando se activa en modo de pantalla de bloqueo
              // se lanza el error FINGERPRINT_ERROR_CANCELED
              if (errorCode == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                  Log.d(TAG, "reiniciar huella");
                  if (cancellationSignal != null)
                      cancellationSignal.cancel();

              isBioFPVerificationStarted=true;
              cancellationSignal = new CancellationSignal();
              DeviceCVMVerifierInput input = new DeviceCVMVerifierInput(cancellationSignal);
              deviceCVMVerifier.startAuthentication(input);
              }
              // tratamiento habitual del código de error
              else {
                        message.setText(charSequence + ". Por favor, inténtalo de nuevo...");
                        if(errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
                            confirmCredential("Verificar mediante Keyguard", "Demasiados intentos. Verifica usando tu PIN / patrón / contraseña");
                  }
              }
            }

            @Override
            public void onVerifyFailed() {
                message.setText("No se pudo reconocer la huella digital. Por favor, inténtalo de nuevo.");
            }


            @Override
            public void onVerifyHelp(int i, CharSequence charSequence) {
                message.setText(charSequence + ". Por favor, inténtalo de nuevo.");
            }

        });

        deviceCVMVerifier.setKeyguardActivity(this);
        cancellationSignal = new CancellationSignal();

        // Inicia la autenticación cuando la pantalla está encendida y desbloqueada
        if (DeviceUtil.isDeviceScreenOn(getApplicationContext())) {
            Log.d(TAG, "Iniciando la autenticación por huella digital");
            DeviceCVMVerifierInput input = new DeviceCVMVerifierInput(cancellationSignal);
            deviceCVMVerifier.startAuthentication(input);
        } else {
            Log.d(TAG, "La pantalla está desactivada, se omite la autenticación por huella digital");
        }
    }

  	/* En caso de fallo de la verificación por huella digital, es posible implementar el siguiente callback
    para recurrir a la verificación de Keyguard.
    **/
    public void onKeyguardFallback(View v) {

      Log.d(TAG, "onKeyguardFallback");
      // llamar a deviceCVMVerifier.startAuthentication(input)


    }

  	@Override
  	public void onCancel(View v) {
      Log.d(TAG, "Cancelar autenticación");
      cancelTransaction("La transacción ha sido cancelada.");
    }

    @Override
    public void onBackPressed() {
        Log.d(TAG, "onBackPressed()");
        cancelTransaction("La transacción ha sido cancelada.");
    }


    /*
    Después de cancelar la autenticación biométrica por huella digital, el servicio de pago deberá desactivarse
    **/
  	private void cancelTransaction(String message) {
          if (cancellationSignal != null) {
              cancellationSignal.cancel();
          }
          PaymentBusinessManager.getPaymentBusinessService().deactivate();
    }

}
```

{% endcode %}

Si la aplicación de cartera digital pasa a segundo plano, deja de escuchar la autenticación por huella digital.

Esto se puede lograr usando el siguiente fragmento de código:

```java
@Override
public void onResume() {
       super.onResume();
       cancellationSignal=new CancellationSignal();
       deviceCVMVerifier.startAuthentication(cancellationSignal);
   }

@Override
public void onPause() {
     if(cancellationSignal != null)
             cancellationSignal.cancel();
}
```

### Compatibilidad con escenarios de pantalla de bloqueo (opcional)

Si necesitas admitir solicitudes de autenticación cuando el dispositivo está bloqueado, verifica lo siguiente:

* Las actividades mostradas durante el pago se declaran con `showOnLockScreen=true`.
* Se adquiere un wake lock y se establecen banderas de ventana para mostrar la interfaz en la pantalla de bloqueo.
* Libera el `wakeLock` cuando finalice el pago para reducir el uso de la batería.

Configura los siguientes ajustes en el manifiesto e implementa el código de ejemplo según sea necesario:

```xml
<activity
        android:name=".BioFingerprintActivity"
        android:showOnLockScreen="true"
        android:screenOrientation="portrait" />
```

```java
@Override
public void onCreate() {
        //…
        unlockAndWake();
        //…
}

private void unlockAndWake() {

    PowerManager.WakeLock mWl;
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    if (!pm.isScreenOn()) {
        mWl = pm.newWakeLock(
                PowerManager.SCREEN_BRIGHT_WAKE_LOCK | 
                PowerManager.FULL_WAKE_LOCK | 
                PowerManager.ACQUIRE_CAUSES_WAKEUP, "");
        mWl.acquire();
    }

    getWindow().addFlags(
            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | 
            WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON   | 
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON   | 
            WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}

@Override
public void onDestroy() {

  try{
      if(null!=mW1){
          mWl.release();
      }
  }
 	catch(Exception e){ }
}
```

### Autenticación delegada

La autenticación delegada permite que tu aplicación de cartera digital solicite autenticación al usuario final y luego informe al SDK de que el pago puede continuar.

La autenticación puede usar la pantalla de bloqueo del dispositivo o la biometría para desbloquear el almacén de claves subyacente protegido por la autenticación del usuario.

Este flujo se aplica cuando el SDK solicita autenticación durante el pago. Tu aplicación de cartera digital puede:

* Solicitar autenticación al usuario final y luego llamar a `DeviceCVMVerifier.onDelegatedAuthPerformed(timeOfAuth)`.
* Reutilizar una autenticación reciente y exitosa (dentro del período de validez de la clave configurado) y llamar a `DeviceCVMVerifier.onDelegatedAuthPerformed(timeOfAuth)` de inmediato.

Si el usuario final aborta la transacción, llama a `DeviceCVMVerifier.onDelegatedAuthCancelled()`.

```java
@Override
public void onAuthenticationRequired(final PaymentService service, CHVerificationMethod cvm, long cvmResetTimeout) {
                            
  // solo aplicable para el método biométrico o KeyGuard
   if(cvm == CHVerificationMethod.BIOMETRICS || cvm == CHVerificationMethod.DEVICE_KEYGUARD){
      // obtener el verificador
      final DeviceCVMVerifier verifier = (DeviceCVMVerifier)service.getCHVerifier(cvm);
                                
      // MPA realiza la autenticación, proporcionando la marca de tiempo de la autenticación
      ...

      // la marca de tiempo la usa el SDK para compararla con la hora actual y asegurarse de que todavía está dentro de la duración de validez de la clave

      // MPA podría configurar el tipo de CVM como FINGERPRINT si el método de verificación es biometría
      verifier.setCVMType(CVMType.FINGERPRINT);

      // también se recomienda que MPA realice una comprobación y se asegure de que queda suficiente tiempo para que el usuario final realice el segundo toque de una transacción.
      verifier.onDelegatedAuthPerformed(timeOfAuth);
                                
      // si el usuario no desea realizar la autenticación, MPA deberá cancelar la transacción
      verifier.onDelegatedAuthCancelled();
  }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/es/implement-nfc-wallet/make-payment/implement-contactless-payments/5.-perform-cdcvm-verification.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
