Overview
SimulScan is an end-to-end data capture solution for extracting critical data from documents. A differentiating data capture value-add, it involves capturing fields of interest in a given document and converting it into data that an end-user application can use immediately at the point of transaction.
SimulScan customers benefit from:
- Productivity gain by decoding multiple bar codes read with a single trigger pull
- Automated data entry with character recognition [OCR]
- Simplified workflow exceptions with checked mark recognition [OMR] and Signature presence detection
Customers can interactively capture documents and obtain meaningful data present in the document. Barcodes are identified and decoded; strings are recognized from fields containing text; images are refined from fields containing pictures and so forth. Based on a "template", an image of the entire document is processed by various engines to extract the relevant data.
Prerequisites
What's required:
- A Zebra device that supports SimulScan: (support details)
- TC55 KK
- TC70 KK or L
- TC75 KK or L
- TC8000 L
- EMDK v3.1.x and higher
Licensing
Refer to the SimulScan Licensing page to obtain a per-device license)
Copy the received XML to the device
Setup the license on the device:
- Go to Settings -> About phone -> Legal information -> Symbol licenses (this will only be available on a 2.42+ BSP device)
- Click on the Android menu button -> Install license
- Navigate to the XML you copied
- Once this is complete, the License Information should be updated to reflect the fact that a license is installed
Getting started
Initialize EMDK manager
Follow the “Basic Scanning Tutorial using Barcode API” to set up your project for the EMDK.
Note: It is recommended to release EMDKManager in onDestroy() and onClose() (Service disconnected unexpectedly)
Get SimulScanManager
SimulScanManager simulscanManager = (SimulScanManager) emdkManager.getInstance(FEATURE_TYPE.SimulScan);
Note: Release() must be called on SimulScanManager before switching to another EMDK or DataWedge application
Get SimulScanReader
There are two options here:
Use the SimulScanManager.getDevice(SimulScanDeviceIdentifier deviceIdentifier) API
The valid SimulScanDeviceIdentifiers are:
- INTERNAL_CAMERA1 : Use the internal camera
- INTERNAL_IMAGER1 : Use the internal imager
- TEMPLATE_DRIVEN : Use the device defined in the template
If the SimulScanDeviceIdentifier is not valid in the target platform an exception will be thrown from the call to “getDevice”
try { simulscanManager.getDevice(SimulScanDeviceIdentifier.INTERNAL_CAMERA1); } catch (SimulScanException e) { e.printStackTrace(); }
Use the SimulScanManager.getSupportedDevicesInfo() first and then pass one the received SimulScanReaderInfo objects to SimulScanManager.getDevice(SimulScanReaderInfo simulscanReaderInfo)
List<SimulScanReaderInfo> readerInfoList = simulscanManager.getSupportedDevicesInfo(); try { simulscanManager.getDevice(readerInfoList.get(0)); } catch (SimulScanException e) { e.printStackTrace(); }
Using SimulScanReader
First register data and status listener to the SimulScanReader object. The listeners must implement the SimulScanDataEventListerner & SimulScanStatusEventListerne interfaces.
public class SimulScanTestApp implements SimulScanStatusEventListerner, SimulScanDataEventListerner{
@Override
public void onSimulScanData(SimulScanData form) {
// TODO Auto-generated method stub
}
@Override
public void onSimulScanStatus(SimulScanStatusData status) {
// TODO Auto-generated method stub
}
}
....
SimulScanTestApp m_ SimulScanTestApp = new SimulScanTestApp();
try {
selectedSimulScanReader.addSimulScanStatusListener(m_ SimulScanTestApp); selectedSimulScanReader.addSimulScanDataListener(m_ SimulScanTestApp);
} catch (SimulScanException e) {
e.printStackTrace();
}
SimulScanReader.enable() enables the reader hardware. This method does not make the reader to scan. Basically it will make the scanner device available for your application. If another reader is already enabled by you or other applications, this will throw a SimulScanException. You must call disable() when you are done, otherwise all readers will remain locked and will be unavailable for this and any other application that uses SimulScan.
try {
selectedSimulScanReader.enable();
} catch (SimulScanException e) {
e.printStackTrace();
}
Once the barcode is enabled, we will must set a valid template for the reader. The template and other configurations can be changed via the SimulScanReader’s SimulScanConfig. The templates can be loaded via the SimulScanMultiTemplate class.
SimulScanConfig config = selectedSimulScanReader.getConfig();
SimulScanMultiTemplate multiTemplate = new SimulScanMultiTemplate(Uri.fromFile("/file/path"));
if(multiTemplate != null)
config.multiTemplate = multiTemplate;
//optionally set other configs
config.enableAutoCapture = true;
config.enableResultConfirmation = true;
config.processingTimeout = 10000;
// Apply config
selectedSimulScanReader.setConfig(config);
To create SimulScan templates use the “Template Builder" graphical tool web tool at https://simulscan.zebra.com/. Template builder help can be found there at https://simulscan.zebra.com/Content/Help/WebHelp/index.htm. After creating the templates, copy the template XML to your device and use the “new SimulScanMultiTemplate()” API to open the created template.
After setting a template we can start a scan using the SimulScanReader.read() API. The read request can be canceled by issuing a cancelRead(). If a read() is submitted while another read is pending, the method call will fail. It is recommended to check whether a read is pending by calling isReadPending() before submitting a read().
try {
if(!selectedSimulScanReader.isEnabled())
selectedSimulScanReader.enable();
} catch (SimulScanException e) {
e.printStackTrace();
}
When we are done with scanning, we must release the scanner hardware resources for other applications to use. So it is recommended to override onStop() method disable any enabled SimulScanReaders.
@Override
public void onStop(){
if(selectedSimulScanReader.isReadPending()){
try {
selectedSimulScanReader.cancelRead();
} catch (SimulScanException e) {
e.printStackTrace();
}
}
try {
if(selectedSimulScanReader.isEnabled()){
selectedSimulScanReader.disable();
}
} catch (SimulScanException e) {
e.printStackTrace();
}
super.onStop();
}
SimulScanConfig in detail
The SimulScanConfig APIs can be used to set various SimulScan configuration parameters for each SimulScan reader. To get the current configuration of a SimulScanReader via a SimulScanConfig object, use the SimulScanReader.getConfig() API. Use the SimulScanConfig object’s public parameters to change the configuration and then call SimulScanReader.setConfig(SimulScanConfig config) to apply the changes.
The valid configuration parameters are as follows:
enableAutoCapture : If true, form will be captured automatically when detected.
enableDebugMode : If enabled, allows a session to write form capture, region images, region values, and other data to storage.
enableFeedbackAudio : Turn on/off audio feedback.
enableHaptic : Turn on/off haptic feedback.
enableLED : Turn on/off LED feedback.
enableResultConfirmation : If enabled, shows a UI confirmation with results in SimulScanView before sending results back to application.
identificationTimeout : Amount of time in milliseconds to wait before timing out identification.
multiTemplate : The SimulScanMultiTemplate to scan
processingTimeout : Amount of time in milliseconds to wait before timing out processing
:::java SimulScanConfig config = selectedSimulScanReader.getConfig();
config.enableAutoCapture = true; config.enableResultConfirmation = true; config.processingTimeout = 10000;
// Apply config selectedSimulScanReader.setConfig(config);
Handling onSimulScanStatus events
EMDK will generate onSimulSCanStatus events when there is a change in state in a particular SimulScanReader. Use the SimulScanStatusData object in the onSimulScanScanStatus callback method to get information on the status.
@Override
public void onSimulScanStatus(SimulScanStatusData statusData) {
// Print the friendly name of the Reader that originated the status update
Log.v(TAG, "Reader: "+ statusData.getFriendlyName());
// Handle the various state changes
switch (statusData.getState()) {
case DISABLED:
Log.v(TAG, "onDisabled");
break;
case ENABLED:
Log.v(TAG, "onEnabled");
break;
case SCANNING:
Log.v(TAG, "Scanning");
break;
case IDLE:
Log.v(TAG, "Idle");
break;
case ERROR:
Log.e(TAG, "ERROR: " + statusData.extendedInfo. getExtendedStatusDescription ());
break;
case UNKNOWN:
default:
break;
}
}
Use the SimulScanStatusData’s getFriendlyName() API to get the friendly name of the SimulScanReader that has generated the Status event and use the getState() API to get the SimulScanStatus object with the status change information.
The list of valid states are as follows:
- DISABLED : Disabled called successfully on reader
- ENABLED : Enabled reader successfully
- ERROR : Error occurred
- IDLE : Finished scanning
- SCANNING : Successfully started scanning
- UNKNOWN : Known status
For additional error information use the Extended info parameter of the SimulScanStatusData object.
Note: If you plan to do any significant processing during the onSimulScanStatus callback, you should do so in a background thread so that it does not block the UI thread.
Handling onSimulScanData events
EMDK will generate onSimulScanData events after a successful scan. Use the SimulScanData object that is passed to this callback routine to get the extracted scanned information.
Note: The SimulScanData should be processed on a background thread so that it does not block the UI thread.
public void onSimulScanData(SimulScanData simulscanData) {
Date timestamp = new Date(simulscanData.getTimestamp());
List<SimulScanElement> simulscanDataElements = simulscanData.getElements();
List<SimulScanRegion> simulscanDataRegions = new ArrayList<SimulScanRegion>();
for (SimulScanElement curElement : simulscanDataElements)
{
if (curElement instanceof SimulScanRegion) {
Log.d(TAG, ((SimulScanRegion) curElement).getName());
} else if (curElement instanceof SimulScanGroup) {
List<SimulScanRegion> regionsInGroup = ((SimulScanGroup)curElement).getRegions();
for (SimulScanRegion curRegion : regionsInGroup){
Log.d(TAG, “Group:”+ ((SimulScanGroup)curElement).getName() +” Region:”+ ((SimulScanRegion) curRegion).getName());
}
}
}
}
SimulScanData.getTemplate() returns the extracted template. This template information can be used to reconstruct the original scanned image from the extracted data. The SimulScanElements returned from SimulScanData.getElements() API are either instances of SimulScanRegion for SimulScanGroup. Use the SimulScanRegion’s getData() API to get the actual OCR, OMR, Barcode or image data. The type of the returned object from getData() will depend on the SimulScanRegion.
RegionType as shown in the table below:
RegionType | Data type |
OCR | String |
OMR | Integer |
Barcode | String |
Picture | Byte[] (binary image data) |
Important considerations
Due to a known issue with the Symbol SimulScan framework version 1.8, the orientation of your application must be fixed preferably using the AndroidManifest.xml. Failing to do so may cause your application to hang if the orientation changes during a scan.
SimulScan Default Templates
The SimulScan default templates are available under "/enterprise/device/settings/datawedge/templates"
. Although this path is not accessible via the file browser on devices having latest images, it is possible to access the path programmatically and get templates copied to any other location preferred by the application. The application must obtain the SimulScanManager instance before attempting to copy these templates from above location.