7

I recently integrated Google's Smart Lock for Passwords feature into my app and almost everything is running smoothly as expected.

There is just one small issue I was not able to fix yet: In ResultCallback#onResult, if status.getStatusCode() == CommonStatusCodes.RESOLUTION_REQUIRED the following command leads to the presentation of a Google resolution dialog that is asking whether to save the credentials via Smart Lock (see attached image) or which credentials to use, if there are already multiple credentials saved in Smart Lock:

status.startResolutionForResult(getActivity(), REQUEST_CODE_READ);

Google Smart Lock dialog: Save password with Smart Lock? Never or Save Password

When the resolution dialog is presented, and the user does some orientation changes, then the resolution dialog multiplies, each of them overlapping the others. As a user, you first don’t see that there are multiple copies of the dialog, but if you close the first (by tapping on „Never“ or „Save Password“) then the uppermost dialog disappears, revealing another identical dialog below.

Prags
  • 2,457
  • 2
  • 21
  • 38

2 Answers2

6

You can handle this by maintaining some state between the activity starting and stopping.

See use of the mIsResolving variable in this sample code. Simply save whether there is a pending dialog already when onSaveInstanceState() is called and restore in onCreate(), and guard against calling the API again if so, clearing the state once onActivityResult() is received for the intent.

private void resolveResult(Status status, int requestCode) {
    // We don't want to fire multiple resolutions at once since that can result
    // in stacked dialogs after rotation or another similar event.
    if (mIsResolving) {
        Log.w(TAG, "resolveResult: already resolving.");
        return;
    }
    if (status.hasResolution()) {
        try {
            status.startResolutionForResult(MainActivity.this, requestCode);
            mIsResolving = true;
...

@Override
protected void onCreate(Bundle savedInstanceState) {
...
    if (savedInstanceState != null) {
        mIsResolving = savedInstanceState.getBoolean(KEY_IS_RESOLVING);
    }
...

@Override
protected void onSaveInstanceState(Bundle outState) {
...
    outState.putBoolean(KEY_IS_RESOLVING, mIsResolving);
...

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
...
            mIsResolving = false;
...

This is a common pitfall for many apps, so we'll look into whether we can support this state in Play Services layer, but for now, using the boolean for the activity is the current and general recommendation for maintaining resolution state.

Steven
  • 3,812
  • 23
  • 38
0

I know, that it's an old question, but recently i have to fight with this issue, in my case I was using status.startResolutionForResult() in custom class and i didn't have any access to onSaveInstanceState() (I could make some custom callback with interface, but i didn't want to), but in my custom class i had an instance of an activity, so always before calling startResolutionForResult() I'm checking mActivity.hasWindowFocus() to see if activity lose focus, becouse of dialog that show, if it's true, then I call startResolutionForResult(), otherwise i do nothing

@Override
public void onResult(@NonNull LocationSettingsResult result) {

    final Status status = result.getStatus();
    switch (status.getStatusCode()){
        case LocationSettingsStatusCodes.SUCCESS:

            getLocation();
            break;
        case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:

            if (mActivity.hasWindowFocus()) {
                try {
                    status.startResolutionForResult(mActivity, SETTINGS_CHECK);
                } catch (IntentSender.SendIntentException e) {
                    e.printStackTrace();
                }
            }
            break;
        case  LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:

            mReceiver.unableToObtainLocation();
            break;
    }
}
Panczur
  • 633
  • 1
  • 9
  • 26