Introduction
By integrating Smart Lock for Passwords into your Android app, you can automatically sign the users into your app using the credentials they have saved. Users can save both username-password credentials and federated identity provider credentials. Integrate Smart Lock for Passwords into your app by using the
Credentials API to retrieve saved credentials on sign-in. Use successfully retrieved credentials to sign the user in, or use the Credentials API to rapidly onboard new users by partially completing your app's sign in or sign up form. Prompt users after sign-in or sign-up to store their credentials for future automatic authentication.
Working Flow
- For the first time, we will log in to the application with the credentials
- Then, the API prompts the user to store the credits against the selected Gmail account.
- For the second time, the Smart lock lets the user log in to the app automatically without user inputs
It is similar to a smart lock in Google Chrome Browser.
Steps
I have split this part into 3 steps as in the following.
- Step 1 - Creating a New Project with Empty Activity.
- Step 2 - Setting up the Library for Android Project.
- Step 3 - Implementing Smart Lock in Android.
Step 1 - Creating a New Project with Empty Activity
- Open Android Studio and select Create a new project.
- Name the project as per your wish and select an empty activity.
- Click the “Finish” button to create a new project in Android Studio.
Step 2 - Setting up the Library for Android Project
In this part, we will see how to set up the library for the project.
- Open your app level build.gradle file and add the following lines to download the library.
- compile 'com.google.android.gms:play-services-auth:10.0.1'
- Then click “Sync Now” to download the library.
- We need to use “compile” instead of “implementation” if we have using Android Studio Version below 3.0.
Step 3 - Implementing Smart Lock in Android
- Create your activity and add the following GoogleApiClient Callbacks.
- GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener
- In your activity add the following lines to initialize the GoogleApiClient.
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .enableAutoManage(this, 0, this)
- .addApi(Auth.CREDENTIALS_API)
- .build();
Here, “enableAutoManage” is used to enable auto signing method.
“Auth.CREDENTIALS_API” is used to enable the scope for the smart lock for Android.
Save Credentials
You can save your username and password credentials by passing them as in the following,
- String username = mUsernameTextInputLayout.getEditText().getText().toString();
- String password = mPasswordTextInputLayout.getEditText().getText().toString();
- Credential credential = new Credential.Builder(username)
- .setPassword(password)
- .build();
Here, credentials are saved with credentials.Builder. The Credential Builder has the ability to store username and password. Then Pass your credentials to save method. The following method is used to store the credentials for Google Smartlock.
- protected void saveCredential(Credential credential) {
-
- Auth.CredentialsApi.save(mGoogleApiClient,
- credential).setResultCallback(new ResultCallback() {
- @Override
- public void onResult(Status status) {
- if (status.isSuccess()) {
- Log.d(TAG, "Credential saved");
- goToContent();
- } else {
- Log.d(TAG, "Attempt to save credential failed " +
- status.getStatusMessage() + " " +
- status.getStatusCode());
- resolveResult(status, RC_SAVE);
- }
- }
- });
- }
Following Method is used to process the status of saving your credentials.
- private void resolveResult(Status status, int requestCode) {
-
-
-
- if (mIsResolving) {
- Log.w(TAG, "resolveResult: already resolving.");
- return;
- }
-
- Log.d(TAG, "Resolving: " + status);
- if (status.hasResolution()) {
- Log.d(TAG, "STATUS: RESOLVING");
- try {
- status.startResolutionForResult(this, requestCode);
- mIsResolving = true;
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "STATUS: Failed to send resolution.", e);
- }
- } else {
- Log.e(TAG, "STATUS: FAIL");
- if (requestCode == RC_SAVE) {
- goToContent();
- }
- }
- }
We can manage the results of the smart lock API, using OnActivityResult which shows output of saving your credentials
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- Log.d(TAG, "onActivityResult:" + requestCode + ":" + resultCode + ":" + data);
- if (requestCode == RC_SAVE) {
- Log.d(TAG, "Result code: " + resultCode);
- if (resultCode == RESULT_OK) {
- Log.d(TAG, "Credential Save: OK");
- }
- else {
- Log.e(TAG, "Credential Save Failed");
- }
- goToContent();
- }
- if (requestCode == RC_READ) {
- if (resultCode == RESULT_OK) {
- Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
- processRetrievedCredential(credential);
- } else {
- Log.e(TAG, "Credential Read: NOT OK");
- }
- }
- }
-
-
-
- protected void goToContent() {
- startActivity(new Intent(this, ContentActivity.class));
- finish();
- }
Retrieve Credentials
The following method is used to retrieve your saved credentials from your account and made your login process easier.
- private void requestCredentials() {
- Log.d(TAG, "requestCredentials");
- CredentialRequest request = new CredentialRequest.Builder()
- .setPasswordLoginSupported(true)
- .build();
-
- Auth.CredentialsApi.request(mGoogleApiClient, request).setResultCallback(
- new ResultCallback() {
- @Override
- public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {
- Status status = credentialRequestResult.getStatus();
- Log.v(TAG, status.getStatus().toString());
- if (credentialRequestResult.getStatus().isSuccess()) {
- Credential credential = credentialRequestResult.getCredential();
- processRetrievedCredential(credential);
- } else if (status.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) {
- Log.d(TAG, "Sign in required");
- } else if (status.getStatusCode() == CommonStatusCodes.RESOLUTION_REQUIRED) {
- Log.w(TAG, "Unrecognized status code: " + status.getStatusCode());
- try {
- status.startResolutionForResult(MainActivity.this, RC_READ);
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "STATUS: Failed to send resolution.", e);
- }
- }
- }
- });
- }
The above code is used to made auto login easier.
Full Code
You can find the full source code below.,
- package com.ajts.androidmads.smartlockapiexample;
-
- import android.content.Intent;
- import android.content.IntentSender;
- import android.support.annotation.NonNull;
- import android.support.annotation.Nullable;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
-
- import com.google.android.gms.auth.api.Auth;
- import com.google.android.gms.auth.api.credentials.Credential;
- import com.google.android.gms.auth.api.credentials.CredentialRequest;
- import com.google.android.gms.auth.api.credentials.CredentialRequestResult;
- import com.google.android.gms.common.ConnectionResult;
- import com.google.android.gms.common.api.CommonStatusCodes;
- import com.google.android.gms.common.api.GoogleApiClient;
- import com.google.android.gms.common.api.ResultCallback;
- import com.google.android.gms.common.api.Status;
-
- public class MainActivity extends AppCompatActivity implements
- GoogleApiClient.ConnectionCallbacks,
- GoogleApiClient.OnConnectionFailedListener {
-
- GoogleApiClient mGoogleApiClient;
- static final String TAG = "MainActivity";
- static final int RC_SAVE = 1;
- static final int RC_READ = 2;
- String username = "1234";
- String password = "1234";
- EditText usernameEditText, passwordEditText;
- Button signInButton;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- usernameEditText = (EditText) findViewById(R.id.usernameEditText);
- passwordEditText = (EditText) findViewById(R.id.passwordEditText);
- signInButton = (Button) findViewById(R.id.signInButton);
-
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .enableAutoManage(this, 0, this)
- .addApi(Auth.CREDENTIALS_API)
- .build();
-
- signInButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- String username1 = usernameEditText.getText().toString();
- String password1 = passwordEditText.getText().toString();
- if (!(username.equals(username1) && password.equals(password1))) {
- return;
- }
- Credential credential = new Credential.Builder(username1)
- .setPassword(password1)
- .build();
- saveCredential(credential);
- }
- });
- }
-
- protected void saveCredential(Credential credential) {
-
- Auth.CredentialsApi.save(mGoogleApiClient,
- credential).setResultCallback(new ResultCallback<Status>() {
- @Override
- public void onResult(@NonNull Status status) {
- if (status.isSuccess()) {
- Log.d(TAG, "Credential saved");
- goToContent();
- } else {
- Log.d(TAG, "Attempt to save credential failed " +
- status.getStatusMessage() + " " +
- status.getStatusCode());
- resolveResult(status, RC_SAVE);
- }
- }
- });
- }
-
- private void resolveResult(Status status, int requestCode) {
- if (status.hasResolution()) {
- try {
- status.startResolutionForResult(this, requestCode);
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "STATUS: Failed to send resolution.", e);
- }
- } else {
- if (requestCode == RC_SAVE) {
- goToContent();
- }
- }
- }
-
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- Log.d(TAG, "onActivityResult:" + requestCode + ":" + resultCode + ":" + data);
- if (requestCode == RC_SAVE) {
- Log.d(TAG, "Result code: " + resultCode);
- if (resultCode == RESULT_OK) {
- Log.d(TAG, "Credential Save: OK");
- } else {
- Log.e(TAG, "Credential Save Failed");
- }
- goToContent();
- }
- if (requestCode == RC_READ) {
- if (resultCode == RESULT_OK) {
- Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
- processRetrievedCredential(credential);
- } else {
- Log.e(TAG, "Credential Read: NOT OK");
- }
- }
- }
-
-
-
-
- protected void goToContent() {
- startActivity(new Intent(this, ContentActivity.class));
- finish();
- }
-
- private void requestCredentials() {
- Log.d(TAG, "requestCredentials");
- CredentialRequest request = new CredentialRequest.Builder()
- .setPasswordLoginSupported(true)
- .build();
-
- Auth.CredentialsApi.request(mGoogleApiClient, request).setResultCallback(
- new ResultCallback<CredentialRequestResult>() {
- @Override
- public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {
- Status status = credentialRequestResult.getStatus();
- Log.v(TAG, status.getStatus().toString());
- if (credentialRequestResult.getStatus().isSuccess()) {
- Credential credential = credentialRequestResult.getCredential();
- processRetrievedCredential(credential);
- } else if (status.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) {
- Log.d(TAG, "Sign in required");
- } else if (status.getStatusCode() == CommonStatusCodes.RESOLUTION_REQUIRED) {
- Log.w(TAG, "Unrecognized status code: " + status.getStatusCode());
- try {
- status.startResolutionForResult(MainActivity.this, RC_READ);
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "STATUS: Failed to send resolution.", e);
- }
- }
- }
- }
- );
-
- }
-
- private void processRetrievedCredential(Credential credential) {
- if (username.equals(credential.getId()) && password.equals(credential.getPassword())) {
- goToContent();
- } else {
- Log.d(TAG, "Retrieved credential invalid, so delete retrieved" + " credential.");
- }
- }
-
- @Override
- public void onConnected(@Nullable Bundle bundle) {
- requestCredentials();
- }
-
- @Override
- public void onConnectionSuspended(int i) {
-
- }
-
- @Override
- public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
-
- }
- }
Download Code
You can download the full source from the following
GitHub link. If you like this tutorial, do star it in GitHub and hit like in C-SharpCorner. Post your doubts and comments in the comments section.