Google Smart Lock In Android

By integrating Smart Lock for Passwords into your Android app, you can automatically sign users in to 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.

 

Google Smart Lock

 

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.

Reference: Official Link

Working Flow

  1. For the first time, we will login to the application with the credentials
  2. Then, the API prompts the user to store the credits against the selected Gmail account.
  3. 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

  1. Open Android Studio and Select Create a new project.
  2. Name the project as per your wish and select an empty activity.

    Google Smart Lock

  1. Click “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.

  1. Open your app level build.gradle file and add the following lines to download the library.
    1. compile 'com.google.android.gms:play-services-auth:10.0.1'  
  1. Then Click “Sync Now” to download the library.
  2. 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

  1. Create your activity and add the following GoogleApiClient Callbacks.
    1. GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener 
  1. In your activity add the following lines to initialize the GoogleApiClient.
    1. mGoogleApiClient = new GoogleApiClient.Builder(this)  
    2. .addConnectionCallbacks(this)  
    3. .enableAutoManage(this, 0, this)  
    4. .addApi(Auth.CREDENTIALS_API)  
    5. .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,

  1. String username = mUsernameTextInputLayout.getEditText().getText().toString();  
  2. String password = mPasswordTextInputLayout.getEditText().getText().toString();  
  3. Credential credential = new Credential.Builder(username)  
  4.                         .setPassword(password)  
  5.                         .build();  

Here, credentials are saved with Credential.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 to Google Smartlock.

  1. protected void saveCredential(Credential credential) {  
  2.     // Credential is valid so save it.  
  3.     Auth.CredentialsApi.save(mGoogleApiClient,  
  4.             credential).setResultCallback(new ResultCallback() {  
  5.         @Override  
  6.         public void onResult(Status status) {  
  7.             if (status.isSuccess()) {  
  8.                 Log.d(TAG, "Credential saved");  
  9.                 goToContent();  
  10.             } else {  
  11.                 Log.d(TAG, "Attempt to save credential failed " +  
  12.                         status.getStatusMessage() + " " +  
  13.                         status.getStatusCode());  
  14.                 resolveResult(status, RC_SAVE);  
  15.             }  
  16.         }  
  17.     });  
  18. }  

Following Method is used to process the status of saving your credentials.

  1. private void resolveResult(Status status, int requestCode) {  
  2.  // We don't want to fire multiple resolutions at once since that  
  3.  // can   result in stacked dialogs after rotation or another  
  4.  // similar event.  
  5.  if (mIsResolving) {  
  6.   Log.w(TAG, "resolveResult: already resolving.");  
  7.   return;  
  8.  }  
  9.   
  10.  Log.d(TAG, "Resolving: " + status);  
  11.  if (status.hasResolution()) {  
  12.   Log.d(TAG, "STATUS: RESOLVING");  
  13.   try {  
  14.    status.startResolutionForResult(this, requestCode);  
  15.    mIsResolving = true;  
  16.   } catch (IntentSender.SendIntentException e) {  
  17.    Log.e(TAG, "STATUS: Failed to send resolution.", e);  
  18.   }  
  19.  } else {  
  20.   Log.e(TAG, "STATUS: FAIL");  
  21.   if (requestCode == RC_SAVE) {  
  22.    goToContent();  
  23.   }  
  24.  }  
  25. }  

We can manage the results of the smart lock API, using OnActivityResult which shows output of saving your credentials

  1. public void onActivityResult(int requestCode, int resultCode, Intent data) {  
  2.     super.onActivityResult(requestCode, resultCode, data);  
  3.     Log.d(TAG, "onActivityResult:" + requestCode + ":" + resultCode + ":" + data);  
  4.     if (requestCode == RC_SAVE) {  
  5.         Log.d(TAG, "Result code: " + resultCode);  
  6.         if (resultCode == RESULT_OK) {  
  7.             Log.d(TAG, "Credential Save: OK");  
  8.         }   
  9.         else {  
  10.             Log.e(TAG, "Credential Save Failed");  
  11.         }  
  12.         goToContent();  
  13.     }  
  14.     if (requestCode == RC_READ) {  
  15.         if (resultCode == RESULT_OK) {  
  16.             Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);  
  17.             processRetrievedCredential(credential);  
  18.         } else {  
  19.             Log.e(TAG, "Credential Read: NOT OK");  
  20.         }  
  21.     }  
  22. }  
  23. /** 
  24.  * Start the Content Activity and finish this one. 
  25.  */  
  26. protected void goToContent() {  
  27.     startActivity(new Intent(this, ContentActivity.class));  
  28.     finish();  
  29. }  

Retrieve Credentials

The following method is used to retrieve your saved credentials from your account and made your login process easier.

  1. private void requestCredentials() {  
  2.     Log.d(TAG, "requestCredentials");  
  3.     CredentialRequest request = new CredentialRequest.Builder()  
  4.       .setPasswordLoginSupported(true)  
  5.       .build();  
  6.   
  7.     Auth.CredentialsApi.request(mGoogleApiClient, request).setResultCallback(  
  8.      new ResultCallback() {  
  9.      @Override  
  10.      public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {  
  11.       Status status = credentialRequestResult.getStatus();  
  12.       Log.v(TAG, status.getStatus().toString());  
  13.       if (credentialRequestResult.getStatus().isSuccess()) {  
  14.        Credential credential = credentialRequestResult.getCredential();  
  15.        processRetrievedCredential(credential);  
  16.       } else if (status.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) {  
  17.        Log.d(TAG, "Sign in required");  
  18.       } else if (status.getStatusCode() == CommonStatusCodes.RESOLUTION_REQUIRED) {  
  19.        Log.w(TAG, "Unrecognized status code: " + status.getStatusCode());  
  20.        try {  
  21.         status.startResolutionForResult(MainActivity.this, RC_READ);  
  22.        } catch (IntentSender.SendIntentException e) {  
  23.         Log.e(TAG, "STATUS: Failed to send resolution.", e);  
  24.        }  
  25.       }  
  26.      }  
  27.     });  
  28. }  

The above code is used to made auto login easier.

Full Code

You can find the full source code below.,

  1. package com.ajts.androidmads.smartlockapiexample;  
  2.   
  3. import android.content.Intent;  
  4. import android.content.IntentSender;  
  5. import android.support.annotation.NonNull;  
  6. import android.support.annotation.Nullable;  
  7. import android.support.v7.app.AppCompatActivity;  
  8. import android.os.Bundle;  
  9. import android.util.Log;  
  10. import android.view.View;  
  11. import android.widget.Button;  
  12. import android.widget.EditText;  
  13.   
  14. import com.google.android.gms.auth.api.Auth;  
  15. import com.google.android.gms.auth.api.credentials.Credential;  
  16. import com.google.android.gms.auth.api.credentials.CredentialRequest;  
  17. import com.google.android.gms.auth.api.credentials.CredentialRequestResult;  
  18. import com.google.android.gms.common.ConnectionResult;  
  19. import com.google.android.gms.common.api.CommonStatusCodes;  
  20. import com.google.android.gms.common.api.GoogleApiClient;  
  21. import com.google.android.gms.common.api.ResultCallback;  
  22. import com.google.android.gms.common.api.Status;  
  23.   
  24. public class MainActivity extends AppCompatActivity implements  
  25.         GoogleApiClient.ConnectionCallbacks,  
  26.         GoogleApiClient.OnConnectionFailedListener {  
  27.   
  28.     GoogleApiClient mGoogleApiClient;  
  29.     static final String TAG = "MainActivity";  
  30.     static final int RC_SAVE = 1;  
  31.     static final int RC_READ = 2;  
  32.     String username = "1234";  
  33.     String password = "1234";  
  34.     EditText usernameEditText, passwordEditText;  
  35.     Button signInButton;  
  36.   
  37.     @Override  
  38.     protected void onCreate(Bundle savedInstanceState) {  
  39.         super.onCreate(savedInstanceState);  
  40.         setContentView(R.layout.activity_main);  
  41.   
  42.         usernameEditText = (EditText) findViewById(R.id.usernameEditText);  
  43.         passwordEditText = (EditText) findViewById(R.id.passwordEditText);  
  44.         signInButton = (Button) findViewById(R.id.signInButton);  
  45.   
  46.         mGoogleApiClient = new GoogleApiClient.Builder(this)  
  47.                 .addConnectionCallbacks(this)  
  48.                 .enableAutoManage(this, 0, this)  
  49.                 .addApi(Auth.CREDENTIALS_API)  
  50.                 .build();  
  51.   
  52.         signInButton.setOnClickListener(new View.OnClickListener() {  
  53.             @Override  
  54.             public void onClick(View v) {  
  55.                 String username1 = usernameEditText.getText().toString();  
  56.                 String password1 = passwordEditText.getText().toString();  
  57.                 if (!(username.equals(username1) && password.equals(password1))) {  
  58.                     return;  
  59.                 }  
  60.                 Credential credential = new Credential.Builder(username1)  
  61.                         .setPassword(password1)  
  62.                         .build();  
  63.                 saveCredential(credential);  
  64.             }  
  65.         });  
  66.     }  
  67.   
  68.     protected void saveCredential(Credential credential) {  
  69.         // Credential is valid so save it.  
  70.         Auth.CredentialsApi.save(mGoogleApiClient,  
  71.                 credential).setResultCallback(new ResultCallback<Status>() {  
  72.             @Override  
  73.             public void onResult(@NonNull Status status) {  
  74.                 if (status.isSuccess()) {  
  75.                     Log.d(TAG, "Credential saved");  
  76.                     goToContent();  
  77.                 } else {  
  78.                     Log.d(TAG, "Attempt to save credential failed " +  
  79.                             status.getStatusMessage() + " " +  
  80.                             status.getStatusCode());  
  81.                     resolveResult(status, RC_SAVE);  
  82.                 }  
  83.             }  
  84.         });  
  85.     }  
  86.   
  87.     private void resolveResult(Status status, int requestCode) {  
  88.         if (status.hasResolution()) {  
  89.             try {  
  90.                 status.startResolutionForResult(this, requestCode);  
  91.             } catch (IntentSender.SendIntentException e) {  
  92.                 Log.e(TAG, "STATUS: Failed to send resolution.", e);  
  93.             }  
  94.         } else {  
  95.             if (requestCode == RC_SAVE) {  
  96.                 goToContent();  
  97.             }  
  98.         }  
  99.     }  
  100.   
  101.     public void onActivityResult(int requestCode, int resultCode, Intent data) {  
  102.         super.onActivityResult(requestCode, resultCode, data);  
  103.         Log.d(TAG, "onActivityResult:" + requestCode + ":" + resultCode + ":" + data);  
  104.         if (requestCode == RC_SAVE) {  
  105.             Log.d(TAG, "Result code: " + resultCode);  
  106.             if (resultCode == RESULT_OK) {  
  107.                 Log.d(TAG, "Credential Save: OK");  
  108.             } else {  
  109.                 Log.e(TAG, "Credential Save Failed");  
  110.             }  
  111.             goToContent();  
  112.         }  
  113.         if (requestCode == RC_READ) {  
  114.             if (resultCode == RESULT_OK) {  
  115.                 Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);  
  116.                 processRetrievedCredential(credential);  
  117.             } else {  
  118.                 Log.e(TAG, "Credential Read: NOT OK");  
  119.             }  
  120.         }  
  121.     }  
  122.   
  123.     /** 
  124.      * Start the Content Activity and finish this one. 
  125.      */  
  126.     protected void goToContent() {  
  127.         startActivity(new Intent(this, ContentActivity.class));  
  128.         finish();  
  129.     }  
  130.   
  131.     private void requestCredentials() {  
  132.         Log.d(TAG, "requestCredentials");  
  133.         CredentialRequest request = new CredentialRequest.Builder()  
  134.                 .setPasswordLoginSupported(true)  
  135.                 .build();  
  136.   
  137.         Auth.CredentialsApi.request(mGoogleApiClient, request).setResultCallback(  
  138.                 new ResultCallback<CredentialRequestResult>() {  
  139.                     @Override  
  140.                     public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {  
  141.                         Status status = credentialRequestResult.getStatus();  
  142.                         Log.v(TAG, status.getStatus().toString());  
  143.                         if (credentialRequestResult.getStatus().isSuccess()) {  
  144.                             Credential credential = credentialRequestResult.getCredential();  
  145.                             processRetrievedCredential(credential);  
  146.                         } else if (status.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) {  
  147.                             Log.d(TAG, "Sign in required");  
  148.                         } else if (status.getStatusCode() == CommonStatusCodes.RESOLUTION_REQUIRED) {  
  149.                             Log.w(TAG, "Unrecognized status code: " + status.getStatusCode());  
  150.                             try {  
  151.                                 status.startResolutionForResult(MainActivity.this, RC_READ);  
  152.                             } catch (IntentSender.SendIntentException e) {  
  153.                                 Log.e(TAG, "STATUS: Failed to send resolution.", e);  
  154.                             }  
  155.                         }  
  156.                     }  
  157.                 }  
  158.         );  
  159.   
  160.     }  
  161.   
  162.     private void processRetrievedCredential(Credential credential) {  
  163.         if (username.equals(credential.getId()) && password.equals(credential.getPassword())) {  
  164.             goToContent();  
  165.         } else {  
  166.             Log.d(TAG, "Retrieved credential invalid, so delete retrieved" + " credential.");  
  167.         }  
  168.     }  
  169.   
  170.     @Override  
  171.     public void onConnected(@Nullable Bundle bundle) {  
  172.         requestCredentials();  
  173.     }  
  174.   
  175.     @Override  
  176.     public void onConnectionSuspended(int i) {  
  177.   
  178.     }  
  179.   
  180.     @Override  
  181.     public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {  
  182.   
  183.     }  
  184. }  

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.