Scan module integration - rezolved/rezolve_sdk_sampleapp_android GitHub Wiki

Prerequisites

To integrate scan module with rest of Rezolve systems, first you need to complete SspActManager integration (LINK NEEDED), including creation of RezolveConfiguration:

int desiredImageWidthInPixels = 400;

new ResolverConfiguration.Builder(rezolveSDK)
                .enableBarcode1dResolver(true)
                .enableCoreResolver(true)
                .enableSspResolver(sspActManager, desiredImageWidthInPixels)
                .build(this);

This will allow to "translate" result of a scan into a meaningful ContentResult.

Dependencies

These dependencies are required by the Scan module. They should be added in a project build.gradle:

dependencies {
    def sdkScanVersion = "3.0.1"
    implementation "com.rezolve.sdk:scan-android:$sdkScanVersion"
    implementation "com.rezolve.sdk:scan-android-x86:$sdkScanVersion" // optional module, required for support of x86 devices
}

Permissions

The module uses device camera and audio. These permission are required for the Scan module usage.

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />

Please consult official Android docummentation for details about implementing runtime permissions.

Implementation

Sample implementation can be found here.

RezolveScanView view component allows to show camera view:

<com.rezolve.sdk.views.RezolveScanView
      android:id="@+id/rezolve_scan_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />

RezolveScanView instance can be found by using findViewById:

RezolveScanView scanView = findViewById(R.id.rezolve_scan_view);

AudioScanManager and VideoScanManager instances allow to manipulate and use the functionality of the Scan module. AudioScanManagerProvider.getAudioScanManager() returns an AudioScanManager instance, and VideoScanManagerProvider.getVideoScanManager() returns a VideoScanManager instance. Those managers are needed to manage the module and handle data:

private AudioScanManager audioScanManager = AudioScanManagerProvider.getAudioScanManager();
private VideoScanManager videoScanManager = VideoScanManagerProvider.getVideoScanManager();

Scan module usage

First, create a listener for scan callbacks:

    private final ResolveResultListener resolveResultListener = new ResolveResultListener() {
        @Override
        public void onProcessingStarted(@NonNull UUID uuid) {
            Log.d(TAG, "onProcessingStarted: " + uuid);
            processingStarted();
        }

        @Override
        public void onProcessingFinished(@NonNull UUID uuid) {
            Log.d(TAG, "onProcessingFinished: " + uuid);
            processingFinished();
        }

        @Override
        public void onProcessingUrlTriggerStarted(@NonNull UUID uuid, @NonNull UrlTrigger urlTrigger) {
            Log.d(TAG, "onProcessingUrlTriggerStarted: " + uuid + " url: " + urlTrigger.getUrl());
        }

        @Override
        public void onContentResult(@NonNull UUID uuid, @NonNull ContentResult result) {
            Log.d(TAG, "onContentResult: " + result);
            if(result instanceof ProductResult) {
                ProductResult productResult = (ProductResult) result;
                onProductResult(productResult.getProduct(), productResult.getCategoryId());
            } else if(result instanceof CategoryResult) {
                CategoryResult categoryResult = (CategoryResult) result;
                onCategoryResult(categoryResult.getCategory(), categoryResult.getMerchantId());
            } else if(result instanceof SspActResult) {
                SspActResult act = (SspActResult) result;
                if (act.sspAct.getPageBuildingBlocks() != null && !act.sspAct.getPageBuildingBlocks().isEmpty()) {
                    onSspActResult(act);
                }
            } else if(result instanceof SspProductResult) {

            } else if(result instanceof SspCategoryResult) {

            }
        }

        @Override
        public void onResolverError(@NonNull UUID uuid, @NonNull ResolverError resolverError) {
            if(resolverError instanceof  ResolverError.Error) {
                ResolverError.Error error = (ResolverError.Error) resolverError;
                onScanError(error.rezolveError.getErrorType(), error.message);
            }
        }
    };

Create image reader when your fragment or activity is created:

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

        videoScanManager.createImageReader();
    }

It is recommended to check the state of required permissions each time before start of scanning in case user has revoked permissions.

If RECORD_AUDIO permission was given you can initialize audio scan. If CAMERA permission was given you can initialize video scan.

    @Override
    protected void onResume() {
        super.onResume();
        ResolverResultListenersRegistry.getInstance().add(resolveResultListener);

        String[] scannerPermissions = {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
        Permissions.check(this, scannerPermissions, null, null, new PermissionHandler() {
            @Override
            public void onGranted() {
                audioScanManager.clearCache();
                audioScanManager.startAudioScan();

                videoScanManager.clearCache(); // clears cached scan results
                videoScanManager.startCamera(); // starts camera preview
                videoScanManager.attachReader(); // adds watermark detection
            }
        });
    }

When your fragment or activity is paused, stop scan managers and remove the listener from registry to avoid memory leaks. When it goes into onDestroy state, destroy the image reader:

    @Override
    protected void onPause() {
        super.onPause();
        videoScanManager.detachReader();
        audioScanManager.stopAudioScan();
        audioScanManager.destroy();
        ResolverResultListenersRegistry.getInstance().remove(resolveResultListener);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        videoScanManager.destroyImageReader();
    }

It is also popular to implement Rezolve Scan module in "scan on demand" mode. In this case you should add/remove watermark reader on user's demand:

button.setOnTouchListener(new View.OnTouchListener() {
   @Override
   public boolean onTouch(View v, MotionEvent event) {
      switch (event.getAction()) {
         case MotionEvent.ACTION_DOWN:
            // video scan started
            videoScanManager.clearCache();
            videoScanManager.attachReader();
            return true;

         case MotionEvent.ACTION_OUTSIDE:
         case MotionEvent.ACTION_UP:
            // video scan stopped
            videoScanManager.detachReader();
            return true;
      }
         
      return false;
   }
});

Torch

VideoScanManager also provides some helper methods to operate torch:

videoScanManager.isTorchSupported(); // true if torch is supported on a device
videoScanManager.isTorchOn(); // true if torch is currently turned on
videoScanManager.setTorch(boolean isOn); // turns the torch on/off