Customize Unattended Process UI
If you need more extensive customization for your unattended process, you can define your own layout and just ask MobbScan to draw the camera stream during the whole process in a specific view in your layout.
This gives you the ability to create your own activity, and you will be able to show the messages and handle the events that suit your needs.
Follow the next steps in order to have a nice, functional activity with an unattended process.
1. Set portrait mode on the activity
MobbScan handles the rotation of the device in a different way as most applications. Because of this, all the activities that implements custom scan layouts must be set to vertical (portrait) orientation in the AndroidManifest.xml
file.
...
<activity
android:name="com.mobbeel.mobbscan.UnattendedDetectionActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar" />
...
2. Layout modification
You will have to include three elements in your custom layout so MobbScan can use them to draw the camera and detect faces and documents.
- FrameLayout: View where the camera frames will be streamed by MobbScan.
- DetectorView: View with a rectangular cutout for the document detection process.
- FaceFeedbackView: View with an oval cutout for the face detection process.
<?xml version="1.0" encoding="utf-8"?>
<YOUR_LAYOUT>
...
<FrameLayout
android:id="@+id/cameraViewContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.mobbeel.mobbscan.ux.DetectorView
android:id="@+id/documentDetectorView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.mobbeel.mobbscan.ux.FaceFeedbackView
android:id="@+id/faceDetectorView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
...
</YOUR_LAYOUT>
The FrameLayout must be displayed during the whole process, as this displays the camera in your activity. But the other two views should only be displayed when they are necessary. Therefore, keep the visibility of both of them as invisible
while they are not being used.
3. Views configuration
These two views that we add can be configured to fit your app style.
DetectorView options
setText
: allows you to place some text in the middle of the detection rectangle, useful for feedback messages, for example. The color resource id used for this istext_color
. If you don't want to use this text, set it to an empty string.setColorRectangleBorder
: allows you to change the color of the rectangle border. The color resource id used for this isrectangle_default_color
.setSizeRectangleBorder
: allows you to change the width of the border.setBackgroundColorHex
: allows you to change the color of the non cutout part of the view, which is transparent by default. You may want to give some black tint in order to make the cutout more distinguishable. Another way to change this color is by overriding thebackground_default_color
color resource id.setBackgroundColor
: allows you to make the same assetBackgroundColorHex
but passing the final color. Another way of changing this color is by overriding thebackground_default_color
color resource id.setDocumentDetectedColor
: this will change the border color of the rectangle to the default detect color. This is very useful to let the user know whether the document is being detected or not. If you want to change the detection color, just override therectangle_detect_color
color resource id.setDocumentNotDetectedColor
this will change the border color back to the default color. This is very useful to let the user know whether the document is being detected or not. If you want to change the detection color, just override therectangle_default_color
color resource id.
If you want to change the color of any of the default colors used, just override the corresponding color resource id as explained in Customize MobbScan Default Interfaces.
FaceFeedbackView options
setBackgroundColor
: allows you to change the color of the non cutout part of the view, which is transparent by default. You may want to give some black tint in order to make the cutout more distinguishable. Another way of changing this color is by overriding theface_overlay_color
color resource id.- Border color: in this view we have two borders. One of them is the white one, which is displayed from the beginning. You can change this color by overriding the
face_outline_color
color resource id. The other border is the one that indicates the progress in green. In order to change the color of this other border override theface_progress_color
resource id. setProgress
: allows you to set the progress that is returned by the detection feedback in the view.
If you want to change the color of any of the default colors used, just override the corresponding color resource id as explained on Customize MobbScan Default Interfaces.
4. Document Detector configuration
Once you have your MobbScan views configured according to your needs, you should configure the detection process. To do this, you will have to do the following:
Create the DocumentDetectionTrack
MobbScan needs to have the information about the views, and where to show the frames.
In order to tell MobbScan where to place the frames, you have to set a MobbScanDocumentDetectionTrack
with the view where you want the frames.
This newly created object needs to hold all the information about where to look for the document inside the frames, so you have to set a MarginsListener
and pass the information from the DetectorView you have on your layout as follows:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
val documentDetectionTrack = MobbScanDocumentDetectionTrack(cameraViewContainer)
documentDetectorView.setMarginsListener({ marginLeft, marginTop, marginRight, marginBottom ->
documentDetectionTrack.setClearZone(marginLeft, marginTop, marginRight, marginBottom)
})
MobbScanAPI.getInstance().documentDetectionTrack = documentDetectionTrack
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanDocumentDetectionTrack documentDetectionTrack = new MobbScanDocumentDetectionTrack(cameraViewContainer);
documentDetectorView.setMarginsListener((marginLeft, marginTop, marginRight, marginBottom) ->
documentDetectionTrack.setClearZone(marginLeft, marginTop, marginRight, marginBottom));
MobbScanAPI.getInstance().setDocumentDetectionTrack(documentDetectionTrack);
...
}
Get feedback about the detection
If you need to show feedback about the detection process to your user, you have to configure a listener for this matter:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().setIdDocumentDetectionFeedbackListener(object : IDDocumentDetectionFeedbackListener {
override fun onIDDocumentDetection(result: MobbScanDetectionFeedbackResult?) {
// Show the user the feedback about the detection process (messages to correct what they are doing)
}
override fun onNewOrientationDetected(rotationDegrees: Int) {
// Won't be used in this screen as the unattended process doesn't support landscape mode.
}
})
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().setIdDocumentDetectionFeedbackListener(new IDDocumentDetectionFeedbackListener() {
@Override
public void onIDDocumentDetection(MobbScanDetectionFeedbackResult result) {
// Show the user the feedback about the detection process (messages to correct what they are doing)
}
@Override
public void onNewOrientationDetected(final int rotationDegrees) {
// Won't be used in this screen as the unattended process doesn't support landscape mode.
}
};
);
...
}
5. Perform StartScan
Now that we have all of our elements configured, we can start with the process. We recommend you to read the Getting started guide before starting with this, as many of the operations needed for this process are mainly the same.
Initialization
This is exactly the same as in the Getting started guide, so you can go there and get more information.
Setting up the SDK parameters
This is exactly the same as in the Getting started guide, so you can go there and get more information.
6. Start recording process
StartScan call
This is exactly the same as in the Getting started guide, so you can go there and get more information.
Configure video streaming
Once you have a valid ScanID from the start process, we are ready to start detecting our document.
The first step in this process is the configuration of the service. While the service is being configured we don't display anything in the cameraViewContainer
view, which is why we recommend using a View to cover the whole screen while the service is being configured and, when it's configured, to remove this View and let the camera preview to be displayed.
To start the configuration process you have to do the next method call:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().startUnattendedVideoDetectingForView(cameraViewContainer, scanId) { result: VideoUnattendedResult, error: MobbScanAPIError? ->
if (result == VideoUnattendedResult.OK) {
// Remove view and start detection
} else {
// If the configuration goes wrong handle it as you want here
}
}
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().startUnattendedVideoDetectingForView(cameraViewContainer, scanId, (result, error) -> {
if (result == VideoUnattendedResult.OK) {
// Remove configuration view and start detection
} else {
// If the configuration goes wrong handle it as you want here
}
});
...
}
As you can see in the code above, the call requires you to pass a RecordingVideoStartedListener
instance. This listener returns whether the configuration process went as expected or if an error occurred. Either way, you will have the information to do whatever you desire with it (restart the process, or show a message maybe).
If the configuration goes as expected, from this point until the end, the frames displayed in the device are being recorded.
7. Detect document
At this point we are ready to start the detection process. It is a good moment to display a View with the information about what the user is going to do next, maybe an animation or the instructions about what to do.
You can do all that you want now, the detection process won't start until you make the next method call:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().detectDocument(documentSide) { result, resultData, error ->
// Process the detection event here
// Save the image of the document now, it will be useful later
}
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().detectDocument(documentSide, new IDDocumentDetectionListener() {
@Override
public void onIDDocumentDetected(MobbScanDetectionResult result, MobbScanDetectionResultData resultData, MobbScanAPIError error) {
// Process the detection event here
// Save the image of the document now, it will be useful later
}
});
...
}
The moment you receive a MobbScanDetectionResult.OK
it will mean that the detection of that side of the document went as desired and you will have the image of the document and some more info in the MobbScanDetectionResultData
object. If you are scanning a one sided document, you have to go to the next step now. In the other case, if you are scanning a two sided document, you will have to call the same method again but changing the documentSide
parameter to the one left and wait for the new MobbScanDetectionResult.OK
for the left document side.
Don't forget that you have the control of the process now. If you want to show some intermediate Views explaining what to do for each side detection, go ahead. You only need to show the View when you receive the first MobbScanDetectionResult.OK
, and remove it when users click a button for example and then start the second call to the method.
8. Face detector configuration
Once you have all the sides of the document detected, you can start the face detection process, as previously explained. Feel free to show a View with instructions before starting the detection process.
Create the DocumentDetectionTrack
Now you need to configure the face detector. As with the document detector, it requires to have the information about the views, and where to show the frames.
In order to tell MobbScan where to place the frames, you have to set a MobbScanFaceDetectionTrack
with the view where you want the frames.
This newly created object needs to hold all the information about where to look for the face inside the frames, so you have to set a MarginsListener
and pass the information from the DetectorView you have on your layout as follows:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
val faceDetectionTrack = MobbScanFaceDetectionTrack(cameraViewContainer)
faceDetectorView.setMarginsListener({ marginLeft, marginTop, marginRight, marginBottom ->
faceDetectionTrack.setClearZone(marginLeft, marginTop, marginRight, marginBottom) })
MobbScanAPI.getInstance().setFaceDetectionTrack(faceDetectionTrack)
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanFaceDetectionTrack faceDetectionTrack = new MobbScanFaceDetectionTrack(cameraViewContainer);
faceDetectorView.setMarginsListener((marginLeft, marginTop, marginRight, marginBottom) ->
faceDetectionTrack.setClearZone(marginLeft, marginTop, marginRight, marginBottom)
);
MobbScanAPI.getInstance().setFaceDetectionTrack(faceDetectionTrack);
...
}
Get feedback about the detection
If you want to show feedback about the detection process to your user, in this case, you have to configure a listener for this matter:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().setIdDocumentDetectionFeedbackListener(object : IDDocumentDetectionFeedbackListener {
override fun onIDDocumentDetection(result: MobbScanDetectionFeedbackResult?) {
// Show the user the feedback about the detection process (messages to correct what they are doing)
}
override fun onNewOrientationDetected(rotationDegrees: Int) {
// Won't be used in this screen as the unattended process doesn't support landscape mode.
}
})
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().setIdDocumentDetectionFeedbackListener(new IDDocumentDetectionFeedbackListener() {
@Override
public void onIDDocumentDetection(MobbScanDetectionFeedbackResult result) {
// Show the user the feedback about the detection process (messages to correct what they are doing)
}
@Override
public void onNewOrientationDetected(final int rotationDegrees) {
// Won't be used in this screen as the unattended process doesn't support landscape mode.
}
};
);
...
}
Configure camera
At this point we have the rear camera displaying the frames. In order to change to the front camera you have to do the next method calls:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().unattendedVideoSwitchCamera()
MobbScanAPI.getInstance().mirrorCamera() // To make the movement of the user more natural
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().unattendedVideoSwitchCamera();
MobbScanAPI.getInstance().mirrorCamera(); // To make the movement of the user more natural
...
}
9. Detect face
Before starting this process, remove the DetectorView from the layout, put the visibility of the view as gone
.
If you started your layout with the FaceFeedbackView
visibility as gone
, now it's the moment to show it as we are about to start with the facial process.
All these changes could be nicely done behind an explaning View, so you don't have to worry about the actual order or the timing of the camera changes.
When you have your View all set up and ready to start detecting the face, you only have to call this method:
Note: Right now the only validation method available for these process is
MobbScanFaceValidationMode.DEFAULT
any other is not supported.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().detectFace(MobbScanFaceValidationMode.DEFAULT) { result, data, error ->
// Called when the face is acquired.
// Get the face image from data.
}
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().detectFace(MobbScanFaceValidationMode.DEFAULT, new FaceAcquisitorListener() {
@Override
public void onFaceAcquired(MobbScanFaceAcquisitorResult result, MobbScanFaceAcquisitorData data, MobbScanAPIError error) {
// Called when the face is acquired.
// Get the face image from MobbScanFaceAcquisitorData.
}
});
...
}
When you receive the MobbScanFaceAcquisitorResult.FACE_ACQUIRED
event, you have all the images you need in order to validate your user. Save the face image as this will be usefull in the future.
10. Validate user
At this point we have all the information we need to validate our user:
- Front document image (if needed)
- Back document image
- User face image
All of the following thing we do to validate our user doesn't require the camera to be visible, so you can place a View with an undetermined spinner while you get the results back.
Scan document
To scan the document and get the data from it, you have to call the following method:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().scanDocument(scanId, frontDocumentImage, backDocumentImage, IDDocumentScanListener { result, resultData, error ->
// Your IDDocumentScanListener code here...
})
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().scanDocument(scanId, frontDocumentImage, backDocumentImage, new IDDocumentScanListener() {
@Override
public void onIDDocumentScanned(MobbScanScanResult result, MobbScanScanResultData resultData, MobbScanAPIError error) {
// Your IDDocumentScanListener code here...
}
});
...
}
When you receive a MobbScanScanResult.COMPLETED
event, it means that your document has been scanned and the information has been extracted. You can check in the MobbScanScanResultData
object the validation of the document, and if they are not good enough for you, you decide if you want to restart the process.
Validate user face
In order to validate your user with the ID that was shown, you have to perform the next method call:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().validateFace(scanId, userFaceImage) { result, resultData, error ->
// Your ValidationCheckListener code here...
}
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().validateFace(scanId, userFaceImage, new ValidationCheckListener() {
@Override
public void onValidationChecked(MobbScanValidationState result, MobbScanValidationResultData resultData, MobbScanAPIError error) {
// Your ValidationCheckListener code here...
}
});
...
}
The moment you get MobbScanValidationState.VALID
event it means that the user was validated. If you get a different result, you can ask the user to repeat the facial validation again, or to start the process again.
11. Stop recording
When you have your user validated, you can now stop the video recording. You can stop this the moment you get the facial detection result too. It's up to you when you want to stop the video recording. In order to stop it, you just have to call the following method:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
MobbScanAPI.getInstance().stopUnattendedVideo { result, error ->
// If VideoUnattendedResult.OK, video saved correctly.
// If VideoUnattendedResult.ERROR start process again.
}
...
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MobbScanAPI.getInstance().stopUnattendedVideo(new RecordingVideoFinishedListener() {
@Override
public void onVideoFinished(VideoUnattendedResult result, MobbScanAPIError error) {
// If VideoUnattendedResult.OK, video saved correctly.
// If VideoUnattendedResult.ERROR start process again.
}
});
...
}
At this point the video recording stops, and you can close the activity. As you can see in the method call you have to pass a RecordingVideoFinishedListener
as a parameter. If the result is an error, this means that something happened at the moment of saving the video in the Backend, and you should start the process all over again.