# QR Scan

The QR Scan module captures the QR code on the back of an ID, decodes its identity data, and sends it to the server. Your Incode Flow or Workflow configuration determines whether the module runs and what the decoded payload is used for.

There is no Dashboard equivalent for this module, so you cannot use [integration Pattern 3](https://developer.incode.com/docs/android-common-implementation-patterns#pattern-3-run-flows-configured-in-dashboard) to add it. You must use [Pattern 1](https://developer.incode.com/docs/android-common-implementation-patterns#pattern-1-configure-flows-locally-and-run-end-to-end) or [2](https://developer.incode.com/docs/android-common-implementation-patterns#pattern-2-configure-flows-locally-and-run-step-by-step), adding the module to a `FlowConfig` in code as shown on this page.

QR Scan requires camera access. The SDK requests the camera permission during the flow.

## Add QR Scan

1. Add the module with the no-argument `addQRScan()` overload for default behavior, or `addQRScan(showTutorials)` to control whether the tutorial screens appear:

   ```kotlin
   flowConfigBuilder.addQRScan()
   // or with the tutorial option:
   flowConfigBuilder.addQRScan(showTutorials = true)
   ```
   ```java
   flowConfigBuilder.addQRScan();
   // or with the tutorial option:
   flowConfigBuilder.addQRScan(true);
   ```

2) If your flow also uses [Conference](https://developer.incode.com/docs/android-conference-assisted-video), [Approval](https://developer.incode.com/docs/android-approval), or an INE validation step, add them after QR Scan. `FlowConfig.Builder.build()` throws `ModuleConfigurationException` if QR Scan follows any of these steps.

### Example

The example below adds QR Scan with tutorials shown and reads the decoded value from the result.

```kotlin
val flowConfig: FlowConfig = FlowConfig.Builder()
    .addQRScan(showTutorials = true)
    .build()

val onboardingListener: OnboardingListener = object : OnboardingListener() {
    override fun onQRScanCompleted(qrScanResult: QRScanResult) {
        // Read the decoded QR value
        val decoded = qrScanResult.value
    }

    override fun onError(error: Throwable) {}

    override fun onUserCancelled() {}
}

IncodeWelcome.getInstance()
    .startOnboarding(activityContext, sessionConfig, flowConfig, onboardingListener)
```
```java
FlowConfig flowConfig = new FlowConfig.Builder()
    .addQRScan(true)
    .build();

IncodeWelcome.OnboardingListener onboardingListener = new IncodeWelcome.OnboardingListener() {
    @Override
    public void onQRScanCompleted(@NonNull QRScanResult qrScanResult) {
        // Read the decoded QR value
        String decoded = qrScanResult.value;
    }

    @Override
    public void onError(@NonNull Throwable error) {}

    @Override
    public void onUserCancelled() {}
};

IncodeWelcome.getInstance()
    .startOnboarding(activityContext, sessionConfig, flowConfig, onboardingListener);
```

## Configuration Options

QR Scan has no `Builder`. Its single option is supplied through the `addQRScan` overload or the `QRScan` constructor.

| Setting         | Description                                                                                            |
| --------------- | ------------------------------------------------------------------------------------------------------ |
| `showTutorials` | When `true` (the default), shows the tutorial screens that explain the QR scan process before capture. |

For the complete option set, see `QRScan` in [API Reference](https://developer.incode.com/docs/android-api-reference).

## Result

QR Scan delivers a `QRScanResult` through the `onQRScanCompleted(QRScanResult)` callback on the `OnboardingListener`. Key fields include:

- `value`: The value decoded from the scanned QR code; `null` when unavailable.
- Fields inherited from `BaseResult`:
  - `resultCode`: The `ResultCode` for this result.
  - `error`: When `resultCode` is `ERROR`, the `Throwable` that caused it; otherwise, `null`.
  - `deviceStats`: The `DeviceStats` snapshot of the device state when the result was produced.
  - `motionStatus`: Device motion assessment during capture. One of the following:
    - `UNCLEAR`: Motion could not be determined; the default.
    - `PASS`: Device motion was within acceptable limits.
    - `FAIL`: Excessive device motion was detected.

Errors surface through `OnboardingListener.onError(Throwable)`. If the decoded QR code cannot be uploaded to the server, the SDK delivers a `QRCodeUploadException`.

For all fields, see `QRScanResult` in [API Reference](https://developer.incode.com/docs/android-api-reference).
