ANDROID DocumentDetector Setting up the SDK Customization Learn how to customize our SDK and make it look like your app.
Custom layout creation
To create a new layout we recommend that you use the default templates from the SDKs and make the desired changes.
Step-by-step
Declare the dependency on CameraView
in your app-level gradle file.
Copy // CameraX core library using the camera2 implementation
implementation "androidx.camera:camera-view:1.3.4"
2. Create a layout file in your project's layout directory using the CAF template.
3. Create your views, and parameterize the visibility and call methods of the ViewModel of each corresponding SDK according to the following tables. Example:
Copy < layout >
...
< androidx.camera.view.PreviewView
android : id = "@id/cameraImageView"
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : visibility = "@{viewModel.cameraVisibility ? View.VISIBLE : View.GONE}"
/>
...
</ layout >
Variables and methods used in layout
All the methods and variables described below are accessed from the SDKViewModel class.
Methods
Method
Description
Return
SDK
Responsible for initiating image capture in MANUAL mode
DocumentDetector, PassiveFaceLiveness
Responsible for closing the SDK.
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
Responsible for reversing the camera.
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
State variables
The Layout used in the SDK is composed of several state variables, these variables are responsible for identifying the state that the SDK is in at each moment of its execution:
Variable
Description
Type
SDK
Indicates the 'loading' state
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
Indicates that the SDK is ready to capture, after performing all validations for sensors, framing, face, etc.
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
stepDoneSuccessfullyStatus
Indicates that the capture step ended successfully
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
Indicates if there are any faulty sensor checks, quality, framing, face distance, etc.
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
Indicates what type of error has occurred. See the table below
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
Indicates the capture mode enabled. May vary between AUTOMATIC and MANUAL
DocumentDetector, PassiveFaceLiveness
Indicates the status of the mask. Can range from NORMAL, SUCCESS to ERROR
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
Responsible for returning the Drawable Resource Id used to define the mask.
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
Name of the previous step that was performed. If not, the value will be null. Example: Back of ID.
DocumentDetector v7.x or below
Visibility variables
Variable
Description
Type
SDK
Indicates the visibility of the step initialization popup
manualCaptureButtonVisibility
Indicates visibility of the manual capture button
DocumentDetector, PassiveFaceLiveness
switchCameraButtonVisibility
Indicates the visibility of the reverse camera button
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
Responsible for the visibility of the SDK status message.
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
Returns the status message. Customize with MessageSettings
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
Returns the status message. Customize with MessageSettings
Responsible for camera visibility.
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
Indicates mask visibility.
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
Responsible for the visibility of the camera flip button.
This variable has been deprecated, we recommend using the switchCameraButtonVisibility variable.
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
Responsible for the visibility of the loading displayed by the SDK.
This variable has been deprecated, we recommend using the loadingStatus variable.
DocumentDetector v7.x or below
, PassiveFaceLiveness, FaceAuthenticator
Sets the visibility of the manual capture button.
This variable has been deprecated, use manualCaptureButtonVisibility.
DocumentDetector v7.x or below
, PassiveFaceLiveness
ValidationFailure
Each SDK contains a number of validation errors that can occur while running. These mostly generate the "error mask" state and prevent the capture from being performed:
SENSOR_LUMINOSITY_FAILURE
Brightness sensor. The environment is too dark
DocumentDetector, PassiveFaceLiveness
SENSOR_ORIENTATION_FAILURE
Orientation sensor. Device not in correct position
DocumentDetector, PassiveFaceLiveness
Stability sensor. The device is in motion
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
DocumentDetector, PassiveFaceLiveness, FaceAuthenticator
A face with closed eyes was identified
PassiveFaceLiveness, FaceAuthenticator
PassiveFaceLiveness, FaceAuthenticator
PassiveFaceLiveness, FaceAuthenticator
PassiveFaceLiveness, FaceAuthenticator
Incorrect face angle on the X axis.
Incorrect face angle on the Y axis.
Incorrect face angle on the Z axis.
PassiveFaceLiveness, FaceAuthenticator
Quality of the document capture is too low.
Error in the proof of life. It is a probable fraud attempt
PassiveFaceLiveness, FaceAuthenticator
Document type or document side was not expected.
PASSPORT_COUNTRY_CODE_FAILURE
Passaport country code (or issuing code) is not allowed.
Using layout in Builder
After creating the desired files, create an object of type DocumentDetector. This object is for you to configure all your business rules for the SDK, including the interface customization attributes:
Copy DocumentDetector mDocumentDetector = new DocumentDetector . Builder ( String mobileToken)
// see table below
. build ();
Builder method
Parameter
Required
Compatibility
.setLayout(@LayoutRes Integer layoutId)
Replaces the SDK's default layout. Create a file in your project's layout folder, copy the standard layout template corresponding to the SDK you are integrating and make the desired changes.
.setStyle(@StyleRes int styleResourceId)
Replaces the SDK's default style. In your project's styles.xml file, copy the default template and edit it.
.setMask(@DrawableRes Integer greenMask, @DrawableRes Integer whiteMask, @DrawableRes Integer redMask)
Replaces the masks for capturing a document or face: SUCCESS, NORMAL, and FAIL, in that order. If you use this option, use masks with the same detection area of the document and face, as this region is very important for the algorithm to capture.
DocumentDetector v7.x or below
.setMask(MaskType type)
Defines which group of masks predefined in the product will be used by the SDK:
MaskType.DEFAULT
, with the dotted pattern in the document format or face;
MaskType.DETAILED
, which displays an illustration of the requested document - CNH or RG - along with the dotted mask (only in DocumentDetector);
MaskType.NONE
, which removes the mask entirely.
No. The default masks are used.
DocumentDetector v7.x or below
Using the methods
Copy DocumentDetector mDocumentDetector = new DocumentDetector . Builder ( String mobileToken)
. setLayout ( R . layout . customLayout )
. setStyle ( R . style . customStyle )
. setMask ( MaskType . DETAILED )
. build ();
Different uses .setMask() method
Copy DocumentDetector mDocumentDetector = new DocumentDetector . Builder ( String mobileToken)
// Using Customized Masks
. setMask ( R . drawable . customGreenMask , R . drawable . customWhiteMask , R . drawable . customRedMask )
// Using masks already offered by the SDK
. setMask ( MaskType . DETAILED )
. build ();
Custom style creation
To create a new style, we recommend that you use the same template that we use, this way it will be easier to perform customizations.
Customization of masks
To customize the masks, first create a drawable resource in your project. You can customize whiteMask, greenMask, and redMask in any way you like. We have provided generic document and face masks that you can use for reference. See the setMask
method definition and examples in DocumentDetector.Builder . And see also examples of custom mask integration.
Default templates
DocumentDetector (v7.x or below) DocumentDetector (v8.x) PassiveFaceLiveness FaceAuthenticator
Activity ( setLayout
)
Copy <? xml version = "1.0" encoding = "utf-8" ?>
< layout >
< data >
< import type = "android.view.View" />
< variable
name = "viewModel"
type = "com.combateafraude.documentdetector.controller.viewmodel.SDKViewModel" />
</ data >
< androidx.constraintlayout.widget.ConstraintLayout
xmlns : android = "http://schemas.android.com/apk/res/android"
xmlns : app = "http://schemas.android.com/apk/res-auto"
android : layout_height = "match_parent"
android : layout_width = "match_parent"
android : keepScreenOn = "true" >
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineStart"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "vertical"
app : layout_constraintGuide_percent = "0.1" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineEnd"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "vertical"
app : layout_constraintGuide_percent = "0.9" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineTop"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "horizontal"
app : layout_constraintGuide_percent = "0.05" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineStatus"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "horizontal"
app : layout_constraintGuide_percent = "0.78" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineBottom"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "horizontal"
app : layout_constraintGuide_percent = "0.97" />
< androidx.camera.view.PreviewView
android : id = "@id/cameraImageView"
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : visibility = "@{viewModel.cameraVisibility ? View.VISIBLE : View.GONE}"
/>
< ImageView
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : src = "@{viewModel.previewBitMap}"
android : visibility = "@{viewModel.previewVisibility ? View.VISIBLE : View.GONE}" >
</ ImageView >
< ImageView
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : adjustViewBounds = "true"
android : contentDescription = "@string/photo_mask_caf"
android : scaleType = "fitXY"
android : visibility = "@{viewModel.maskVisibility ? View.VISIBLE : View.GONE}"
android : src = "@{context.getDrawable(viewModel.maskLayout)}" />
< ImageView
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : padding = "10dp"
android : adjustViewBounds = "true"
android : contentDescription = "@string/close_caf"
android : onClick = "@{() -> viewModel.close()}"
android : src = "@drawable/ic_back_caf"
app : layout_constraintStart_toStartOf = "@id/guidelineStart"
app : layout_constraintTop_toTopOf = "@id/guidelineTop" />
< ImageView
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : padding = "10dp"
android : adjustViewBounds = "true"
android : contentDescription = "@string/switch_caf"
android : onClick = "@{() -> viewModel.switchCamera()}"
android : visibility = "@{viewModel.switchCameraButtonVisibility ? View.VISIBLE : View.GONE}"
android : src = "@drawable/ic_camera_switch"
app : layout_constraintEnd_toEndOf = "@id/guidelineEnd"
app : layout_constraintTop_toTopOf = "@id/guidelineTop" />
< com.google.android.material.floatingactionbutton.FloatingActionButton
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : layout_margin = "16dp"
android : visibility = "@{viewModel.manualCaptureButtonVisibility ? View.VISIBLE : View.GONE}"
android : onClick = "@{() -> viewModel.takePhoto()}"
app : layout_constraintStart_toStartOf = "@id/guidelineStart"
app : layout_constraintEnd_toEndOf = "@id/guidelineEnd"
app : layout_constraintTop_toTopOf = "@id/guidelineStatus"
android : contentDescription = "@string/take_picture"
app : backgroundTint = "?attr/colorPrimary"
app : tint = "#FFF"
app : srcCompat = "@drawable/ic_camera_caf" />
< androidx.constraintlayout.widget.ConstraintLayout
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : visibility = "@{viewModel.statusVisibility ? View.VISIBLE : View.GONE}"
app : layout_constraintStart_toStartOf = "@id/guidelineStart"
app : layout_constraintEnd_toEndOf = "@id/guidelineEnd"
app : layout_constraintTop_toTopOf = "@id/guidelineStatus" >
< TextView
android : id = "@+id/statusMessage"
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : background = "@drawable/bg_radius_caf"
android : gravity = "center_horizontal"
android : lineSpacingExtra = "5sp"
android : padding = "8dp"
android : layout_marginTop = "10dp"
android : textAlignment = "center"
android : textColor = "#606060"
android : textSize = "15sp"
android : textStyle = "bold"
android : text = "@{viewModel.statusMessage}"
app : layout_constraintStart_toStartOf = "parent"
app : layout_constraintEnd_toEndOf = "parent"
app : layout_constraintTop_toTopOf = "parent" />
< ImageView
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : background = "@drawable/triangle_caf"
android : rotation = "270"
android : adjustViewBounds = "true"
android : contentDescription = "@string/nothing_caf"
app : layout_constraintEnd_toEndOf = "@id/statusMessage"
app : layout_constraintStart_toStartOf = "@id/statusMessage"
app : layout_constraintTop_toTopOf = "@id/statusMessage"
app : layout_constraintBottom_toTopOf = "@id/statusMessage" />
</ androidx.constraintlayout.widget.ConstraintLayout >
< TextView
android : id = "@+id/tvCurrentStepName"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
app : layout_constraintBottom_toTopOf = "@id/tvPreviousStepName"
app : layout_constraintStart_toStartOf = "@id/guidelineStart"
app : layout_constraintEnd_toEndOf = "@id/guidelineEnd"
android : layout_marginBottom = "5dp"
android : textSize = "18sp"
android : textColor = "#ffffff"
android : letterSpacing = "0.06"
android : text = "@{viewModel.currentStepName}"
android : gravity = "center_horizontal" />
< ImageView
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : adjustViewBounds = "true"
android : visibility = "@{viewModel.currentStepDone ? View.VISIBLE : View.GONE}"
android : contentDescription = "@string/check_caf"
app : layout_constraintTop_toTopOf = "@id/tvCurrentStepName"
app : layout_constraintBottom_toBottomOf = "@id/tvCurrentStepName"
app : layout_constraintEnd_toStartOf = "@id/tvCurrentStepName"
android : layout_marginEnd = "8dp"
android : src = "@drawable/ic_check_caf" />
< TextView
android : id = "@+id/tvPreviousStepName"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
app : layout_constraintStart_toStartOf = "@id/guidelineStart"
app : layout_constraintEnd_toEndOf = "@id/guidelineEnd"
app : layout_constraintBottom_toBottomOf = "@id/guidelineBottom"
android : textSize = "16sp"
android : textColor = "#66FFFFFF"
android : letterSpacing = "0.06"
android : text = "@{viewModel.previousStepName}"
android : gravity = "center_horizontal" />
< ImageView
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : adjustViewBounds = "true"
android : visibility = "@{viewModel.previousStepDone ? View.VISIBLE : View.GONE}"
android : contentDescription = "@string/check_caf"
app : layout_constraintTop_toTopOf = "@id/tvPreviousStepName"
app : layout_constraintBottom_toBottomOf = "@id/tvPreviousStepName"
app : layout_constraintEnd_toStartOf = "@id/tvPreviousStepName"
android : layout_marginEnd = "8dp"
android : alpha = "0.4"
android : src = "@drawable/ic_check_caf" />
< ProgressBar
android : layout_width = "64dp"
android : layout_height = "64dp"
android : indeterminate = "true"
android : indeterminateTint = "?attr/colorPrimary"
android : indeterminateTintMode = "src_atop"
android : visibility = "@{viewModel.loadingStatus ? View.VISIBLE : View.GONE}"
app : layout_constraintVertical_bias = "0.45"
app : layout_constraintBottom_toBottomOf = "@id/guidelineBottom"
app : layout_constraintTop_toTopOf = "@id/guidelineTop"
app : layout_constraintStart_toStartOf = "@id/guidelineStart"
app : layout_constraintEnd_toEndOf = "@id/guidelineEnd" />
</ androidx.constraintlayout.widget.ConstraintLayout >
</ layout >
Styles ( setStyle
)
Copy <? xml version = "1.0" encoding = "utf-8" ?>
< resources >
< style name = "windowProperties" parent = "Theme.MaterialComponents.Light" >
< item name = "windowActionBar" >false</ item >
< item name = "windowNoTitle" >true</ item >
< item name = "android:windowTranslucentStatus" >true</ item >
< item name = "android:windowActivityTransitions" >true</ item >
< item name = "android:colorControlActivated" >#606060</ item >
</ style >
< style name = "defaultStyle" parent = "windowProperties" >
< item name = "colorPrimary" >#4CD964</ item >
</ style >
< style name = "defaultButtonStyle" parent = "Widget.MaterialComponents.Button" >
< item name = "android:layout_width" >0dp</ item >
< item name = "android:layout_height" >60dp</ item >
< item name = "android:gravity" >center</ item >
< item name = "android:textColor" >#FFFFFF</ item >
< item name = "android:textSize" >18sp</ item >
< item name = "android:fontFamily" >sans-serif</ item >
< item name = "android:textAllCaps" >false</ item >
</ style >
< style name = "transparentButton" parent = "Widget.MaterialComponents.Button" >
< item name = "android:layout_width" >0dp</ item >
< item name = "android:layout_height" >60dp</ item >
< item name = "android:gravity" >center</ item >
< item name = "android:textColor" >#323232</ item >
< item name = "android:textSize" >18sp</ item >
< item name = "android:textStyle" >normal</ item >
< item name = "android:fontFamily" >@font/roboto</ item >
< item name = "android:textAllCaps" >false</ item >
< item name = "android:background" >#00FFFFFF</ item >
</ style >
< style name = "textPreview" parent = "windowProperties" >
< item name = "android:textColor" >#323232</ item >
</ style >
</ resources >
Mask ( setMask
)
Copy < vector xmlns : android = "http://schemas.android.com/apk/res/android"
android : width = "375dp"
android : height = "667dp"
android : viewportWidth = "375"
android : viewportHeight = "667" >
< path
android : pathData = "M375,0V667H0V0H375ZM341,85H35V516H341V85Z"
android : strokeAlpha = "0.35"
android : fillColor = "#000000"
android : fillType = "evenOdd"
android : fillAlpha = "0.35" />
<!--
The color of the mask can be changed by the android:fillColor attribute of the element below.
The default colors are: #22CB7B (green), #E74C3C (red), #ffffff (white)
-->
< path
android : pathData = "--image-byte-array-"
android : fillColor = "#22CB7B"
android : fillType = "evenOdd" />
</ vector >
Activity ( setLayout
)
Copy <? xml version = "1.0" encoding = "utf-8" ?>
< layout xmlns : android = "http://schemas.android.com/apk/res/android"
xmlns : app = "http://schemas.android.com/apk/res-auto"
xmlns : tools = "http://schemas.android.com/tools" >
< data >
< import type = "android.view.View" />
< import type = "com.combateafraude.documentdetector.R" />
< variable
name = "viewModel"
type = "com.combateafraude.documentdetector.controller.viewmodel.SDKViewModel" />
</ data >
< androidx.constraintlayout.widget.ConstraintLayout
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : background = "@color/caf_black"
android : keepScreenOn = "true" >
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineStart"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "vertical"
app : layout_constraintGuide_percent = "0.1" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineEnd"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "vertical"
app : layout_constraintGuide_percent = "0.9" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineTop"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "horizontal"
app : layout_constraintGuide_percent = "0.05" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineBottom"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "horizontal"
app : layout_constraintGuide_percent = "0.97" />
< androidx.constraintlayout.widget.ConstraintLayout
android : layout_width = "0dp"
android : layout_height = "wrap_content"
android : elevation = "1dp"
app : layout_constraintEnd_toEndOf = "@id/frameCameraPreview"
app : layout_constraintStart_toStartOf = "@id/frameCameraPreview"
app : layout_constraintTop_toTopOf = "@id/frameCameraPreview" >
< ImageView
android : id = "@+id/closeImage"
android : layout_width = "32dp"
android : layout_height = "32dp"
android : layout_marginStart = "16dp"
android : layout_marginTop = "16dp"
android : adjustViewBounds = "true"
android : contentDescription = "@string/close_caf"
android : onClick = "@{() -> viewModel.close()}"
android : src = "@drawable/close_capture"
app : layout_constraintStart_toStartOf = "parent"
app : layout_constraintTop_toTopOf = "parent" />
< TextView
android : id = "@+id/tvCurrentStepName"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : layout_marginTop = "16dp"
android : gravity = "center_horizontal"
android : lineSpacingExtra = "5sp"
android : paddingHorizontal = "12dp"
android : paddingVertical = "4dp"
android : text = "@{viewModel.stepName}"
android : textColor = "@color/caf_white"
android : textSize = "16sp"
android : textStyle = "bold"
android : visibility = "@{(viewModel.stepNameVisibility && viewModel.stepName.length() > 0) ? View.VISIBLE : View.INVISIBLE}"
app : cafBackgroundColor = "@{R.color.mask_color_black_background}"
app : layout_constraintEnd_toEndOf = "parent"
app : layout_constraintStart_toStartOf = "parent"
app : layout_constraintTop_toTopOf = "parent"
tools : text = "CNH" />
</ androidx.constraintlayout.widget.ConstraintLayout >
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineTopCameraPreview"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "horizontal"
app : layout_constraintGuide_percent = ".06" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineBottomCameraPreview"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "horizontal"
app : layout_constraintGuide_percent = ".94" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineStartCameraPreview"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "vertical"
app : layout_constraintGuide_percent = ".04" />
< androidx.constraintlayout.widget.Guideline
android : id = "@+id/guidelineEndCameraPreview"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : orientation = "vertical"
app : layout_constraintGuide_percent = ".96" />
< FrameLayout
android : id = "@+id/frameCameraPreview"
android : layout_width = "0dp"
android : layout_height = "0dp"
app : layout_constraintBottom_toBottomOf = "@id/guidelineBottomCameraPreview"
app : layout_constraintEnd_toEndOf = "@id/guidelineEndCameraPreview"
app : layout_constraintStart_toStartOf = "@id/guidelineStartCameraPreview"
app : layout_constraintTop_toTopOf = "@id/guidelineTopCameraPreview" >
< androidx.cardview.widget.CardView
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : elevation = "0dp"
app : cardCornerRadius = "16dp" >
< androidx.camera.view.PreviewView
android : id = "@id/cameraImageView"
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : visibility = "@{viewModel.cameraVisibility ? View.VISIBLE : View.GONE}" />
< ImageView
android : layout_width = "match_parent"
android : layout_height = "80dp"
android : importantForAccessibility = "no"
android : src = "@drawable/preview_camera_gradient" />
< ImageView
android : id = "@+id/previewBitmap"
android : layout_width = "match_parent"
android : layout_height = "match_parent"
android : importantForAccessibility = "no"
android : src = "@{viewModel.previewBitMap}"
android : visibility = "@{viewModel.previewVisibility ? View.VISIBLE : View.GONE}" />
</ androidx.cardview.widget.CardView >
</ FrameLayout >
< androidx.constraintlayout.widget.ConstraintLayout
android : id = "@+id/maskInfoContainer"
android : layout_width = "0dp"
android : layout_height = "0dp"
app : layout_constraintBottom_toBottomOf = "@id/guidelineBottom"
app : layout_constraintEnd_toEndOf = "@id/guidelineEnd"
app : layout_constraintStart_toStartOf = "@id/guidelineStart"
app : layout_constraintTop_toTopOf = "@id/guidelineTop" >
< ImageView
android : id = "@+id/maskImage"
android : layout_width = "80dp"
android : layout_height = "80dp"
android : adjustViewBounds = "true"
android : contentDescription = "@string/photo_mask_caf"
android : src = "@{viewModel.feedbackImage}"
android : visibility = "@{viewModel.feedbackImageVisibility ? View.VISIBLE : View.INVISIBLE}"
app : cafBackgroundColor = "@{viewModel.feedbackStatusBackground}"
app : layout_constraintBottom_toBottomOf = "@id/maskInfoContainer"
app : layout_constraintEnd_toEndOf = "@id/maskInfoContainer"
app : layout_constraintStart_toStartOf = "@id/maskInfoContainer"
app : layout_constraintTop_toTopOf = "@id/maskInfoContainer"
app : layout_constraintVertical_bias = "0.40"
tools : src = "@drawable/center_image" />
< TextView
android : id = "@+id/statusMessage"
android : layout_width = "wrap_content"
android : layout_height = "wrap_content"
android : layout_marginStart = "8dp"
android : layout_marginTop = "8dp"
android : layout_marginEnd = "8dp"
android : gravity = "center_horizontal"
android : lineSpacingExtra = "5sp"