Search code examples
androidkotlinandroid-jetpack-composeautofill

Autofill email password in jetpack compose - Android


While we use the XML and Kotlin setup, using edittext with email and password setup automatically shows options to fill the detail in suggestion of the keyboard but the same thing does not occur in the Compose architecture.

Have they provided a way to do it or is it a compose drawback for now?

I know we can build it as XML and put it in the composable but its not a clean way so if there is any proper solution to this, please help


Solution

  • Yes a proper solution did exist as mentioned below.

    Using Google Credential Manager to Save User Credentials

    First you will need the below dependency

    androidx.credentials:credentials:1.2.2

    This is my custom build class to handle the function

    import android.app.Activity
    import androidx.credentials.CreatePasswordRequest
    import androidx.credentials.CredentialManager
    import androidx.credentials.GetCredentialRequest
    import androidx.credentials.GetPasswordOption
    import androidx.credentials.PasswordCredential
    import androidx.credentials.exceptions.CreateCredentialCancellationException
    import androidx.credentials.exceptions.CreateCredentialException
    import androidx.credentials.exceptions.GetCredentialCancellationException
    import androidx.credentials.exceptions.GetCredentialException
    import androidx.credentials.exceptions.NoCredentialException
    
    class AccountManager(val activity: Activity) {
        private val credentialManager = CredentialManager.create(activity)
        suspend fun signUp(username: String, password: String): SignupResult {
            return try {
                credentialManager.createCredential(activity,     CreatePasswordRequest(username, password))
                SignupResult.Success(username)
            } catch (e: CreateCredentialCancellationException) {
                e.printStackTrace()
                SignupResult.Cancelled
            } catch (e: CreateCredentialException) {
                SignupResult.Failure
            } catch (e:Exception){
                SignupResult.Failure
            }
        }
    
        suspend fun signIn():SignInResult{
            return try {
                val res = credentialManager.getCredential(activity,GetCredentialRequest(listOf(GetPasswordOption())))
                val credential = res.credential as? PasswordCredential ?: return SignInResult.Failure
                SignInResult.Success(credential.id,credential.password)
            } catch (e: GetCredentialCancellationException) {
                e.printStackTrace()
                SignInResult.Cancelled
            } catch (e: NoCredentialException) {
                SignInResult.NoCredentials
            } catch (e: GetCredentialException) {
                SignInResult.Failure
            } catch (e:Exception){
                SignInResult.Failure
            }
        }
    }
    
    sealed interface SignInResult {
        data class Success(val username: String,val pwd: String) : SignInResult
        data object Cancelled : SignInResult
        data object Failure : SignInResult
        data object NoCredentials : SignInResult
    }
    sealed interface SignupResult {
        data class Success(val username: String) : SignupResult
        data object Cancelled : SignupResult
        data object Failure : SignupResult
    }
    

    Here i have also mentioned the imports for easy implementation

    Below is the code for your composable

    val context = LocalContext.current
    val scope = rememberCoroutineScope()
    val accountManager = remember {
        AccountManager(context as ComponentActivity)
    }
    
    //submit the user entered email password to our custom class to save it 
    Text ("Login", modifier = Modifier.clickable {
        scope.launch {            
             accountManager.signUp(email,password)
        }
    })
    
    //When the screen is opened use below code to show user the prompt to fetch the details also errors can be handled specifically
    
    LaunchedEffect(key1 = true) {
        when (val res = accountManager.signIn()) {
            SignInResult.Cancelled -> {}
            SignInResult.Failure -> {}
            SignInResult.NoCredentials -> {}
            is SignInResult.Success -> {
                //Update the field with this object 
                res.username
                res.pwd
            }
        }
    }