Sign in to Google account with old password - how to redirect to blue Google Sign-In page? Sign in to Google account with old password - how to redirect to blue Google Sign-In page? android android

Sign in to Google account with old password - how to redirect to blue Google Sign-In page?


Disclaimer I am not a Google employee. Everything I say below are my conclusions from investigating similar issues.

Short answer

You are doing everything right. It is the recommended way of logging into google account.Unfortunately there is no actual callback in this mechanism to specify what actually went wrong in your case. The way Google Play Services handles it is by notifying user that his credentials became obsolete by notificaion you can see below (right after the password was changed).

notification

I would recommend filing a bug for adding extra result codes for your case on https://issuetracker.google.com as it seems like a sensible improvement.

Long answer

Google uses Android account API just like everybody else (you can try it yourself). Behind the scenes it's just a oauth token retrieval and storage mechanism.

When the password was changed, the token is no longer valid and you get errors trying to use it.

The way it works is the way Google Play Services developers chose to implement it (hence I recommend you to file a bug).

For example, AliExpress somehow can handle this and redirects user to blue page with asking user to sign in again.

Aliexpress uses the deprecated API. As you can see the dialog for picking account has different color and no avatars. The API is is still usable, but may be shut down anytime (or not). I do not recommend you to use this, but here is how it works:

import com.google.android.gms.common.AccountPicker;import com.google.android.gms.auth.GoogleAuthUtil;import com.google.android.gms.auth.UserRecoverableAuthException;void chooseAccount() {    Intent signInIntent = AccountPicker.newChooseAccountIntent(null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null);    startActivityForResult(signInIntent, REQ_CHOOSE_ACCOUNT);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {    if (requestCode == REQ_CHOOSE_ACCOUNT) {        String email = data.getExtras().getString("authAccount");        // better do this in background thread        try {            GoogleAuthUtil.getToken(this, new Account(email, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE), "oauth2:https://www.googleapis.com/auth/userinfo.profile");        } catch (UserRecoverableAuthException recEx) {            Intent recoverIntent = recEx.getIntent();            // Will redirect to login activity            startActivityForResult(recoverIntent, REQ_RECOVER);        } catch (Exception e) {            Log.d(TAG, "caught exception", e);        }    }}

Hope it helps!

UPD: new Google Play APIs have ResolvableApiException, which extends ApiException you are catching. It has method startResolutionForResult() similar to the one used in older APIs. But the Bundle you receive contains no resolution info.

Bundle[{googleSignInStatus=Status{statusCode=unknown status code: 12501, resolution=null}}]

If you will file a bug, post it here, we will star it)

You can also show the "Choose account" dialog using default Android API (min API 23)

The code below may be sued to show a "choose account dialog" using default Android Account Management APIs. This is new and (hopefully) not going to be deprecated for a while.

import android.accounts.Account;import android.accounts.AccountManager;// Unfortunately can be used only on API 23 and higherIntent signInIntent = AccountManager.newChooseAccountIntent(            null,            null,            new String[] { "com.google" },            "Please select your account",            null,            null,            new Bundle());startActivityForResult(signInIntent, REQ_SELECT_ACCOUNT);@Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (requestCode == REQ_SELECT_ACCOUNT) {            String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME);            String accountType = data.getExtras().getString(AccountManager.KEY_ACCOUNT_TYPE);            // now you can call GoogleAuthUtil as in example above        }    }

You can also get list of Google accounts, visible to your app

Account becomes visible to your app after user have tried to sign in with that kind of account into your app, using one of the methods above. Event if sign in was not successful (e.g. password is expired), you will see this account in the list (won't be able to distinguish which one in case of multiple accounts though). So this may be used as workaround, but in a limited way.

import android.accounts.Account;import android.accounts.AccountManager;try {        // requires android.permission.GET_ACCOUNTS        Account[] accounts = AccountManager.get(this).getAccountsByType("com.google");        for (Account account : accounts) {            Log.d(TAG, "account: " + account.name);        }    } catch (Exception e) {        Log.i("Exception", "Exception:" + e);    }

ConclusionUnfortunately I've found no other ways to access google account data to work around your case using modern Google Sign-In APIs. All advanced AccountManager APIs require you to have the same signature as account owner app (GMS - Google Mobile Services) which is not the case. So we can only request this from Google and hope for it to be implemented :(