Search code examples
androidlockscreensecurityexceptionandroid-fingerprint-api

SecurityException while checking if fingerprints are enrolled in Samsung Phones


I am using a lockscreen with fingerprint in my app. While it works seamlessly with other phones having fingerprint sensor, samsung users are facing some SecurityException as I can see in my google console reports.Here is the report:

java.lang.RuntimeException: 

at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3319)

at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3415)

at android.app.ActivityThread.access$1100 (ActivityThread.java:229)

at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1821)

at android.os.Handler.dispatchMessage (Handler.java:102)

at android.os.Looper.loop (Looper.java:148)

 at android.app.ActivityThread.main (ActivityThread.java:7406)

at java.lang.reflect.Method.invoke (Native Method)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1230)

at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1120)

Caused by: java.lang.SecurityException: 

at android.os.Parcel.readException (Parcel.java:1621)

at android.os.Parcel.readException (Parcel.java:1574)

at android.hardware.fingerprint.IFingerprintService$Stub$Proxy.hasEnrolledFingerprints (IFingerprintService.java:503)

at android.hardware.fingerprint.FingerprintManager.hasEnrolledFingerprints (FingerprintManager.java:776)

at com.example.ark.access.LockScreen.setUpFingerPrint (LockScreen.java:252)

at com.example.ark.access.LockScreen.onCreate (LockScreen.java:67)

at android.app.Activity.performCreate (Activity.java:6904)

at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1136)

at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3266)

Here is the portion of my file which checks for fingerprints:

    private void setUpFingerPrint(ImageView white,ImageView black)
{
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        //Get an instance of KeyguardManager and FingerprintManager//
        KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
        FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);


        //Check whether the device has a fingerprint sensor//
        if (!fingerprintManager.isHardwareDetected()) {
            // If a fingerprint sensor isn’t available, then inform the user that they’ll be unable to use your app’s fingerprint functionality//
            //Toast.makeText(this, R.string.noFingerPrint, Toast.LENGTH_SHORT).show();
            white.setVisibility(View.GONE);
            black.setVisibility(View.GONE);
        }
        //Check whether the user has granted your app the USE_FINGERPRINT permission//
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
            // If your app doesn't have this permission, then display the following text//
            Toast.makeText(this, R.string.noFingerPrintPermission, Toast.LENGTH_SHORT).show();
        }

        //Check that the user has registered at least one fingerprint//
        if (!fingerprintManager.hasEnrolledFingerprints()) {
            // If the user hasn’t configured any fingerprints, then display the following message//
            Toast.makeText(this, R.string.noFingerPrintRegistered, Toast.LENGTH_SHORT).show();
        }

        //Check that the lockscreen is secured//
        if (!keyguardManager.isKeyguardSecure()) {
            // If the user hasn’t secured their lockscreen with a PIN password or pattern, then display the following text//
            Toast.makeText(this, R.string.lockScreenNotConfigured, Toast.LENGTH_SHORT).show();
        }
        else {
            try {
                generateKey();
            } catch (FingerprintException e) {
                e.printStackTrace();
            }

            if (initCipher()) {
                //If the cipher is initialized successfully, then create a CryptoObject instance//
                FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);

                // Here, I’m referencing the FingerprintHandler class that we’ll create in the next section. This class will be responsible
                // for starting the authentication process (via the startAuth method) and processing the authentication process events//
                int k = getIntent().getIntExtra("Mode", 0);
                FingerprintHandler helper = new FingerprintHandler(this,k,white,black);
                helper.startAuth(fingerprintManager, cryptoObject);
            }
        }
    }
    else
    {
        white.setVisibility(View.GONE);
        black.setVisibility(View.GONE);
    }
}

Line 252 is the one having the check fingerprintmanager.hasEnrolledFingerprints()

I am having a hard time figuring it out as I have no samsung phones to test. Till now it has happened in Galaxy J7 and Grand Prime Plus.


Solution

  • The solution that worked for me is this :

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //Get an instance of KeyguardManager and FingerprintManager//
            KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE);
            FingerprintManager fingerprintManager = (FingerprintManager)context.getSystemService(FINGERPRINT_SERVICE);
    
    
            //Check whether the device has a fingerprint sensor//
            if (!fingerprintManager.isHardwareDetected()) {
                // If a fingerprint sensor isn’t available, then inform the user that they’ll be unable to use your app’s fingerprint functionality//
                //Toast.makeText(this, R.string.noFingerPrint, Toast.LENGTH_SHORT).show();
                listener.noFingerPrintHardware();
            } else {
                //Check whether the user has granted your app the USE_FINGERPRINT permission//
                if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
                    listener.fingerPrintPermissionError();
                } else {
                    //Check that the user has registered at least one fingerprint//
                    if (!fingerprintManager.hasEnrolledFingerprints()) {
                        listener.noEnrolledFingerprints();
                    } else {
    
                        //Check that the lockscreen is secured//
                        if (!keyguardManager.isKeyguardSecure()) {
                            listener.keygaurdNotSecure();
                        } else {
                            try {
                                generateKey();
                            } catch (FingerprintException e) {
                                e.printStackTrace();
                            }
    
                            if (initCipher(listener)) {
                                //If the cipher is initialized successfully, then create a CryptoObject instance//
                                FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
    
                                // Here, I’m referencing the FingerprintHandler class that we’ll create in the next section. This class will be responsible
                                // for starting the authentication process (via the startAuth method) and processing the authentication process events//
                                FingerprintHandler helper = new FingerprintHandler(context,listener);
                                helper.startAuth(fingerprintManager, cryptoObject);
                            }
                        }
                    }
                }
            }
        }
        else
        {
            listener.noFingerPrintHardware();
        }
    

    I put the checks in a nested-if format, where the fingerprint authentication starts only when all the checks are satisfied. There have been no such crashes since.