Skip to main content

Custom capture UI

Use MBCaptureSessionService when your application must own the surrounding controls and layout. The SDK still manages camera capture and validation; your fragment manages presentation and user interaction.

Add a capture container​

<FrameLayout
android:id="@+id/capture_view_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />

Create the capture service​

class CustomCaptureFragment : Fragment(R.layout.custom_capture_fragment),
MBCaptureSessionListener,
MBBoundingBoxFaceValidatorListener,
MBCaptureProgressListener,
MBCountDownListener {

private lateinit var captureService: MBCaptureSessionService

@SuppressLint("UnsafeOptInUsageError")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val orientation = when (resources.configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> MBOrientation.LANDSCAPE
else -> MBOrientation.PORTRAIT
}

val options = MBCaptureSessionOptions.Builder()
.captureConstrains(MBCaptureConstrains.V3)
.imageQualityLevel(MBImageQualityLevel.LEVEL_2)
.videoCaptureDuration(2_000)
.cameraQuality(MBCameraOptions(orientation = orientation))
.build()

captureService = MBCaptureSessionService(
requireContext(),
viewLifecycleOwner,
options
).apply {
captureSessionListener = this@CustomCaptureFragment
faceBoundingBoxValidatorListener = this@CustomCaptureFragment
captureProgressListener = this@CustomCaptureFragment
countDownListener = this@CustomCaptureFragment
}

view.findViewById<FrameLayout>(R.id.capture_view_container)
.addView(captureService.getCaptureSessionView())

captureService.startCamera(sessionId)
}
}

The lifecycle owner allows CameraX to stop camera work when the fragment view is destroyed. For V2 and V3, set MBCameraOptions.orientation to match the current screen orientation.

Handle session events​

override fun onSuccess(result: MBCaptureSessionResult?) {
result?.let(::upload)
}

override fun onFailure(errorEnum: MBCaptureSessionError) {
showRetry(errorEnum)
}

override fun onStateChanged(stateEnum: MBCaptureState) { }

Show V3 feedback​

override fun onValidating(
faceBoxStatus: MBFaceBoundingBoxStatus,
faceGeometry: MBFaceGeometryModel
) {
feedbackLabel.text = feedbackText(faceBoxStatus)
}

Check geometry before lighting so the user receives one clear instruction at a time. See Capture constraints and image quality for the status fields.

Show progress and countdown​

override fun onCaptureProgress(captureProgressCounter: Float) {
progressBar.progress = (captureProgressCounter * 100).toInt()
}

override fun onCountdown(timeCounter: Int) {
countdownLabel.text = timeCounter.toString()
}

Manual capture​

Set .automaticCapture(false), then call startCaptureSession() from your button after the SDK reports a valid face:

captureButton.setOnClickListener {
captureService.startCaptureSession()
}

Disable the button until validation succeeds to avoid collecting an invalid capture.