> 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

## Descripción general

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

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

## Integración del SDK

Manejar la autenticación en `ContactlessPaymentServiceListener.onAuthenticationRequired()`. Ver [Implementar callbacks 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, use el `CHVerificationMethod` proporcionado por el SDK. Úselo para obtener un `DeviceCVMVerifier` instancia, luego inicie la autenticación y escuche el resultado usando `DeviceCVMVerifyListener`.

`cvmResetTimeout` le indica cuánto tiempo permanece válida la verificación. Úselo para guiar al usuario final para el segundo toque.

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

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

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

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

    // comprobar el tipo de CDCVM
    if(cvm == CHVerificationMethod.DEVICE_KEYGUARD) {
        // Iniciar la Activity implementada para gestionar la pantalla de autenticación del 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 su aplicación de billetera 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 bundle 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, obtener una instancia del objeto DeviceCVMVerifier correspondiente
      chDeviceCVMVerifier = (DeviceCVMVerifier) paymentService.getCHVerifier(cvm);

      // luego establecer el listener correspondiente en el objeto DeviceCVMVerifier
      chDeviceCVMVerifier.setDeviceCVMVerifyListener(new DeviceCVMVerifyListener() {

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


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

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


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

      });

      cbDeviceCVMVerifier.setKeyguardActivity(this);

      // Iniciar la autenticación cuando la pantalla esté ENCENDIDA y desbloqueada
      if (DeviceUtil.isDeviceScreenOn(getApplicationContext())) {

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

     }

}
```

{% endcode %}

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

Use este método cuando el dispositivo admita autenticación biométrica (la huella dactilar 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) {

    // comprobar el tipo de CDCVM
    if(cvm == CHVerificationMethod.FINGERPRINT) {
        // Iniciar la activity que gestiona la pantalla de autenticación por huella
        // 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);
    }
}

//...
```

Implemente una `Activity` que extienda `DeviceCVMKeyguardActivity`. Esto permite la recuperación al keyguard del dispositivo cuando la verificación biométrica falle.

{% 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 bundle
      CHVerificationMethod cvm = (CHVerificationMethod) extras.getSerializable(Tags.CVM);

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

      // gracias al objeto cvm obtener una instancia del 'DeviceCVMVerifier'
      deviceCVMVerifier = (DeviceCVMVerifier) paymentService.getCHVerifier(cvm);

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

            @Override
            public void onVerifySuccess() {
              // ¡La verificación es OK!
              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 produce el error FINGERPRINT_ERROR_CANCELED
              if (errorCode == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                  Log.d(TAG, "reiniciar Fp");
                  if (cancellationSignal != null)
                      cancellationSignal.cancel();

              isBioFPVerificationStarted=true;
              cancellationSignal = new CancellationSignal();
              DeviceCVMVerifierInput input = new DeviceCVMVerifierInput(cancellationSignal);
              deviceCVMVerifier.startAuthentication(input);
              }
              // manejo habitual del código de error
              else {
                        message.setText(charSequence + ". Por favor, inténtelo de nuevo...");
                        if(errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
                            confirmCredential("Verificar por Keyguard", "Demasiados intentos. Por favor verifique usando su PIN / Patrón / Contraseña");
                  }
              }
            }

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


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

        });

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

        // Iniciar la autenticación cuando la pantalla esté ENCENDIDA y desbloqueada
        if (DeviceUtil.isDeviceScreenOn(getApplicationContext())) {
            Log.d(TAG, "Iniciando autenticación por huella dactilar");
            DeviceCVMVerifierInput input = new DeviceCVMVerifierInput(cancellationSignal);
            deviceCVMVerifier.startAuthentication(input);
        } else {
            Log.d(TAG, "La pantalla está desactivada, omitiendo la autenticación por huella");
        }
    }

  	/* En caso de fallo en la verificación por huella, es posible implementar el siguiente callback
    para volver a la verificación por 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, el servicio de Pago debe desactivarse
    **/
  	private void cancelTransaction(String message) {
          if (cancellationSignal != null) {
              cancellationSignal.cancel();
          }
          PaymentBusinessManager.getPaymentBusinessService().deactivate();
    }

}
```

{% endcode %}

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

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();
}
```

### Soportar escenarios de pantalla de bloqueo (opcional)

Si necesita soportar solicitudes de autenticación cuando el dispositivo está bloqueado, verifique lo siguiente:

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

Configure los siguientes ajustes en el manifiesto e implemente 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 su aplicación de billetera digital solicite la autenticación al usuario final y luego informe al SDK que el pago puede continuar.

La autenticación puede usar el keyguard del dispositivo o 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. Su aplicación de billetera digital puede enten:

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

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

```java
@Override
public void onAuthenticationRequired(final PaymentService service, CHVerificationMethod cvm, long cvmResetTimeout) {
                            
  // solo aplicable para 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 temporal de la autenticación
      ...

      // la marca temporal es usada por el SDK para comparar con el tiempo actual, para asegurarse de que aún 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 biométrico
      verifier.setCVMType(CVMType.FINGERPRINT);

      // también se recomienda que MPA realice una comprobación y asegure que quede suficiente tiempo para que el usuario 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.
