Start using packagecloud in minutes

Join thousands of developers using packagecloud to distribute software securely, consistently, and affordably.

README

last updated: Fri 09/13/24 at 06:32:55 PM by lucas-yupistudios

BioPass ID Face Liveness SDK Android

Latest Version

September 13, 2024 - [v1.0.5]

Table of Contents

Quick Start Guide

First, you will need a license key to use the SDK. To get your license key contact us through our website BioPass ID.

Check out our official documentation for more in depth information on BioPass ID.

1. Prerequisites:

- Java 17 or higher
- Kotlin 1.9.0 or highr
- Gradle 8.6 or higher
- Android Gradle Plugin 8.4.0 or higher
- A device with a camera
- License key
- Internet connection is required to verify the license

Before proceeding, you should add the following dependencies in your app/build.gradle file:

dependencies 
    implementation 'com.google.mediapipe:tasks-vision:0.10.13'
    implementation 'com.google.mlkit:face-detection:16.1.6'
    implementation 'androidx.camera:camera-core:1.3.4'
    implementation 'androidx.camera:camera-camera2:1.3.4'
    implementation 'androidx.camera:camera-lifecycle:1.3.4'
    implementation 'androidx.camera:camera-view:1.3.4'

Change the minimum Android sdk version to 24 (or higher) in your app/build.gradle file.

minSdkVersion 24

2. Installation

With Gradle

The simplest and easiest way to install the plugin to your project, is to just add the following dependencies to your build.gradle:

dependencies 
    implementation 'com.biopassid:facelivenesssdk:1.0.5' // latest version

Then on your settings.gradle file:

repositories 
    maven 
        url "https://packagecloud.io/biopassid/FaceLivenessSDKAndroid/maven2"


With Local File

Another alternative to use Face Liveness SDK is to download and install the AAR file locally. Here you can find the latest releases and after downloading place the .aar file in any folder of your choice.

We will use Android Studio for the following steps:

  1. First, with your project open, go to File --> Project Structure --> Dependencies.
  2. Then in the Dependencies tab, select your app in the modules tab and click on the plus symbol to show the option to add a JAR/AAR dependency.
  3. On step 1 input the AAR file path, and select the implementation option on step 2.
  4. Just rebuild your project and should be ready to use.

3. How to use

Basic Example

By now you should have all the tools available to start using the plugin in your own project. Here is a code example showing how to launch Intent and use Face Liveness SDK. Through FaceLivenessConfig, you can configure custom settings (such as colors and features).

activity_main

In your xml layout of your main activity:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnCapture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Capture Face"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity

In your main activity:

package com.example.facelivenessdemo

import android.graphics.Bitmap
import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import br.com.biopassid.facelivenesssdk.FaceLiveness
import br.com.biopassid.facelivenesssdk.FaceLivenessCallback
import br.com.biopassid.facelivenesssdk.LivenessFaceAttributes
import br.com.biopassid.facelivenesssdk.config.FaceLivenessConfig

class MainActivity : AppCompatActivity() 

    private lateinit var btnCapture: Button

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Button in your xml layout responsible for calling the Face Liveness SDK
        btnCapture = findViewById(R.id.btnCapture)

        // Instantiate FaceLivenessConfig with your preferred settings
        val config = FaceLivenessConfig(licenseKey = "your-license-key")

        // Define a FaceLivenessCallback to receive the image bitmap and detection result
        val callback = object: FaceLivenessCallback 
            override fun onFaceCapture(
                image: Bitmap,
                faceAttributes: LivenessFaceAttributes?
            ) 
                Log.d(TAG, "onFaceCapture: $image")
                Log.d(TAG, "onFaceCapture: $faceAttributes")


            override fun onFaceDetected(faceAttributes: LivenessFaceAttributes) 
                Log.d(TAG, "onFaceDetected: $faceAttributes")



        // Start Face Liveness capture
        btnCapture.setOnClickListener 
            FaceLiveness.takeFace(this, config, callback, false)



    companion object 
        private const val TAG = "FaceLivenessDemo"


Example using Retrofit to call the BioPass ID API

For this example we used the Liveness from the Multibiometrics plan.

First, add the Retrofit package. To install the Retrofit package, add it to the dependencies section of the app/build.gradle file.

dependencies 
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'

Additionally, in your AndroidManifest.xml file, add the Internet permission.

<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />

LivenessRequest

Create the LivenessRequest data class:

package com.example.facelivenessdemo

import com.google.gson.annotations.SerializedName

data class LivenessRequest(
    @SerializedName("Spoof") val spoof: ImageData
)

data class ImageData(
    @SerializedName("Image") val image: String
)

LivenessResponse

Create the LivenessResponse data class:

package com.example.facelivenessdemo

import com.google.gson.annotations.SerializedName

data class LivenessResponse(
    @SerializedName("Success") val success: Boolean?,
    @SerializedName("result") val result: String?,
    @SerializedName("spoof") val spoof: Boolean?
)

BioPassIDApi

Here, you will need an API key to be able to make requests to the BioPass ID API. To get your API key contact us through our website BioPass ID.

Create the BioPassIDApi interface to make requests to the BioPass ID API:

package com.example.facelivenessdemo

import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST

interface BioPassIDApi 
    @Headers("Content-Type: application/json", "Ocp-Apim-Subscription-Key: your-api-key")
    @POST("multibiometrics/v2/liveness")
    fun enrollPerson(@Body livenessRequest: LivenessRequest) : Call<LivenessResponse>

Network

Create the Network class to make requests to the BioPass ID API:

package com.example.facelivenessdemo

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class Network 
    companion object 

        /** Returns a Client Retrofit Instance for Requests
         */
        fun getRetrofitInstance() : BioPassIDApi 
            return Retrofit.Builder()
                .baseUrl("https://api.biopassid.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(BioPassIDApi::class.java)



activity_main

In your xml layout of your main activity:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnCapture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Capture Face"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity

In your main activity:

package com.example.facelivenessdemo

import android.graphics.Bitmap
import android.os.Bundle
import android.util.Base64
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import br.com.biopassid.facelivenesssdk.FaceLiveness
import br.com.biopassid.facelivenesssdk.FaceLivenessCallback
import br.com.biopassid.facelivenesssdk.LivenessFaceAttributes
import br.com.biopassid.facelivenesssdk.config.FaceLivenessConfig
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.ByteArrayOutputStream

class MainActivity : AppCompatActivity() 

    private lateinit var btnCapture: Button

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Button in your xml layout responsible for calling the Face Liveness SDK
        btnCapture = findViewById(R.id.btnCapture)

        // Instantiate FaceLivenessConfig with your preferred settings
        val config = FaceLivenessConfig(licenseKey = "your-license-key")

        // Define a FaceLivenessCallback to receive the image bitmap and detection result
        val callback = object: FaceLivenessCallback 
            override fun onFaceCapture(
                image: Bitmap,
                faceAttributes: LivenessFaceAttributes?
            ) 
                // Encode Bitmap to base64 string
                val imageData = bitmapToBas64(image)

                // Instantiate Liveness request
                val livenessRequest = LivenessRequest(ImageData(imageData))

                // Get retrofit
                val retrofit = Network.getRetrofitInstance()

                // Execute request to the BioPass ID API
                val callback = retrofit.enrollPerson(livenessRequest)

                // Handle API response
                callback.enqueue(object : Callback<LivenessResponse> 
                    override fun onFailure(call: Call<LivenessResponse>, t: Throwable) 
                        Log.e(TAG, "Error trying to call liveness. $t.message")


                    override fun onResponse(
                        call: Call<LivenessResponse>,
                        response: Response<LivenessResponse>
                    ) 
                        Log.d(TAG, "LivenessResponse: $response.body()")

                )


            override fun onFaceDetected(faceAttributes: LivenessFaceAttributes) 
                Log.d(TAG, "onFaceDetected: $faceAttributes")



        // Start Face Liveness capture
        btnCapture.setOnClickListener 
            FaceLiveness.takeFace(this, config, callback, false)



    // Method to assist converting Bitmap to Base64 string
    private fun bitmapToBas64(bitmap: Bitmap): String 
        val stream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
        val byteArray = stream.toByteArray()
        stream.close()
        return Base64.encodeToString(byteArray, Base64.NO_WRAP)


    companion object 
        private const val TAG = "FaceLivenessDemo"


4. LicenseKey

First, you will need a license key to use the SDK. To get your license key contact us through our website BioPass ID.

To use Face Liveness SDK you need a license key. To set the license key needed is simple as setting another attribute. Simply doing:

val config = FaceLivenessConfig()
config.licenseKey = "your-license-key"

5. FaceLivenessCallback

You can set a custom callback to receive the captured image and the face detection result. You can write you own callback following this example:

val callback = object : FaceLivenessCallback 
    override fun onFaceCapture(image: Bitmap, faceAttributes: LivenessFaceAttributes?) 
        Log.d(TAG, "onFaceCapture: $image")
        Log.d(TAG, "onFaceCapture: $faceAttributes")


    override fun onFaceDetected(faceAttributes: LivenessFaceAttributes) 
        Log.d(TAG, "onFaceDetected: $faceAttributes")


LivenessFaceAttributes

| Name                    | Type  | Description                                                                                                                                                                                                           |
| ----------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| faceProp                | Float | Proportion of the area occupied by the face in the image, in percentage                                                                                                                                               |
| faceWidth               | Int   | Face width, in pixels                                                                                                                                                                                                 |
| faceHeight              | Int   | Face height, in pixels                                                                                                                                                                                                |
| ied                     | Int   | Distance between left eye and right eye, in pixels                                                                                                                                                                    |
| bbox                    | Rect  | Face bounding box                                                                                                                                                                                                     |
| rollAngle               | Float | The Euler angle X of the head. Indicates the rotation of the face about the axis pointing out of the image. Positive z euler angle is a counter-clockwise rotation within the image plane                             |
| pitchAngle              | Float | The Euler angle X of the head. Indicates the rotation of the face about the horizontal axis of the image. Positive x euler angle is when the face is turned upward in the image that is being processed               |
| yawAngle                | Float | The Euler angle Y of the head. Indicates the rotation of the face about the vertical axis of the image. Positive y euler angle is when the face is turned towards the right side of the image that is being processed |
| leftEyeOpenProbability  | Float | Probability that the face’s left eye is open, in percentage                                                                                                                                                           |
| rightEyeOpenProbability | Float | Probability that the face’s right eye is open, in percentage                                                                                                                                                          |
| smilingProbability      | Float | Probability that the face is smiling, in percentage                                                                                                                                                                   |
| averageLightIntensity   | Float | The average intensity of the pixels in the image                                                                                                                                                                      |

FaceLivenessConfig

You can also use pre-build configurations on your application, so you can automatically start using multiples features that better suit your application. You can instantiate each one and use it's default properties, or if you prefer you can change every config available. Here are the types that are supported right now:

FaceLivenessConfig

| Name             | Type                            | Default value                         |
| ---------------- | ------------------------------- | ------------------------------------- |
| licenseKey       | String                          | ""                                    |
| resolutionPreset | FaceLivenessResolutionPreset    | FaceLivenessResolutionPreset.VERYHIGH |
| fontFamily       | Int                             | R.font.facelivenesssdk_opensans_bold  |
| faceDetection    | FaceLivenessDetectionOptions    |                                       |
| mask             | FaceLivenessMaskOptions         |                                       |
| titleText        | FaceLivenessTextOptions         |                                       |
| loadingText      | FaceLivenessTextOptions         |                                       |
| helpText         | FaceLivenessTextOptions         |                                       |
| feedbackText     | FaceLivenessFeedbackTextOptions |                                       |
| backButton       | FaceLivenessButtonOptions       |                                       |

FaceLivenessDetectionOptions

| Name                     | Type  | Default value | Description                                                                                                                                                                                                           |
| ------------------------ | ----- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| timeToCapture            | Long  | 3000          | Time it takes to perform an automatic capture, in miliseconds                                                                                                                                                         |
| maxFaceDetectionTime     | Long  | 60000         | Maximum facial detection attempt time, in miliseconds                                                                                                                                                                 |
| minFaceProp              | Float | 0.1f          | Minimum limit of the proportion of the area occupied by the face in the image, in percentage                                                                                                                          |
| maxFaceProp              | Float | 0.4f          | Maximum limit on the proportion of the area occupied by the face in the image, in percentage                                                                                                                          |
| minFaceWidth             | Int   | 150           | Minimum face width, in pixels                                                                                                                                                                                         |
| minFaceHeight            | Int   | 150           | Minimum face height, in pixels                                                                                                                                                                                        |
| ied                      | Int   | 90            | Minimum distance between left eye and right eye, in pixels                                                                                                                                                            |
| bboxPad                  | Int   | 20            | Padding the face's bounding box to the edges of the image, in pixels                                                                                                                                                  |
| faceDetectionThresh      | Float | 0.5f          | Minimum trust score for a detection to be considered valid. Must be a number between 0 and 1, which 0.1 would be a lower face detection trust level and 0.9 would be a higher trust level                             |
| rollThresh               | Float | 4.0f          | The Euler angle X of the head. Indicates the rotation of the face about the axis pointing out of the image. Positive z euler angle is a counter-clockwise rotation within the image plane                             |
| pitchThresh              | Float | 4.0f          | The Euler angle X of the head. Indicates the rotation of the face about the horizontal axis of the image. Positive x euler angle is when the face is turned upward in the image that is being processed               |
| yawThresh                | Float | 4.0f          | The Euler angle Y of the head. Indicates the rotation of the face about the vertical axis of the image. Positive y euler angle is when the face is turned towards the right side of the image that is being processed |
| closedEyesThresh         | Float | 0.7f          | Minimum probability threshold that the left eye and right eye of the face are closed, in percentage. A value less than 0.7 indicates that the eyes are likely closed                                                  |
| smilingThresh            | Float | 0.7f          | Minimum threshold for the probability that the face is smiling, in percentage. A value of 0.7 or more indicates that a person is likely to be smiling                                                                 |
| tooDarkThresh            | Int   | 50            | Minimum threshold for the average intensity of the pixels in the image                                                                                                                                                |
| tooLightThresh           | Int   | 170           | Maximum threshold for the average intensity of the pixels in the image                                                                                                                                                |
| faceCentralizationThresh | Float | 0.05f         | Threshold to consider the face centered, in percentage                                                                                                                                                                |

FaceLivenessMaskOptions

| Name              | Type    | Default value                 |
| ----------------- | ------- | ----------------------------- |
| enabled           | Boolean | true                          |
| backgroundColor   | Int     | Color.parseColor("#CC000000") |
| frameColor        | Int     | Color.WHITE                   |
| frameEnabledColor | Int     | Color.parseColor("#16AC81")   |
| frameErrorColor   | Int     | Color.parseColor("#E25353")   |

FaceLivenessFeedbackTextOptions

| Name      | Type                             | Default value                      |
| --------- | -------------------------------- | ---------------------------------- |
| enabled   | Boolean                          | true                               |
| messages  | FaceLivenessFeedbackTextMessages | FaceLivenessFeedbackTextMessages() |
| textColor | Int                              | Color.WHITE                        |
| textSize  | Int                              | 14                                 |

FaceLivenessFeedbackTextMessages

| Name                | Type   | Default value                 |
| ------------------- | ------ | ----------------------------- |
| noDetection         | String | "No faces detected"           |
| multipleFaces       | String | "Multiple faces detected"     |
| faceCentered        | String | "Face centered. Do not move"  |
| tooClose            | String | "Turn your face away"         |
| tooFar              | String | "Bring your face closer"      |
| tooLeft             | String | "Move your face to the right" |
| tooRight            | String | "Move your face to the left"  |
| tooUp               | String | "Move your face down"         |
| tooDown             | String | "Move your face up"           |
| invalidIED          | String | "Invalid inter-eye distance"  |
| faceAngleMisaligned | String | "Misaligned face angle"       |
| closedEyes          | String | "Open your eyes"              |
| smiling             | String | "Do not smile"                |
| tooDark             | String | "Too dark"                    |
| tooLight            | String | "Too light"                   |

FaceLivenessButtonOptions

| Name            | Type                    | Default value |
| --------------- | ----------------------- | ------------- |
| enabled         | Boolean                 | true          |
| backgroundColor | Int                     | Color.WHITE   |
| buttonPadding   | Int                     | 0             |
| buttonSize      | Size                    | Size(56, 56)  |
| iconOptions     | FaceLivenessIconOptions |               |
| labelOptions    | FaceLivenessTextOptions |               |

FaceLivenessIconOptions

| Name      | Type    | Default value                       |
| --------- | ------- | ----------------------------------- |
| enabled   | Boolean | true                                |
| iconFile  | Int     | R.drawable.facelivenesssdk_ic_close |
| iconColor | Int     | Color.parseColor("#323232")         |
| iconSize  | Size    | Size(32, 32)                        |

FaceLivenessTextOptions

| Name      | Type    | Default value               |
| --------- | ------- | --------------------------- |
| enabled   | Boolean | true                        |
| content   | String  | ""                          |
| textColor | Int     | Color.parseColor("#323232") |
| textSize  | Int     | 14                          |

FaceLivenessResolutionPreset (enum)

| Name                                  | Resolution        |
| ------------------------------------- | ----------------- |
| FaceLivenessResolutionPreset.HIGH     | 720p (1280x720)   |
| FaceLivenessResolutionPreset.VERYHIGH | 1080p (1920x1080) |

How to change font family

You can use the default font family or set one of your own. To set a font family, create a font folder under res directory. Download the font which ever you want and paste it inside font folder. All font names must be only: lowercase a-z, 0-9, or underscore. The structure should be some thing like below.

Then, just set the font family passing the reference of the font family file.

val config = FaceLivenessConfig()
config.licenseKey = "your-license-key"
config.fontFamily = R.font.roboto_mono_bold_italic

How to change icon

You can use the default icons or define one of your own. To set a icon, download the icon which ever you want and paste it inside drawable folder. The structure should be some thing like below.

Then, just set the icon passing the reference of the icon file.

val config = FaceLivenessConfig()
config.licenseKey = "your-license-key"
// changing back button icon
config.backButton.iconOptions.iconFile = R.drawable.ic_baseline_photo_camera

Changelog

v1.0.5

  • Documentation update;
  • Connection timeout for license activation removed.

v1.0.4

  • Documentation update;
  • Fixed a bug where the maximum detection time was reset even after the SDK was closed.

v1.0.3

  • Documentation update;
  • Fixed validation of facial angles.

v1.0.2

  • Documentation update;
  • Fix in the drawing of the face's bounding box, which was inverted on the X axis.

v1.0.1

  • Documentation update;
  • Upgrade from Camera2 to CameraX, see prerequisites section;
  • FaceLivenessFaceCaptureResult renamed to LivenessFaceAttributes;
  • New feedback message specific to invalid IED;
  • New faceCentralizationThresh in FaceLivenessDetectionOptions;
  • New debug parameter:
    • If debug=true, the facial detection attributes that result in an invalid face will be printed in the UI;
    • If debug=true, the face rectangle will be drawn in the UI.
  • Bug fixes for face centering;
  • Fixed a bug that caused the onFaceCapture callback to crash on some devices.

v1.0.0

  • Added documentation;
  • Added face detection;
  • Added auto capture.
Quick install instructions for: