Complete Manual for Facial Detection and Filling in Android Applications
Estimated time: 45-60 minutes for complete configuration
What will you learn from this manual?
That manual will teach you how to implement and use JAAKVisage SDK for automated face detection and video recording in native Android applications. No advanced technical skills required - Just follow the steps.
Before Start - Checks list
Be sure to have these elements ready:
- Android Studio Iguana installed
- Android 6.0 + device (API 23+)
- Gratle 8.4 configured
- Basic knowledge about Kotlin / Android
- Access to a functional camera
Contents Index
| Section | What will you do? | Time |
|---|---|---|
| Step 1 | Configure Project and Units | 10 min |
| Step 2 | Basic implementation of SDK | 20 min |
| Step 3 | Configure permits and manifests | 10 min |
| Step 4 | Record and video management | 15 min |
| Step 5 | Test facial detection | 10 min |
Step 1: Configure Project and Units
Objective
Configure Android development environment and add necessary dependencies to SDK.
Technical requirements
| Requirement | Version | Mandatory? |
|---|---|---|
| Android Studio | Iguana | Yes |
| minSdk | 23 (Android 6.0 +) | Yes |
| targetSdkVersion | 33 | Yes |
| compileSandk | 35 | Yes |
| Fat | 8.4 | Yes |
| Java / Kotlin | 18 | Yes |
1.1 Building (Project) configuration
buildscript {
ext.kotlin_version = "1.9.22"
ext.hilt_version = '2.46'
repositories {
google()
mavenCentral()
maven {
url 'https://us-maven.pkg.dev/jaak-platform/jaak-android'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:8.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
}
}
1.2 Building Setup (Module: app)
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
android {
namespace 'com.jaak.visagesdk'
compileSdk 35
defaultConfig {
minSdk 23
targetSdk 33
versionCode 1
versionName "1.0"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_18
targetCompatibility JavaVersion.VERSION_18
}
buildFeatures {
viewBinding = true
}
}
dependencies {
// Android Core
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.constraintlayout:constraintlayout:2.2.0")
implementation 'com.google.android.material:material:1.12.0'
// Dependency Injection
implementation("com.google.dagger:hilt-android:$hilt_version")
kapt("com.google.dagger:hilt-android-compiler:$hilt_version")
// JAAK Visage SDK
implementation("com.jaak.visagesdk:jaakvisage-sdk:1.0.0-beta")
}
Step 2: Basic implementation of SDK
Objective
Create JAAKVisage's basic implementation SDK with face detection and automatic recording.
2.1 Application Class
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class JaakVisageSDKApp : Application()
2.2 Main activity
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.jaak.visagesdk.databinding.ActivityMainBinding
import com.jaak.visagesdk.ui.adapter.VisageListener
import com.jaak.visagesdk.ui.view.VisageSDK
import com.jaak.visagesdk.utils.CameraFacing
import com.jaak.visagesdk.utils.Utils
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : AppCompatActivity(), VisageListener {
private lateinit var binding: ActivityMainBinding
private lateinit var visageSDK: VisageSDK
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
configureVisageSDK()
binding.btnStartDetection.setOnClickListener {
startFaceDetection()
}
}
private fun configureVisageSDK() {
visageSDK = VisageSDK(this, this)
// Recommended facial detection configuration
visageSDK.setCameraFacing(CameraFacing.FRONT) // Recommended front camera
// Development tools (optional)
visageSDK.setDebugMode(true) // Real-time Metrics: FPS | MEM | FACE | MSC
visageSDK.setConfigPanel(true) // Visible configuration panel
}
private fun startFaceDetection() {
// The SDK automatically manages camera permissions
visageSDK.startVisage() // Begins facial detection and automatic recording
}
override fun onSuccessVisage(typeProcess: Int, uri: Uri?) {
// typeProcess is always 2 (face detection video)
uri?.let { videoUri ->
val base64Video = Utils.videoCameraUriToBase64(videoUri) ?: ""
Log.d("Visage", "Video capturado: $videoUri")
Log.d("Visage", "Base64 length: ${base64Video.length}")
if (base64Video.isNotEmpty()) {
Toast.makeText(this, "Facial video successfully processed", Toast.LENGTH_LONG).show()
// Processing video as required
processVideoForKYC(base64Video, videoUri)
} else {
Toast.makeText(this, "Failed to process video", Toast.LENGTH_SHORT).show()
}
}
}
override fun onErrorVisage(text: String) {
Log.e("Visage", "Error: $text")
val errorMessage = when {
text.contains("permission", ignoreCase = true) -> "Required camera permits"
text.contains("camera", ignoreCase = true) -> "Camera Error - Check that it isn't in use"
text.contains("cancelled", ignoreCase = true) -> "User's cancelled process"
else -> "Error: $text"
}
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show()
}
private fun processVideoForKYC(base64Video: String, originalUri: Uri) {
// Create payload for backend
val kycData = mapOf(
"facialVideo" to base64Video,
"timestamp" to System.currentTimeMillis(),
"source" to "visage_sdk_android",
"videoUri" to originalUri.toString()
)
Log.d("Visage", "Processing video for KYC: ${kycData.keys}")
// Send to your backend /API for biometric analysis
}
}
2.3 Layout XML (activity _ main.xml)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="JAAK Visage SDK Android"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toTopOf="@+id/btnStartDetection"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/btnStartDetection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Initiate Facial Detection"
android:textSize="16sp"
android:padding="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Step 3: Configure Permises and Manifesto
Objective
Configure the permissions and the Android manifesto correctly.
3.1 AndroidManifes.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:replace="android:maxSdkVersion"
android:maxSdkVersion="28"/>
<application
android:name="com.jaak.visagesdk.JaakVisageSDKApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
tools:replace="android:theme,android:name">
<activity
android:name="com.jaak.visagesdk.MainActivity"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.jaak.visagesdk"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
3.2 file _ paths.xml
Create re / xml / file _ paths.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Pictures/" />
<external-path name="my_movies" path="Movies/" />
<external-path name="my_files" path="Android/data/com.jaak.visagesdk/files/Jaak Visage SDK/" />
</paths>
Track 4: Record and Videos Management
Objective
Implement complete management of video prints and advanced processing.
4.1 Advanced implementation with configuration
class AdvancedVisageActivity : AppCompatActivity(), VisageListener {
private lateinit var binding: ActivityAdvancedBinding
private lateinit var visageSDK: VisageSDK
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAdvancedBinding.inflate(layoutInflater)
setContentView(binding.root)
setupAdvancedConfiguration()
}
private fun setupAdvancedConfiguration() {
visageSDK = VisageSDK(this, this)
// Camera Setup
setupCameraSpinner()
// Configure Main Button
binding.btnLaunchVisage.setOnClickListener {
if (validateAndApplyConfiguration()) {
visageSDK.startVisage()
}
}
// Default values
loadDefaultValues()
}
private fun setupCameraSpinner() {
val cameraOptions = arrayOf("Border Chamber", "Rear Camera")
val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, cameraOptions)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
binding.spinnerCameraFacing.adapter = adapter
}
private fun loadDefaultValues() {
binding.spinnerCameraFacing.setSelection(0) // Default border
binding.cbShowConfigPanel.isChecked = false
binding.cbShowDebugMode.isChecked = false
}
private fun validateAndApplyConfiguration(): Boolean {
try {
// Configure Camera
val cameraFacing = if (binding.spinnerCameraFacing.selectedItemPosition == 0)
CameraFacing.FRONT else CameraFacing.BACK
// Apply to SDK
visageSDK.setCameraFacing(cameraFacing)
visageSDK.setConfigPanel(binding.cbShowConfigPanel.isChecked)
visageSDK.setDebugMode(binding.cbShowDebugMode.isChecked)
return true
} catch (e: Exception) {
Toast.makeText(this, "Configure error: ${e.message}", Toast.LENGTH_SHORT).show()
return false
}
}
override fun onSuccessVisage(typeProcess: Int, uri: Uri?) {
try {
Log.d("AdvancedVisage", "Procesamiento exitoso - Tipo: $typeProcess")
uri?.let { videoUri ->
// Optimized conversion to Base64 for camera videos
val base64Video = Utils.videoCameraUriToBase64(videoUri)
if (!base64Video.isNullOrEmpty()) {
Log.d("AdvancedVisage", "Video convertido: ${base64Video.length} caracteres")
// Processing video as required
processCompleteVideo(base64Video, videoUri)
Toast.makeText(this, "Facial video successfully processed", Toast.LENGTH_LONG).show()
} else {
Log.e("AdvancedVisage", "Error: Can't convert video to Base64")
Toast.makeText(this, "Failed to process video", Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
Log.e("AdvancedVisage", "Error processing result: ${.message}")
Toast.makeText(this, "Unexpected error: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
private fun processCompleteVideo(base64Video: String, originalUri: Uri) {
// Prepare complete data for KYC
val kycData = mapOf(
"facialVideo" to base64Video,
"timestamp" to System.currentTimeMillis(),
"source" to "visage_sdk_android_v1",
"deviceInfo" to getDeviceInfo(),
"videoUri" to originalUri.toString(),
"sessionId" to generateSessionId()
)
// Send to backend for biometric analysis
sendToKYCBackend(kycData)
Log.d("AdvancedVisage", "Processed video for KYC completely")
}
private fun getDeviceInfo(): Map<String, String> {
return mapOf(
"model" to android.os.Build.MODEL,
"manufacturer" to android.os.Build.MANUFACTURER,
"sdkVersion" to android.os.Build.VERSION.SDK_INT.toString(),
"appVersion" to packageManager.getPackageInfo(packageName, 0).versionName
)
}
private fun generateSessionId(): String {
return "visage_${System.currentTimeMillis()}_${(1000..9999).random()}"
}
override fun onErrorVisage(text: String) {
Log.e("AdvancedVisage", "Error: $text")
// Qualify errors for best management
when {
text.contains("permission", ignoreCase = true) -> handlePermissionError(text)
text.contains("camera", ignoreCase = true) -> handleCameraError(text)
text.contains("cancelled", ignoreCase = true) -> handleUserCancellation(text)
else -> handleGenericError(text)
}
}
private fun handlePermissionError(text: String) {
Toast.makeText(this, "Camera permits required for face detection", Toast.LENGTH_LONG).show()
}
private fun handleCameraError(text: String) {
Toast.makeText(this, "Camera error. Check that it isn't being used", Toast.LENGTH_LONG).show()
}
private fun handleUserCancellation(text: String) {
Toast.makeText(this, "User's cancelled process", Toast.LENGTH_SHORT).show()
}
private fun handleGenericError(text: String) {
Toast.makeText(this, "Error: $text", Toast.LENGTH_LONG).show()
}
}
4.2 Usefulness of Video Analysis
class VideoAnalyzer {
companion object {
fun analyzeVideoQuality(base64Video: String): VideoQualityReport {
return VideoQualityReport(
sizeInBytes = base64Video.length * 3 / 4, // Size approach
base64Length = base64Video.length,
estimatedDurationSeconds = estimateDuration(base64Video),
qualityScore = calculateQualityScore(base64Video)
)
}
private fun estimateDuration(base64Video: String): Float {
// Estimate (very rough)
val sizeInMB = (base64Video.length * 3 / 4) / (1024 * 1024)
return sizeInMB * 2 // Approximately 2 seconds per MB
}
private fun calculateQualityScore(base64Video: String): Float {
// Simple score based on video size
val sizeInMB = (base64Video.length * 3 / 4) / (1024 * 1024)
return when {
sizeInMB > 5 -> 0.9f
sizeInMB > 2 -> 0.7f
sizeInMB > 1 -> 0.5f
else -> 0.3f
}
}
}
}
data class VideoQualityReport(
val sizeInBytes: Int,
val base64Length: Int,
val estimatedDurationSeconds: Float,
val qualityScore: Float
)
Track 5: Test Facial Detection
Objective
Check that all functionalities of SDK They work properly.
checklist
| Element | State | Description |
|---|---|---|
| Camera permits | ☐ | App automatically requests and gets permission |
| Facial detection | ☐ | AI detects faces in real time |
| Automatic registration | ☐ | Reforms with proper face detection |
| Base64 conversion | ☐ | Videos become right |
| Errors management | ☐ | Mistakes are handled correctly |
Test process
Step A: Install and Configure
- Unit at Android Studio
- Install onto physical device (non-emulator)
- Check permits are requested automatically
Step B: Test Basic Detection
- Open Application and press "Start Facial Detection"
- Position face front to front camera
- To expect automatic detection (green corners)
- Check Auto Start Retirement
- Review login to confirm processing
Step C: Test Different Conditions
- Change light (light, artificial)
- Test distances (close, far from device)
- Check debug mode (FPS, memory, detection)
- Confirm videos are saved correctly
Problem solving
Common problems
| Problem | Resolution |
|---|---|
| "SDK does not initialise " | Check Application class and dependencies |
| "Camera doesn't start." | Check permissions and physical device |
| "No face detectors." | Enhance light and use front camera |
| "Record Failed" | Check storage space |
Advanced Debug
private fun enableAdvancedDebugging() {
visageSDK.setDebugMode(true) // Muestra: FPS | MEM | FACE | CAM
visageSDK.setConfigPanel(true) // Status Panel Sample
Log.d("Visage", "= = = DIRECT INFORMATION = = =")
Log.d("Visage", "Modelo: ${Build.MODEL}")
Log.d("Visage", "Manufacturer: ${Build.MANUFACTURER}")
Log.d("Visage", "SDK: ${Build.VERSION.SDK_INT}")
Log.d("Visage", "RAM disponible: ${getAvailableMemory()}")
}
private fun getAvailableMemory(): String {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val memoryInfo = ActivityManager.MemoryInfo()
activityManager.getMemoryInfo(memoryInfo)
return "${memoryInfo.availMem / (1024 * 1024)} MB"
}
Full reference
Methods SDK
| Method | Description | Example |
|---|---|---|
| VisageSDK (context, list) | Building SDK | VisageSDK(this, this) |
| startVisage () | Begins facial detection and recording | visageSDK.startVisage() |
| SetCameraFacing (facing) | Configure front / back camera | visageSDK.setCameraFacing(CameraFacing.FRONT) |
| SetDebug | Real-time metric activity | visageSDK.setDebugMode(true) |
| SetConFigPanel (toolean) | Configure Panel Sample | visageSDK.setConfigPanel(true) |
Available
| Configure | Description | When to use |
|---|---|---|
| CameraFacing.FRONT | Front camera | Recommended for faces |
| CameraFacing.BACK | Rear | Special cases |
| SetDebug | Real-time technologies | During development |
| SetConFigPanel (true) | Visibility Panel | To debugging |
Response structure
| Response | Description | When it's generated |
|---|---|---|
| onSuccess Visage (typeProcess, uri) | Successful video engrave | typeProcess = 2, uri video |
| onErrors | Test error | Any bug in detection / recording |
Advanced Problem Resolution
Problem: "MML Kit model error"
// Check compatibility with ML Kit
private fun checkMLKitCompatibility() {
try {
// ML Kit starts automatically
Log.d("Visage", "ML Kit available for face detection")
} catch (e: Exception) {
Log.e("Visage", "ML error Kit: ${e.message}")
showError("Unsupported with face detection")
}
}
Problem: "Videos aren't processed"
// Check video conversion
private fun debugVideoConversion(uri: Uri) {
try {
val base64Video = Utils.videoCameraUriToBase64(uri)
if (base64Video.isNullOrEmpty()) {
Log.e("Visage", "Error: Conversion to Base64 failed")
Log.e("Visage", "URI: $uri")
// Check if the file exists
contentResolver.query(uri, null, null, null, null)?.use { cursor ->
Log.d("Visage", "Archivo existe: ${cursor.count > 0}")
}
} else {
Log.d("Visage", "Successful conversion: ${base64Vide.length} characters")
}
} catch (e: Exception) {
Log.e("Visage", "Failed processing video: ${.message}")
}
}
Do you need some help?
Support information
- Problem description: What kind of detection are you trying to figure out?
- Android Studio Logs: Screenshots of errors in Lochcat
- Unit information: Model, Android version, RAM
- Configure SDK: Parameters used
- Test conditions: Lighting, distance, direction
Support Contact
Email: support Always include: Android logs, built-up configuration, version SDK
You have successfully implemented JAAKVisage SDK Your app can now detect faces and record videos automatically using artificial intelligence, generating optimized files for biometric and KYC.