androidxamarinmobilefingerprintjava-runtime-compiler

How to create handler inside thread that has not called Looper.prepare() in xamarin mobile app


I have a mobile application which has Finger Print Authentication and it uses xamarin framework. Until now everything worked well with all devices except Samsung Note 8. While trying to debug this device it gives me an exception Java.Lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(). I have no idea what does it mean and how to fix it because it works well with other devices. It gives exception on row keyGen.Init(keyGenSpec)

    static readonly string KEY_NAME = "YYYYYYY";

    static readonly string KEYSTORE_NAME = "AndroidKeyStore";

    static readonly string KEY_ALGORITHM = KeyProperties.KeyAlgorithmAes;
    static readonly string BLOCK_MODE = KeyProperties.BlockModeCbc;
    static readonly string ENCRYPTION_PADDING = KeyProperties.EncryptionPaddingPkcs7;

    static readonly string TRANSFORMATION = KEY_ALGORITHM + "/" +
                                            BLOCK_MODE + "/" +
                                            ENCRYPTION_PADDING;

    readonly KeyStore _keystore;

    public CryptoObjectHelper()
    {
        _keystore = KeyStore.GetInstance(KEYSTORE_NAME);
        _keystore.Load(null);
    }

    public FingerprintManagerCompat.CryptoObject BuildCryptoObject()
    {
        Cipher cipher = CreateCipher();
        return new FingerprintManagerCompat.CryptoObject(cipher);
    }

    Cipher CreateCipher(bool retry = true)
    {
        IKey key = GetKey();
        Cipher cipher = Cipher.GetInstance(TRANSFORMATION);
        try
        {
            cipher.Init(CipherMode.EncryptMode, key);
        }
        catch (KeyPermanentlyInvalidatedException e)
        {
            _keystore.DeleteEntry(KEY_NAME);
            if (retry)
            {
                CreateCipher(false);
            }
            else
            {
                throw new Exception("Could not create the cipher for fingerprint authentication.", e);
            }
        }
        return cipher;
    }

    IKey GetKey()
    {
        if (!_keystore.IsKeyEntry(KEY_NAME))
        {
            CreateKey();
        }

        IKey secretKey = _keystore.GetKey(KEY_NAME, null);
        return secretKey;
    }

    void CreateKey()
    {

            KeyGenerator keyGen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KEYSTORE_NAME);
            KeyGenParameterSpec keyGenSpec =
                new KeyGenParameterSpec.Builder(KEY_NAME, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
                    .SetBlockModes(BLOCK_MODE)
                    .SetEncryptionPaddings(ENCRYPTION_PADDING)
                    .SetUserAuthenticationRequired(true)
                    .Build();
            keyGen.Init(keyGenSpec);
            keyGen.GenerateKey();


    }

Solution

  • Without seing more code it is hard to tell what is going on. It appears your code is executed on a background thread. You might try adding android.os.Looper.Prepare() as the first line inside CreateKey(). Hope it works.