Search code examples
androidaccountmanagerandroid-syncadapter

How should the app react if an authToken invalidates


in my project I need to connect regularly to a server. Therefore I'm implementing an AccountAuthenticator and SyncAdapter to plug them into androids framework. It is critical for the application to connect regularly, say every 5 or 10 minutes.

No matter whether I store the password or an authToken, both can become invalid and the SyncAdapter wouldn't be able to sync any more. Logically the user needs to be informed.

I wanted to display the login form if AccountAuthenticator.getAuthToken(..) can't get a new authToken:

@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response,
                           Account account, String authTokenType,
                           Bundle options) throws NetworkErrorException {
    // code derived from SampleSyncAdapter

    // If the caller requested an authToken type we don't support, then
    // return an error
    if (!authTokenType.equals(Helper.ACCOUNT_TYPE)) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ERROR_MESSAGE,
                         "invalid authTokenType");
        return result;
    }

    // Extract the username and password from the Account Manager, and ask
    // the server for an appropriate AuthToken.
    final AccountManager am = AccountManager.get(context);
    final String password = am.getPassword(account);
    if (password != null) {
        final LoginData loginData =
                           NetworkUtility.authenticate(account.name, password);

        if (loginData.wasSuccessful() &&
            !TextUtils.isEmpty(loginData.getAuthenticationToken())) {
            final Bundle result = new Bundle();
            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
            result.putString(AccountManager.KEY_ACCOUNT_TYPE,
                             Helper.ACCOUNT_TYPE);
            result.putString(AccountManager.KEY_AUTHTOKEN,
                             loginData.getAuthenticationToken());
            return result;
        }
    }

    // If we get here, then we couldn't access the user's password - so we
    // need to re-prompt them for their credentials. We do that by creating
    // an intent to display our AuthenticatorActivity panel.
    final Intent intent = new Intent(context, AuthenticatorActivity.class);
    intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
                    response);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);
    return bundle;
}

but unfortunately this doesn't work, no prompt is created.

I didn't find any information on what would be the best practise way. I've checked the new CouchSurfing app and they simply remove the account. I didn't check now, but I think Google would disable synchronisation. Neither solution would work for my use case.


Solution

  • The solution is simpler than i thought and google also does it:

    Post a message to the notification area (http://developer.android.com/guide/topics/ui/notifiers/notifications.html), and when opening it, the login screen can be shown.