If in SyncAdapter.onPerformSync
the inherent acquisition of an auth token results in the user needing to enter their password, how can you rerun or continue the sync once they have successfully logged in?
While this seems like a fairly standard feature, I've been unable to find anything on it. The AccountManager.getAuthToken docs seem to hint at using an OnAccountsUpdatedListener, but I've tried that and it never gets called. Besides, that will get called for any change to any account if I understand the docs right, which seems a bit...indirect.
EDIT
Here are the relevant parts of my code. I've closely followed the official guide and this excellent blog post by Udinic
In Authenticator.getAuthToken
// There is neither an access nor a refresh token. User has to log in
if (!tokens.hasAccess() && !tokens.hasRefresh()) {
Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(LoginActivity.ARG_ACCOUNT, account);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); // As per AbstractAccountAuthenticator doc
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
}
...
return bundle;
In LoginActivity.finishLogin
// Store access token if one was provided. Note that this should always be the case anyway,
// otherwise the login would have been unsuccessful
if (tokens.hasAccess()) {
manager.setAuthToken(account, Authenticator.TOKEN_TYPE_ACCESS, tokens.access);
}
// Store refresh token if one was provided.
if (tokens.hasRefresh()) {
manager.setAuthToken(account, Authenticator.TOKEN_TYPE_REFRESH, tokens.refresh);
}
final Intent intent = new Intent();
if (tokens.hasAccess()) {
intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
intent.putExtra(AccountManager.KEY_AUTHTOKEN, tokens.access);
}
setAccountAuthenticatorResult(intent.getExtras());
setResult(Activity.RESULT_OK, intent);
finish();
And, even though it's somewhat trivial: In SyncAdapter.onPerformSync:
String token = null;
try {
token = AccountManager.get(getContext()).blockingGetAuthToken(account, Authenticator.TOKEN_TYPE_ACCESS, true);
if (token == null) {
syncResult.stats.numAuthExceptions++;
return;
}
} catch (OperationCanceledException x) {
return;
} catch (AuthenticatorException x) {
syncResult.stats.numAuthExceptions++;
return;
} catch (IOException x) {
syncResult.stats.numIoExceptions++;
return;
}