Build a Fingerprint Lock Screen App for Android

Creating a Fingerprint Lock Screen App in Android starts with a clear boundary: Android verifies the enrolled biometric, and your app opens only protected content. This guide builds a small Kotlin app with AndroidX BiometricPrompt, secure fallback options, and careful failure handling.

Android keeps fingerprint templates in protected system services and secure hardware where available. Your app receives neither an image nor a reusable template. It receives a short-lived authentication result that can release an encryption key or reveal a private screen.

A dependable lock screen must work when a sensor is unavailable, a finger is wet, repeated attempts trigger lockout, or the user prefers a PIN. It must also fail closed: unsuccessful authentication must never expose the content it protects.

The sample uses one activity, AndroidX libraries, and platform cryptography. By the end, it will support enrolled fingerprints, a device-credential fallback, lifecycle-safe prompts, and testing guidance suited to Android phones commonly used across Australia.

Prepare the Android project

Create an Empty Views Activity in Android Studio, select Kotlin, and use AppCompatActivity because AndroidX BiometricPrompt requires a FragmentActivity. Set a minimum SDK of 23, target the current platform SDK, and add current stable AndroidX Core, Activity, AppCompat, and Biometric dependencies through your Gradle version catalog.

Declare biometric permission and mark the fingerprint hardware as optional so people without a sensor can still install the app and use their device PIN or pattern. Biometric permission is normal and does not need a separate runtime dialog; consent is collected through the system authentication prompt.

<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />

<uses-feature
    android:name="android.hardware.fingerprint"
    android:required="false" />

Check authentication capabilities

Before showing an unlock button, ask BiometricManager whether strong authentication is available. Treat success as a capability check rather than proof that the current user has enrolled a fingerprint, because enrolment can change while the app remains installed.

val biometricManager = BiometricManager.from(this)

val biometricReady = biometricManager.canAuthenticate(
    BiometricManager.Authenticators.BIOMETRIC_STRONG
) == BiometricManager.BIOMETRIC_SUCCESS

Keep the credential fallback as a separate decision. Android 11 and newer can combine strong biometrics with device credentials in one prompt, while earlier releases have different platform behaviour and require a separate system confirmation screen.

val credentialReady = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    biometricManager.canAuthenticate(
        BiometricManager.Authenticators.DEVICE_CREDENTIAL
    ) == BiometricManager.BIOMETRIC_SUCCESS
} else {
    getSystemService(KeyguardManager::class.java).isDeviceSecure
}

Implement the fingerprint prompt

Build one BiometricPrompt when the activity is created and reuse it. Give the prompt a clear title and subtitle. Newer Android versions can show the device-credential option directly, while older versions need a negative button connected to the system credential screen.

private val prompt by lazy {
    BiometricPrompt(
        this,
        ContextCompat.getMainExecutor(this),
        object : BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationSucceeded(
                result: BiometricPrompt.AuthenticationResult
            ) {
                unlockProtectedContent()
            }

            override fun onAuthenticationFailed() {
                status.text = "Fingerprint not recognised. Try again."
            }

            override fun onAuthenticationError(
                errorCode: Int,
                errString: CharSequence
            ) {
                status.text = errString.toString()
            }
        }
    )
}

private fun showPrompt() {
    val builder = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Unlock protected content")
        .setSubtitle("Use your fingerprint to continue")

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        builder.setAllowedAuthenticators(
            BiometricManager.Authenticators.BIOMETRIC_STRONG or
                BiometricManager.Authenticators.DEVICE_CREDENTIAL
        )
    } else {
        builder.setAllowedAuthenticators(
            BiometricManager.Authenticators.BIOMETRIC_STRONG
        )
        builder.setNegativeButtonText("Use device PIN")
    }

    prompt.authenticate(builder.build())
}

Treat onAuthenticationFailed as a rejected sample and leave the system prompt open. Treat onAuthenticationError as terminal, routing ERROR_NEGATIVE_BUTTON on older Android to KeyguardManager.createConfirmDeviceCredentialIntent(). Only onAuthenticationSucceeded should reveal or decrypt private content.

Protect data after authentication

BiometricPrompt establishes that the user passed the system check; it does not independently protect a database row or file. For sensitive information, generate an AES-GCM key in Android Keystore, require user authentication for that key, and decrypt only after authentication succeeds. Keep plaintext in memory briefly and clear it when the protected screen leaves the foreground.

On Android 11 and newer, configure a short authentication window with setUserAuthenticationParameters and decide whether device credentials count. Changes to biometric enrolment can invalidate an authentication-bound key. That provides useful protection, but the app must display a recoverable message instead of failing silently.

For a simple interface gate, add FLAG_SECURE to block screenshots and recent-app previews of private screens, and remove sensitive views in onStop. Never collect or upload fingerprint images, save sensor identifiers, or log whether a particular finger was recognised.

Handle failures and device differences

Map hardware errors such as ERROR_HW_UNAVAILABLE or ERROR_HW_NOT_PRESENT to a clear message and the credential path. ERROR_NO_BIOMETRICS means the user must enrol a biometric through system settings. These states should lead somewhere useful rather than starting repeated prompt loops.

A temporary lockout should advise the user to wait or use the device credential, while a permanent lockout requires re-enrolment or a secure-screen change. User cancellation and negative-button selection are normal exits, so close the protected view without presenting them as suspicious activity.

Check that the device has a secure screen lock before offering fallback authentication. If no PIN, password, or pattern exists, direct the user to the appropriate system security settings. This stops the app from becoming a weaker entry point on an otherwise unsecured device.

Test the complete lock screen flow

Test with physical handsets from several manufacturers as well as an emulator. Enrol a fingerprint, reject it repeatedly, cancel the prompt, remove the enrolment, lock the device, and repeat the test after an app update. An emulator with a fingerprint-capable image can be exercised with adb emu finger touch 1.

Exercise backgrounding, rotation, screen locking, process death, and cancellation while the protected screen is open. Confirm that the app returns to a locked state and never restores plaintext after the authentication window expires. Also test a handset with no fingerprint sensor and a device whose PIN has been removed.

External pages must stay outside the trust boundary. A casino promotion guide can open in a normal browser, but it must not receive decrypted files, share the authenticated activity, or appear in a WebView that can cover the lock screen.

Design for Australian use

A commuter stepping onto a Sydney train or Melbourne tram often has one hand free and little time. Keep the unlock action prominent, support portrait screens and large text, and choose short prompts that remain understandable in bright sunlight.

For many Australian businesses, the Privacy Act 1988 and Australian Privacy Principles provide a clear privacy baseline: explain the purpose, avoid unnecessary collection, secure records, and support deletion. Exact duties depend on the organisation and its data. BiometricPrompt does not expose the fingerprint, yet authentication records and protected files may still be personal information.

Android has a broad Australian user base, and Google Play is a major distribution channel. Test across Samsung, Google, and Motorola hardware because their sensor implementations and system prompts can differ. When charging for the app, display prices in Australian dollars with GST shown clearly and provide support during Australian business hours.

Regional and rural users may move between patchy mobile coverage and reliable connections, so authentication and local key operations must work offline. The same flow can protect mobile banking or payment screens, but it should never copy banking credentials or weaken the app’s encrypted storage.


Start building now: create the activity, connect BiometricPrompt to one encrypted record, and exercise the success, cancellation, lockout, no-enrolment, and PIN paths before adding more screens. Publish through a staged Google Play rollout with a privacy policy that states exactly what the app protects and how users recover access.

Create a test account on a supported handset, enrol a fingerprint, and verify the protected area after every lifecycle change. Keep fingerprint data on Android’s side of the security boundary and let the application handle only the authenticated result.