Launching on Android

Overview

The Capture Flow includes capturing receipt images, uploading the resulting images, and notifying a provided listener of flow progress.

To launch the capture flow, use the CaptureFlowCoordinator class. The CaptureFlowCoordinator can be used from any AppCompatActivity.

Info

Before launching the Capture Flow, please follow the Installation and Authentication steps, as well as Initialize and Start SDK.

Basic Steps

  1. Create a CaptureFlowListener (or, alternatively you can have your host Activity implement CaptureFlowCoordinator.CaptureFlowListener). Please note: the Transacting state only applies if you are configured to use the v1 (receipts) endpoints, and DocumentUploading only applies if you are configured to use the v2 (documents) endpoints. Please only include one of these options.

  2. Create a CaptureFlowCoordinator in the Activity from which you wish to launch the Capture Flow.

  3. Launch the Capture Flow when desired by calling CaptureFlowCoordinator.launchCaptureFlow . Please note: that the DocumentType configuration is only valid if configured to use the v2 (documents) endpoints. If this configuration is provided when NOT configured to use v2 endpoints, an exception will be thrown.

    This operation will launch the capture UI, as well as trigger the upload any resulting images. CaptureFlowListener will continue receiving progress updates. You can handle the updates according to the needs of your app.

Additional References:

Example

// Step 1
private val captureFlowListener: CaptureFlowCoordinator.CaptureFlowListener = object : CaptureFlowCoordinator.CaptureFlowListener {
    override fun onCaptureFlowUpdate(newState: CaptureFlowState, externalAccountTransactionId: String?) {
        when (newState) {
            is CaptureFlowState.ImagesCaptured -> {
                // Handle the state that images have just been captured
                val imagesPendingUpload: List<PendingUploadItemData> = newState.imagesPendingUpload
            }
            is CaptureFlowState.FLOW_CANCELLED -> { /* Handle the user cancelling the flow */ }
            is CaptureFlowState.Error -> {
                // Handle an error occurring during the flow
                val error = newState.exception
            }
            // **ONLY APPLICABLE IF CONFIGURED USING API V1 (RECEIPTS) ENDPOINTS**
            is CaptureFlowState.Transacting -> {
                // Handle receipt upload transaction updates that will occur after the image has been captured
                // and the receipt is uploading
                val transaction = newState.transaction
                val currentTransactionStatus = transaction.status
            }
            // **ONLY APPLICABLE IF CONFIGURED USING API V2 (DOCUMENTS) ENDPOINTS**
            is CaptureFlowState.DocumentUploading -> {
                // Handle document upload progress updates that will occur after the image has been captured and the
                // Document is uploading
                val update = newState.update
                val status = update.status
            }
        }
    }
}

// ...

// Step 2
private val captureFlow = CaptureFlowCoordinator(this)

// Step 3
captureFlow.launchCaptureFlow(
    // (Required) Your capture flow listener
    listener = captureFlowListener,
    // (Optional, default null) captureConfig.  If none provided, will default to the default config for the
    // provided document type
    config = null,
    // (Optional, default null) external account transaction id to add an external account
    // transaction id to a captured document
    externalAccountTransactionId = "myExtTxnId",
    // (Optional, default RECEIPT) ONLY APPLICABLE IF USING V2 (DOCUMENTS) API ENDPOINTS
    // The type of document to capture, receipt or invoice
    documentType = DocumentType.RECEIPT
)
// Step 1
private CaptureFlowCoordinator.CaptureFlowListener captureFlowListener = new CaptureFlowCoordinator.CaptureFlowListener() {
    @Override
    public void onCaptureFlowUpdate(@NotNull CaptureFlowState newState, @Nullable String externalAccountTransactionId) {
        if (newState instanceof CaptureFlowState.ImagesCaptured) {
            // Handle the state that images have just been captured
            final CaptureFlowState.ImagesCaptured imagesCapturedState = (CaptureFlowState.ImagesCaptured) newState;
            final List<PendingUploadItemData> imagesPendingUpload = imagesCapturedState.imagesPendingUpload;
        } else if (newState instanceof CaptureFlowState.FLOW_CANCELLED) {
            // Handle the user cancelling the flow
        } else if (newState instanceof CaptureFlowState.Error) {
            // Handle an error occurring during the flow
            final CaptureFlowState.Error errorState = (CaptureFlowState.Error) newState;
            final Exception error = errorState.getException();


        // **ONLY APPLICABLE IF CONFIGURED USING API V1 (RECEIPTS) ENDPOINTS**
        } else if (newState instanceof CaptureFlowState.Transacting) {
            // Handle receipt upload transaction updates that will occur after the image has been captured
            // and the receipt is uploading
            final CaptureFlowState.Transacting transactingState = ((CaptureFlowState.Transacting) newState);
            final Transaction transaction = transactingState.getTransaction();
            final Transaction.Status currentTransactionStatus = transaction.getStatus();


        // **ONLY APPLICABLE IF CONFIGURED USING API V2 (DOCUMENTS) ENDPOINTS**
        } else if (newState instanceof CaptureFlowState.DocumentUploading) {
            // Handle document upload progress updates that will occur after the image has been captured and the
            // Document is uploading
            final DocumentUploadUpdateData update = ((CaptureFlowState.DocumentUploading) newState).getUpdate();
            final DocumentStatus status = update.getStatus();
        }
    }
};

// ...

// Step 2
private CaptureFlowCoordinator captureFlow = new CaptureFlowCoordinator(this);

// Step 3
captureFlow.launchCaptureFlow(
        // (Required) Your capture flow listener
        captureFlowListener,
        // (Optional, default null) captureConfig.  If none provided, will default to the default config for the
        // provided document type
        null,
        // (Optional, default null) external account transaction id to add an external account
        // transaction id to a captured document
        "myExtTxnId",
        // (Optional, default RECEIPT) ONLY APPLICABLE IF USING V2 (DOCUMENTS) API ENDPOINTS
        // The type of document to capture, receipt or invoice
        DocumentType.RECEIPT
);

Capture Flow Customization

Additional Arguments

Additional arguments can be provided to the CaptureFlowCoordinator.launchCaptureFlow() call to customize the behaviour of the Capture Flow.

  • config: CaptureConfig: A CaptureConfig object can be provided to customize the behaviour of capture itself. Please see the Reference Documentation for details on the configurable properties of CaptureConfig.

    If your project is in Kotlin it is recommended to create a custom CaptureConfig using CaptureConfig.defaultConfig.copy() and providing the customizations required to the copy method.

  • externalAccountTransactionId: String?: If the receipt that is about to be captured should be linked with an external transaction (eg. banking transaction), that transaction’s ID can be provided here. When providing an externalAccountTransactionId, CaptureConfig.maxImages must be set to 1. If this rule is ignored, the capture flow will throw an exception. See Bank Transaction Linking page for more details.

Customizing the Default CaptureConfig

By default, every created instance of the capture flow will use the default CaptureConfig object: CaptureConfig.defaultConfig.

This default CaptureConfig can be modified to globally change the default capture configuration. Once a new default config has been set, every subsequent instance of any capture use case will use that default, unless otherwise directly overridden.

This property lives in a Kotlin object (singleton), so it should be customized either in your Application.onCreate, or when you set up the SensibillSDK. The customized values will then be used from that point onward.

// Use default settings, overriding the maximum captured image limit to be 5
CaptureConfig.defaultConfig = CaptureConfig.defaultConfig.copy(
    maxImages = 5
)
// Use default settings, overriding the maximum captured image limit to be 5
final CaptureConfig intendedDefaultConfig = new CaptureConfig(
        true,
        true,
        FlashMode.FLASH_MODE_AUTO,
        true,
        true,
        true,
        true,
        5,
        true,
        true,
        false,
        false,
        true,
        true
);
CaptureConfig.Companion.setDefaultConfig(intendedDefaultConfig);

Branding

You can also customize Capture appearance (colors, fonts), and Tips. See Branding for more information.

Tips Customization

To override any string resources mentioned below, add the exact string key to your own strings.xml file.
For example, for the string key sb__tips_description_flattenreceipt, add the following to override it:

<string name="sb__tips_description_flattenreceipt">My tip description</string>

To override and drawable resources mentioned below, create a new drawable with the exact name as the one that you wish to override.

The list of overridable keys is listed on Customizing Tips page.