Search code examples
androidgoogle-smartlockpasswords

Google Smart Lock disableAutoSignIn() doesn't prevent picker dialog on next app open


I'm integrating Google Smart Lock into my app. It seems to work very well except in the case where the user logs out. First, some background ...

On app startup, when the user is not logged in, I make this call:

CredentialRequest r = new CredentialRequest.Builder()
                  .setPasswordLoginSupported(true)
                  .setAccountTypes(IdentityProviders.FACEBOOK)
                  .build();

          Auth.CredentialsApi.request(googleApiClient, r)
                  .setResultCallback(result -> {
                    Status status = result.getStatus();
                    if (status.isSuccess()) {
                      onCredentialReceived(result.getCredential());
                    } else  if (status.getStatusCode() == CommonStatusCodes.RESOLUTION_REQUIRED) {
                      try {
                        status.startResolutionForResult(activity, REQUEST_CREDENTIALS);
                      } catch (IntentSender.SendIntentException e) {
                        Timber.e(e, "Couldn't start a resolution request for the user's credentials");
                      }
                    }
                  });

Upon logout, my app makes this call:

Auth.CredentialsApi.disableAutoSignIn(googleApiClient)
        .setResultCallback(status -> {
          if (!status.isSuccess()) Timber.e("Error disabling auto sign in");
        });

This works well on the first startup of the app; if the user has a single saved credential, I grab it from Google and log the user in seamlessly. If the user has multiple saved credentials, I start the account picker and grab the credential that way. When the user logs out, I disable auto sign in.

Unfortunately, if the user opens the app again after logging out, the result returned from Auth.CredentialsApi.request() tells me a resolution is required, so I ultimately show the account picker again, and again, and again each time the app is restarted. I had assumed that disabling auto sign in would cause subsequent calls to Auth.CredentialsApi.request() to return a status code != CommonStatusCodes.RESOLUTION_REQUIRED; I expected something like CommonStatusCodes.SIGN_IN_REQUIRED (meaning the user needs to explicitly sign in again and agree to save credentials with Smart Lock) or CommonStatusCodes.CANCELED (meaning Smart Lock is disabled at the moment).

Is this a bug in the Smart Lock API or am I doing something wrong? Thanks!


Solution

  • How best to handle this depends on the UX of the app (e.g. is it sign-in required or optional UX?), so it's up to the developer: if it doesn't make sense to always show the credential selection dialog, simply don't resolve the credentialRequestResult (i.e. don't call startResolutionForResult) if the status is RESOLUTION_REQUIRED.

    For example, you can call the request API when the app starts, but if you find the user cancels the dialog, set some persistent local state (e.g. in shared preferences) not to show it again (i.e. don't resolve) until they take explicit action to sign in (e.g. navigates to the sign-in UI).

    I'd recommend keeping track of whether user canceled the dialog rather than signed out since user might not want to sign in at all in the first place.