Base Implementation
SmartScanner
Interaction with the SmartID Scan library is handled via a SmartScanner object. Instantiate it inside the onCreate()
method of your Activity and pass a reference to your context:
// Constructors for instantiating a SmartScanner object using Android Camera API 1 or 2
mSmartScanner = new SmartScanner(context);
mSmartScanner = SmartScanner(context, cameraId, minScoreCameraAPI2);
// Constructor for instantiating a SmartScanner object unsing Android Camera API X
mSmartScanner = new SmartScanner(context, previewView);
cameraId : set the camera ID of your device. If you want the library to automatically select the best camera, use
NO_CAMERA_ID
as the value.minScoreCameraAPI2 : The minimum level of support required for using Camera API 2. The options are :
LEVEL_LIMITED
,LEVEL_FULL
,LEVEL_3
,DEFAULT_MINIMAL_SCORE
.DEFAULT_MINIMAL_SCORE
is by default set toLEVEL_LIMITED
(more information about levels support on android).previewView : View that displays the camera feed for the CameraX. Refer to the Camera API X section for implementation details.
Decoding type
Now set the decoding type and subtype according to the decoding library you downloaded by calling the setDecodingType()
method on the SmartScanner object. This method supports bitwise operators if you need to specify multiple decoding options:
mSmartScanner.setDecodingType(
IcareDecoders.CODE_OCRB | IcareDecoders.CODE_1D2D,
IcareDecoders.CODE_CH_DRV_LICENSES | IcareDecoders.CODE_EAN8 | IcareDecoders.CODE_EAN13
);
Life cycle
As SmartScanner involves calls to the Android Camera API, it is tightly coupled with the Activity lifecycle.
Call init()
method of SmartScanner object in onResume()
:
@Override
public void onResume() {
//Checks if the application as the rights permission to run the camera
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
//To improve with your own permission dialog, this is only as example
Toast.makeText(getContext(), R.string.request_permission, Toast.LENGTH_SHORT).show();
}
else {
//Initialize the SmartScanner library
mSmartScanner.init();
}
}
To ensure resources are released when they are no longer needed, call release()
on SmartScanner object in onPause()
.
@Override
public void onPause() {
mSmartScanner.release();
super.onPause();
}
Remember to either reset values to their defaults or save the state of your application if you are using functionalities like zoom or some toggle buttons before the application is destroyed.
Layout and Views
Define a layout with one CanvasDrawer for target display and one SurfaceView for camera preview, layering them on top of each other:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="@+id/activity_main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Displays the camera preview -->
<ch.icare.smartscan.views.AutoFitTextureView
android:id="@+id/texture"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<!-- Displays targeting help. You can set target window color and width here using custom attributes -->
<ch.icare.smartscan.views.CanvasDrawer
android:id="@+id/canvasdrawer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/colorPrimaryDark"
custom:targetWidth="4dp"
custom:targetColor="@color/colorAccent"/>
<!-- Displays the focus area -->
<View
android:id="@+id/focus"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
android:background="@drawable/rectangle" />
</FrameLayout>
Pass these two views to SmartScanner within your Activity or Fragment. Ensure the layout is fullscreen to prevent distortion in the camera preview :
mSmartScanner.setCanvasDrawer((CanvasDrawer)findViewById(R.id.canvasdrawer));
mSmartScanner.setSurfaceView((SurfaceView)findViewById(R.id.surfaceview));
Setup and Results
Some functionalities can only be activated when the library is fully loaded. To ensure this, use the OnDecoderLoadedListener :
mSmartScanner.setOnLoadedListener(roi -> {
// Put your code here
// Example:
mSmartScanner.setRegionOfInterest(...)
mSmartScanner.setProcessedFrameRate(...)
});
When a code is successfully decoded, the result is delivered via the OnDecoderResultFoundListener listener:
mSmartScanner.setOnResultListener(result -> {
// Put your code here
// Example:
Toast.makeText(getContext(), result.getResultString(), Toast.LENGTH_SHORT).show();
mSmartScanner.restartDecoding(); // Restart decoding if setContinuousDecoding is set to false
}
);
Refer to the DecodedResult section for more details on the result object.
Theia
Theia is a plate reader powered by deep learning. It requires some configuration adjustments to function properly. As a reminder, Theia is compatible with Android API level 26 and above (see Requirements).
Dependencies
To use the Theia decoder, include the following entries in your manifest file:
<uses-library
android:name="libOpenCL.so"
android:required="false" />
<uses-library
android:name="libOpenCL-pixel.so"
android:required="false" />
Decoding type
The Theia decoder does not have any subtypes. If you are integrating only this decoder, you can use the CODE_NO_SUBTYPE
subtype in the setDecodingType
function:
mSmartScanner.setDecodingType(
IcareDecoders.CODE_THEIA_PLATE_READER,
IcareDecoders.CODE_NO_SUBTYPE
);
Decoder Loading
On lower-performance devices, Theia may take some time to load before it is ready for decoding.
If needed, you can initialize the loading process at the application's startup using the static loadScanner
function.
This initialization should be executed in a background thread to avoid blocking the main UI thread:
new Thread(() -> SmartScanner.loadScanner(context)).start();
You can use the OnDecoderReadyListener
to know when the decoder is ready to decode:
mSmartScanner.setOnDecoderReadyListener(() -> {
// Put your code here
});
Camera API X
The SmartID Scan library is compatible with Android Camera API X. To use it, a few modifications are required.
Dependencies
Add the following dependencies to your gradle
:
def camerax_version = "1.1.0"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version"
Layout and Views
Add a PreviewView to your layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="@+id/activity_main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Wrap the CameraX preview -->
<androidx.camera.view.PreviewView
android:id="@+id/previewview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<ch.icare.smartscan.views.AutoFitTextureView
android:id="@+id/texture"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<ch.icare.smartscan.views.CanvasDrawer
android:id="@+id/canvasdrawer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/colorPrimaryDark"
custom:targetWidth="4dp"
custom:targetColor="@color/colorAccent"/>
<View
android:id="@+id/focus"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
android:background="@drawable/rectangle" />
</FrameLayout>
Instantiation
Instantiate the SmartScanner using its dedicated constructor:
PreviewView previewView = findViewById(R.id.previewview);
SmartScanner smartScanner = new SmartScanner(this, previewView);
Then proceed as usual.
Permissions
Specify the required features and permissions in the app's manifest file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.smartscan.myapplication">
<uses-permission android:name="android.permission.FLASHLIGHT" ">
<uses-permission android:name="android.permission.CAMERA" ">
<uses-permission android:name="android.permission.VIBRATE" ">
<uses-feature android:name="android.hardware.camera" ">
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" ">
<uses-feature
android:name="android.hardware.camera.flash"
android:required="false" ">
...
</manifest>
Depending on your target API level (23 and above), you should also handle camera permissions within your code.
QR-Code with ECI support
Since version 2.0.0, the QR code scanner complies with the latest ISO/IEC 18004 standard. As before, the library will decode the QR code and parse it to provide you with the formatted result.
If an error occurs during parsing, the method getErrorParsingQrCode()
will provide information about the issue, and the specific error will be included in the result returned by getResultString()
.
Here an example:
mSmartScanner.setOnResultListener(new OnDecoderResultFoundListener() {
@Override
public void onResultFound(DecodedResult result) {
if(result.getErrorParsingQrCode())
Log.d("Error" , "ERROR WHEN PARSING QR CODE: " + result.getResultString());
}
});