Skip to content

Using TransferManager

Overview

TransferManager provides the functionality to automatically enable device engagement and then select the appropriate transfer method. The transfer method is selected according the configuration passed during initialization, the features supported by your license and the received device engagement.

It also instantiates a SessionManager each time a device engagement is received, ready to use for during current session for encrypting and decrypting data.

Permissions

For android SDK version 31 and later the following permissions required to be granted in order to use QR Scan for device engagement and BLETransfer for transfering data.

  • Manifest.permission.CAMERA
  • Manifest.permission.BLUETOOTH_ADVERTISE
  • Manifest.permission.BLUETOOTH_SCAN
  • Manifest.permission.BLUETOOTH_CONNECT

For android SDK prior to version 31 the required permissions are:

  • Manifest.permission.CAMERA
  • Manifest.permission.ACCESS_FINE_LOCATION
  • Manifest.permission.ACCESS_COARSE_LOCATION

Creating the configuration

The following example demonstrates a configuration when device engagement received via QR scanning. First TransferManager will try to use BLETransfer for sending and if not possible then it will try the WebAPITransfer.

Example

java
TransferManager.Config config = new TransferManager.Config()
        .setTransferPriority(TransferManager.Config.HANDOVER_QR,
                TransferManager.Config.TRANSFER_BLE,
                TransferManager.Config.TRANSFER_WEB_API);

The following example demonstrates how to use only the WebAPITransfer when device engagement received via QR scanning. WebAPITransfer.

Example

java
TransferManager.Config config = new TransferManager.Config()
        .setTransferPriority(TransferManager.Config.HANDOVER_QR,
                TransferManager.Config.TRANSFER_WEB_API);

Initializing TransferManager

Example

MainActivity.java
package com.example.app;

import android.os.Bundle;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

import com.scytales.mvalid.sdk.engagement.DeviceEngagementCallback;
import com.scytales.mvalid.sdk.retrieval.TransferManager;
import com.scytales.mvalid.sdk.retrieval.TransferReceiveCallback;

public class MainActivity extends AppCompatActivity 
    implements DeviceEngagementCallback, TransferReceiveCallback {


    private TransferManager transferManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // check permissions are granted and other activity initializations

        TransferManager.Config config = new TransferManager.Config()
                .setTransferPriority(TransferManager.Config.HANDOVER_QR,
                        TransferManager.Config.TRANSFER_BLE,
                        TransferManager.Config.TRANSFER_WEB_API);

        try {
            transferManager = new TransferManager(getApplicationContext(), config)
                    .enableDeviceEngagement(this, this)
                    .setTransferReceiveCallback(this);

            ((Button) findViewById(R.id.scan_qr_btn))
                    .setOnClickListener(v -> transferManager.scanQR());
        } catch (Exception e) {
            // handle initialization exception
        }

    }

    // rest of class implementation
}

Send request

Example

MainActivity.java
package com.example.app;

import ...

public class MainActivity extends AppCompatActivity
        implements DeviceEngagementCallback, TransferProgressListener, TransferReceiveCallback {

    ...   

    @Override
    public void onEngage(@NonNull Received<EngagementReceived> received) {
        try {
            received.runCatching(
                    failure -> {
                        Log.e(TAG, failure.toString());
                        // handle failure
                    },
                    success -> {
                        Request request = new RequestBuilder()
                                .setSessionManager(transferManager.getSessionManager())
                                .forIsoDocTypeAgeOver(21, true)
                                .build();
                        transferManager.send(request);
                    }
            );
        } catch (Exception e) {
            Log.e(TAG, "onEngage", e);
            // handle exception
        }
    }

    ...
}

Receiving response

Example

MainActivity.java
package com.example.app;

import ...

public class MainActivity extends AppCompatActivity
        implements DeviceEngagementCallback, TransferProgressListener, TransferReceiveCallback {

    ...   


    @Override
    public void onReceive(@NonNull Received<TransferReceived> received) {
        try {
            received.runCatching(
                    failure -> {
                        Log.e(TAG, failure.toString());
                        // handle failure
                    },
                    success -> {
                        Collection<X509Certificate> rootCertificates =
                                Verifier.getRootCertificates(getApplicationContext());
                        success.runCatchingForServer(receivedBytes -> {
                            ServerResponse response = ServerResponse.fromBytes(receivedBytes);
                            Log.i(TAG, response.toString());
                            List<ServerVerifierResult> verifierResults =
                                    new ServerResponseVerifier(rootCertificates)
                                            .verify(receivedBytes);
                            Log.i(TAG, verifierResults.toString());
                        });
                        success.runCatchingForDevice(receivedBytes -> {
                            transferManager.getSessionManager()
                                    .decryptResponse(receivedBytes)
                                    .runOnDataCatching(data -> {
                                        DeviceResponse response = 
                                                DeviceResponse.fromBytes(data);
                                        Log.i(TAG, response.toString());
                                        List<DeviceVerifierResult> verifierResults = 
                                                transferManager.getSessionManager()
                                                    .getVerifier(rootCertificates)
                                                    .verify(data);
                                        Log.i(TAG, verifierResults.toString());
                                    })
                                    .runOnErrorCatching(status -> {
                                        Log.e(TAG, status.toString());
                                    })
                                    .runOnTerminationCatching(() -> {
                                        transferManager.sendTermination();
                                    });
                        });
                    }
            );
        } catch (Exception e) {
            Log.e(TAG, "onReceive", e);
            // handle exception
        }
    }
    ...
}

Sample code

The following example demonstrates a typical implementation for retrieving data using TransferManager.

Example

MainActivity.java
package com.example.app;

import android.os.Bundle;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.scytales.mvalid.sdk.Functions;
import com.scytales.mvalid.sdk.Received;
import com.scytales.mvalid.sdk.SDKException;
import com.scytales.mvalid.sdk.data.DeviceResponse;
import com.scytales.mvalid.sdk.data.Request;
import com.scytales.mvalid.sdk.data.RequestBuilder;
import com.scytales.mvalid.sdk.data.ServerResponse;
import com.scytales.mvalid.sdk.engagement.DeviceEngagementCallback;
import com.scytales.mvalid.sdk.engagement.EngagementReceived;
import com.scytales.mvalid.sdk.retrieval.TransferManager;
import com.scytales.mvalid.sdk.retrieval.TransferProgressEvent;
import com.scytales.mvalid.sdk.retrieval.TransferProgressListener;
import com.scytales.mvalid.sdk.retrieval.TransferReceiveCallback;
import com.scytales.mvalid.sdk.retrieval.TransferReceived;
import com.scytales.mvalid.sdk.verify.DeviceVerifierResult;
import com.scytales.mvalid.sdk.verify.ServerResponseVerifier;
import com.scytales.mvalid.sdk.verify.ServerVerifierResult;
import com.scytales.mvalid.sdk.verify.Verifier;

import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.List;

public class MainActivity extends AppCompatActivity
        implements DeviceEngagementCallback, TransferProgressListener, TransferReceiveCallback {

    private static final String TAG = "TransferManagerActivity";
    private TransferManager transferManager;
    private Collection<X509Certificate> rootCertificates;

    // Consumes received bytes from server
    private final Functions.FailableConsumer<byte[], Exception> serverResponseConsumer =
            receivedBytes -> {
                // create a ServerResponse to manipulate received data
                ServerResponse response = ServerResponse.fromBytes(receivedBytes);

                // verify received data; a ServerVerifierResult for each
                // requested document
                List<ServerVerifierResult> verifierResults =
                        new ServerResponseVerifier(rootCertificates)
                                .verify(receivedBytes);

                // check verification for all verified documents
                boolean isVerified = verifierResults.stream()
                        .allMatch(VerifierResult::isValid);
            };

    // Consumes received bytes from device
    private final Functions.FailableConsumer<byte[], Exception> deviceResponseConsumer =
            receivedBytes -> transferManager.getSessionManager()
                    .decryptResponse(receivedBytes)
                    .runOnDataCatching(data -> {
                         // create a DeviceResponse to manipulate received data
                        DeviceResponse response = DeviceResponse.fromBytes(data);

                        // verify received data; a DeviceVerifierResult for each
                        // requested document
                        List<DeviceVerifierResult> verifierResults = transferManager
                                .getSessionManager()
                                .getVerifier(rootCertificates)
                                .verify(data);

                        // check verification for all verified documents
                        boolean isVerified = verifierResults.stream()
                                .allMatch(VerifierResult::isValid);   
                    })
                    .runOnErrorCatching(status -> {
                        Log.e(TAG, status.toString());
                    })
                    .runOnTerminationCatching(() -> {
                        transferManager.sendTermination();
                    });

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rootCertificates = Verifier.getRootCertificates(this);

        TransferManager.Config config = new TransferManager.Config()
                .setTransferPriority(TransferManager.Config.HANDOVER_QR,
                        TransferManager.Config.TRANSFER_BLE,
                        TransferManager.Config.TRANSFER_WEB_API);

        try {
            transferManager = new TransferManager(getApplicationContext(), config)
                    .enableDeviceEngagement(this, this)
                    .setTransferProgressListener(this)
                    .setTransferReceiveCallback(this);

            findViewById(R.id.scan_qr_btn)
                    .setOnClickListener(v -> transferManager.scanQR());
        } catch (SDKException e) {
            Log.e(TAG, "onCreate", e);
            // handle exception
        }
    }

    @Override
    public void onEngage(@NonNull Received<EngagementReceived> received) {
        try {
            received.runCatching(
                    failure -> {
                        Log.e(TAG, failure.toString());
                        // handle failure
                    },
                    success -> {
                        Request request = new RequestBuilder()
                                .setSessionManager(transferManager.getSessionManager())
                                .forIsoDocTypeAgeOver(21, true)
                                .build();
                        transferManager.send(request);
                    }
            );
        } catch (Exception e) {
            Log.e(TAG, "onEngage", e);
            // handle exception
        }
    }

    @Override
    public void onProgressEvent(@NonNull TransferProgressEvent transferProgressEvent) {
        Log.i(TAG, transferProgressEvent.toString());
        // update UI with event
    }

    @Override
    public void onReceive(@NonNull Received<TransferReceived> received) {
        try {
            received.runCatching(
                    failure -> {
                        Log.e(TAG, failure.toString());
                        // handle failure
                    },
                    success -> {
                        success.runCatchingForServer(serverResponseConsumer);
                        success.runCatchingForDevice(deviceResponseConsumer);
                    }
            );
        } catch (Exception e) {
            Log.e(TAG, "onReceive", e);
            // handle exception
        }
    }
}